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