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.
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +3 -10
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +0 -4
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +4 -83
- package/android/src/main/java/com/swmansion/audioapi/system/CentralizedForegroundService.kt +14 -29
- package/android/src/main/java/com/swmansion/audioapi/system/ForegroundServiceManager.kt +10 -9
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +10 -51
- package/android/src/main/java/com/swmansion/audioapi/system/notification/BaseNotification.kt +6 -14
- package/android/src/main/java/com/swmansion/audioapi/system/notification/NotificationRegistry.kt +79 -60
- package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotification.kt +249 -411
- package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotificationReceiver.kt +8 -3
- package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotification.kt +240 -222
- package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotificationReceiver.kt +11 -22
- package/android/src/main/java/com/swmansion/audioapi/system/notification/state/RecordingNotificationState.kt +24 -0
- package/android/src/main/res/layout/btn_round_ripple.xml +9 -0
- package/android/src/main/res/layout/notification_collapsed.xml +45 -0
- package/android/src/main/res/layout/notification_expanded.xml +44 -0
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +1 -13
- package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +1 -1
- package/ios/audioapi/ios/AudioAPIModule.mm +5 -48
- package/ios/audioapi/ios/system/notification/BaseNotification.h +0 -7
- package/ios/audioapi/ios/system/notification/NotificationRegistry.h +5 -25
- package/ios/audioapi/ios/system/notification/NotificationRegistry.mm +19 -64
- package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +4 -15
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +2 -1
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/commonjs/api.js +1 -29
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/core/AudioDecoder.js +42 -16
- package/lib/commonjs/core/AudioDecoder.js.map +1 -1
- package/lib/commonjs/core/AudioRecorder.js +2 -1
- package/lib/commonjs/core/AudioRecorder.js.map +1 -1
- package/lib/commonjs/core/AudioStretcher.js +2 -1
- package/lib/commonjs/core/AudioStretcher.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +2 -5
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/commonjs/errors/AudioApiError.js +14 -0
- package/lib/commonjs/errors/AudioApiError.js.map +1 -0
- package/lib/commonjs/errors/index.js +7 -0
- package/lib/commonjs/errors/index.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js +0 -9
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
- package/lib/commonjs/system/notification/PlaybackNotificationManager.js +40 -85
- package/lib/commonjs/system/notification/PlaybackNotificationManager.js.map +1 -1
- package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js +51 -0
- package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js.map +1 -0
- package/lib/commonjs/system/notification/RecordingNotificationManager.js +30 -144
- package/lib/commonjs/system/notification/RecordingNotificationManager.js.map +1 -1
- package/lib/commonjs/system/notification/index.js +1 -9
- package/lib/commonjs/system/notification/index.js.map +1 -1
- package/lib/commonjs/utils/index.js +3 -2
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/paths.js +18 -0
- package/lib/commonjs/utils/paths.js.map +1 -0
- package/lib/commonjs/web-core/AudioContext.js +20 -11
- package/lib/commonjs/web-core/AudioContext.js.map +1 -1
- package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js +0 -1
- package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js.map +1 -1
- package/lib/commonjs/web-system/notification/RecordingNotificationManager.js +1 -6
- package/lib/commonjs/web-system/notification/RecordingNotificationManager.js.map +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js +2 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/module/api.js +3 -2
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/AudioDecoder.js +42 -16
- package/lib/module/core/AudioDecoder.js.map +1 -1
- package/lib/module/core/AudioRecorder.js +3 -1
- package/lib/module/core/AudioRecorder.js.map +1 -1
- package/lib/module/core/AudioStretcher.js +2 -1
- package/lib/module/core/AudioStretcher.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +2 -5
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/errors/AudioApiError.js +10 -0
- package/lib/module/errors/AudioApiError.js.map +1 -0
- package/lib/module/errors/index.js +1 -0
- package/lib/module/errors/index.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.web.js +0 -9
- package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
- package/lib/module/system/notification/PlaybackNotificationManager.js +40 -85
- package/lib/module/system/notification/PlaybackNotificationManager.js.map +1 -1
- package/lib/module/system/notification/RecordingNotificationManager.ios.js +47 -0
- package/lib/module/system/notification/RecordingNotificationManager.ios.js.map +1 -0
- package/lib/module/system/notification/RecordingNotificationManager.js +30 -144
- package/lib/module/system/notification/RecordingNotificationManager.js.map +1 -1
- package/lib/module/system/notification/index.js +1 -2
- package/lib/module/system/notification/index.js.map +1 -1
- package/lib/module/utils/index.js +3 -2
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/paths.js +12 -0
- package/lib/module/utils/paths.js.map +1 -0
- package/lib/module/web-core/AudioContext.js +20 -11
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/module/web-system/notification/PlaybackNotificationManager.js +0 -1
- package/lib/module/web-system/notification/PlaybackNotificationManager.js.map +1 -1
- package/lib/module/web-system/notification/RecordingNotificationManager.js +1 -6
- package/lib/module/web-system/notification/RecordingNotificationManager.js.map +1 -1
- package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/api.d.ts +3 -2
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/AudioDecoder.d.ts +2 -1
- package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
- package/lib/typescript/core/AudioRecorder.d.ts.map +1 -1
- package/lib/typescript/core/AudioStretcher.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -2
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/errors/AudioApiError.d.ts +5 -0
- package/lib/typescript/errors/AudioApiError.d.ts.map +1 -0
- package/lib/typescript/errors/index.d.ts +1 -0
- package/lib/typescript/errors/index.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +1 -1
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -5
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -4
- package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -1
- package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts +32 -9
- package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts.map +1 -1
- package/lib/typescript/system/notification/RecordingNotificationManager.d.ts +26 -13
- package/lib/typescript/system/notification/RecordingNotificationManager.d.ts.map +1 -1
- package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts +36 -0
- package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts.map +1 -0
- package/lib/typescript/system/notification/index.d.ts +0 -1
- package/lib/typescript/system/notification/index.d.ts.map +1 -1
- package/lib/typescript/system/notification/types.d.ts +12 -22
- package/lib/typescript/system/notification/types.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +1 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/paths.d.ts +4 -0
- package/lib/typescript/utils/paths.d.ts.map +1 -0
- package/lib/typescript/web-core/AudioContext.d.ts +8 -9
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/BaseAudioContext.d.ts +6 -7
- package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts +1 -2
- package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts.map +1 -1
- package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts +2 -7
- package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/AudioAPIModule/AudioAPIModule.ts +2 -1
- package/src/api.ts +2 -8
- package/src/core/AudioDecoder.ts +91 -21
- package/src/core/AudioRecorder.ts +2 -1
- package/src/core/AudioStretcher.ts +2 -1
- package/src/core/BaseAudioContext.ts +4 -6
- package/src/errors/AudioApiError.ts +8 -0
- package/src/errors/index.ts +1 -0
- package/src/interfaces.ts +1 -1
- package/src/specs/NativeAudioAPIModule.ts +5 -15
- package/src/specs/NativeAudioAPIModule.web.ts +1 -12
- package/src/system/notification/PlaybackNotificationManager.ts +42 -117
- package/src/system/notification/RecordingNotificationManager.ios.ts +65 -0
- package/src/system/notification/RecordingNotificationManager.ts +33 -183
- package/src/system/notification/index.ts +0 -1
- package/src/system/notification/types.ts +15 -37
- package/src/types.ts +2 -0
- package/src/utils/index.ts +3 -2
- package/src/utils/paths.ts +11 -0
- package/src/web-core/AudioContext.tsx +34 -19
- package/src/web-core/BaseAudioContext.tsx +9 -7
- package/src/web-system/notification/PlaybackNotificationManager.ts +1 -7
- package/src/web-system/notification/RecordingNotificationManager.ts +1 -16
- package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioPlayer.kt +0 -26
- package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +0 -26
- package/android/src/main/java/com/swmansion/audioapi/system/notification/SimpleNotification.kt +0 -119
- package/lib/commonjs/system/notification/SimpleNotificationManager.js +0 -125
- package/lib/commonjs/system/notification/SimpleNotificationManager.js.map +0 -1
- package/lib/module/system/notification/SimpleNotificationManager.js +0 -121
- package/lib/module/system/notification/SimpleNotificationManager.js.map +0 -1
- package/lib/typescript/system/notification/SimpleNotificationManager.d.ts +0 -21
- package/lib/typescript/system/notification/SimpleNotificationManager.d.ts.map +0 -1
- package/src/system/notification/SimpleNotificationManager.ts +0 -175
package/src/core/AudioDecoder.ts
CHANGED
|
@@ -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:
|
|
21
|
-
sampleRate?: number
|
|
91
|
+
input: DecodeDataInput,
|
|
92
|
+
sampleRate?: number,
|
|
93
|
+
fetchOptions?: RequestInit
|
|
22
94
|
): Promise<AudioBuffer> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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 (!
|
|
38
|
-
throw new
|
|
101
|
+
if (!audioBuffer) {
|
|
102
|
+
throw new AudioApiError('Failed to decode audio data.');
|
|
39
103
|
}
|
|
40
|
-
|
|
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:
|
|
61
|
-
sampleRate?: number
|
|
125
|
+
input: DecodeDataInput,
|
|
126
|
+
sampleRate?: number,
|
|
127
|
+
fetchOptions?: RequestInit
|
|
62
128
|
): Promise<AudioBuffer> {
|
|
63
|
-
return AudioDecoder.getInstance().decodeAudioDataInstance(
|
|
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
|
|
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
|
|
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:
|
|
60
|
-
|
|
60
|
+
input: DecodeDataInput,
|
|
61
|
+
fetchOptions?: RequestInit
|
|
61
62
|
): Promise<AudioBuffer> {
|
|
62
|
-
|
|
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(
|
package/src/errors/index.ts
CHANGED
|
@@ -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
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
import { TurboModuleRegistry
|
|
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
|
-
//
|
|
41
|
-
registerNotification(
|
|
42
|
-
type: NotificationType,
|
|
43
|
-
key: string
|
|
44
|
-
): Promise<NotificationOpResponse>;
|
|
38
|
+
// Notification system
|
|
45
39
|
showNotification(
|
|
46
|
-
|
|
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
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
77
|
+
throw new AudioApiError('NativeAudioAPIModule is not available');
|
|
155
78
|
}
|
|
156
79
|
|
|
157
80
|
const params = { control, enabled };
|
|
158
|
-
const result = await NativeAudioAPIModule.
|
|
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
|
|
88
|
+
throw new AudioApiError(result.error);
|
|
165
89
|
}
|
|
166
90
|
}
|
|
167
91
|
|
|
168
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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();
|