lq-audio-studio 4.0.0 → 4.0.1

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 (31) hide show
  1. package/android/build.gradle +2 -1
  2. package/android/consumer-rules.pro +1 -0
  3. package/android/src/main/java/com/aozora/audio/AozoraWebRtcApm.java +36 -0
  4. package/android/src/main/java/net/siteed/audiostudio/AudioProcessing.kt +95 -0
  5. package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +145 -20
  6. package/android/src/main/java/net/siteed/audiostudio/Pcm16FrameAccumulator.kt +47 -0
  7. package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +45 -0
  8. package/android/src/main/java/net/siteed/audiostudio/VoiceProcessingEffects.kt +16 -5
  9. package/android/src/main/java/net/siteed/audiostudio/WebRtcAudioFrameProcessor.kt +118 -0
  10. package/android/src/main/jniLibs/arm64-v8a/libaozora_apm.so +0 -0
  11. package/android/src/main/webrtc-apm-notices/README.md +151 -0
  12. package/android/src/main/webrtc-apm-notices/THIRD_PARTY_NOTICES.md +25 -0
  13. package/android/src/main/webrtc-apm-notices/licenses/AUTHORS +7 -0
  14. package/android/src/main/webrtc-apm-notices/licenses/COPYING +29 -0
  15. package/android/src/main/webrtc-apm-notices/licenses/android-ndk/NOTICE +9997 -0
  16. package/android/src/main/webrtc-apm-notices/licenses/android-ndk/NOTICE.toolchain +15302 -0
  17. package/android/src/main/webrtc-apm-notices/licenses/subprojects/abseil-cpp-20230125.1/AUTHORS +6 -0
  18. package/android/src/main/webrtc-apm-notices/licenses/subprojects/abseil-cpp-20230125.1/LICENSE +203 -0
  19. package/android/src/main/webrtc-apm-notices/licenses/subprojects/abseil-cpp-20230125.1/LICENSE.build +19 -0
  20. package/android/src/main/webrtc-apm-notices/licenses/webrtc/LICENSE +29 -0
  21. package/android/src/main/webrtc-apm-notices/licenses/webrtc/PATENTS +24 -0
  22. package/android/src/main/webrtc-apm-notices/licenses/webrtc/common_audio/third_party/ooura/LICENSE +8 -0
  23. package/android/src/main/webrtc-apm-notices/licenses/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE +27 -0
  24. package/android/src/main/webrtc-apm-notices/licenses/webrtc/modules/third_party/fft/LICENSE +25 -0
  25. package/android/src/main/webrtc-apm-notices/licenses/webrtc/third_party/pffft/LICENSE +1 -0
  26. package/android/src/main/webrtc-apm-notices/licenses/webrtc/third_party/rnnoise/COPYING +1 -0
  27. package/android/src/main/webrtc-apm-notices/licenses/wrapper-LICENSE +27 -0
  28. package/android/src/main/webrtc-apm-notices/manifest.json +150 -0
  29. package/build/types/AudioStudio.types.d.ts +35 -1
  30. package/package.json +1 -1
  31. package/src/AudioStudio.types.ts +47 -0
@@ -0,0 +1,118 @@
1
+ package net.siteed.audiostudio
2
+
3
+ import com.aozora.audio.AozoraWebRtcApm
4
+
5
+ /** Owns one native WebRTC APM instance and its 10 ms capture/render framing. */
6
+ internal class WebRtcAudioFrameProcessor private constructor(
7
+ private var handle: Long,
8
+ val request: AudioProcessingRequest,
9
+ sampleRate: Int,
10
+ ) {
11
+ private val frameBytes = sampleRate / 100 * 2
12
+ private val captureFrames = Pcm16FrameAccumulator(frameBytes)
13
+ private val reverseFrames = Pcm16FrameAccumulator(frameBytes)
14
+
15
+ @Volatile
16
+ var reverseStreamConnected: Boolean = false
17
+ private set
18
+
19
+ @Volatile
20
+ var operational: Boolean = true
21
+ private set
22
+
23
+ @Synchronized
24
+ fun processCapture(data: ByteArray, length: Int): ByteArray {
25
+ if (handle == 0L || !operational) return data.copyOf(length)
26
+ return captureFrames.consume(data, length) { processFrame(it, reverse = false) }
27
+ }
28
+
29
+ @Synchronized
30
+ fun processReverse(data: ByteArray, length: Int, delayMs: Int): Boolean {
31
+ if (handle == 0L || !operational || !request.echoCancellation) return false
32
+ AozoraWebRtcApm.nativeSetStreamDelay(handle, delayMs.coerceIn(0, 500))
33
+ reverseFrames.consume(data, length) { processFrame(it, reverse = true) }
34
+ return reverseStreamConnected
35
+ }
36
+
37
+ @Synchronized
38
+ fun flushCapture(): ByteArray = captureFrames.drain()
39
+
40
+ @Synchronized
41
+ fun release() {
42
+ val current = handle
43
+ handle = 0L
44
+ operational = false
45
+ reverseStreamConnected = false
46
+ if (current != 0L) AozoraWebRtcApm.nativeRelease(current)
47
+ }
48
+
49
+ private fun processFrame(frame: ByteArray, reverse: Boolean): ByteArray {
50
+ val samples = ShortArray(frame.size / 2)
51
+ for (index in samples.indices) {
52
+ val offset = index * 2
53
+ samples[index] = (((frame[offset + 1].toInt() and 0xff) shl 8) or
54
+ (frame[offset].toInt() and 0xff)).toShort()
55
+ }
56
+ val status = if (reverse) {
57
+ AozoraWebRtcApm.nativeProcessReverse(handle, samples)
58
+ } else {
59
+ AozoraWebRtcApm.nativeProcessCapture(handle, samples)
60
+ }
61
+ if (status != 0 && status != WEBRTC_BAD_STREAM_PARAMETER_WARNING) {
62
+ operational = false
63
+ LogUtils.e(CLASS_NAME, "WebRTC APM ${if (reverse) "reverse" else "capture"} failed: $status")
64
+ return frame
65
+ }
66
+ if (reverse) reverseStreamConnected = true
67
+
68
+ val output = ByteArray(frame.size)
69
+ for (index in samples.indices) {
70
+ val value = samples[index].toInt()
71
+ output[index * 2] = (value and 0xff).toByte()
72
+ output[index * 2 + 1] = ((value ushr 8) and 0xff).toByte()
73
+ }
74
+ return output
75
+ }
76
+
77
+ companion object {
78
+ private const val CLASS_NAME = "WebRtcAudioFrameProcessor"
79
+ private const val WEBRTC_BAD_STREAM_PARAMETER_WARNING = -13
80
+ private val SUPPORTED_SAMPLE_RATES = setOf(8000, 16000, 32000, 48000)
81
+
82
+ fun create(
83
+ sampleRate: Int,
84
+ channels: Int,
85
+ encoding: String,
86
+ request: AudioProcessingRequest,
87
+ ): WebRtcAudioFrameProcessor? {
88
+ if (!request.anyEnabled) return null
89
+ if (sampleRate !in SUPPORTED_SAMPLE_RATES || channels != 1 || encoding != "pcm_16bit") {
90
+ LogUtils.w(
91
+ CLASS_NAME,
92
+ "WebRTC APM requires mono PCM16 at 8/16/32/48 kHz; got $sampleRate Hz, $channels channel(s), $encoding"
93
+ )
94
+ return null
95
+ }
96
+ if (!AozoraWebRtcApm.isAvailable()) {
97
+ LogUtils.w(CLASS_NAME, "WebRTC APM native library is unavailable for this ABI")
98
+ return null
99
+ }
100
+ val handle = AozoraWebRtcApm.nativeCreate(
101
+ sampleRate,
102
+ channels,
103
+ request.echoCancellation,
104
+ request.noiseSuppression,
105
+ request.automaticGainControl,
106
+ )
107
+ if (handle == 0L) {
108
+ LogUtils.w(CLASS_NAME, "WebRTC APM native processor creation failed")
109
+ return null
110
+ }
111
+ LogUtils.i(
112
+ CLASS_NAME,
113
+ "WebRTC APM enabled (AEC=${request.echoCancellation}, NS=${request.noiseSuppression}, AGC=${request.automaticGainControl})"
114
+ )
115
+ return WebRtcAudioFrameProcessor(handle, request, sampleRate)
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,151 @@
1
+ # webrtc-apm-deps-build
2
+
3
+ Independent, manual GitHub Actions builds for WebRTC Audio Processing 1.3 and
4
+ the Aozora APM native interface. This repository does not contain the consuming
5
+ application, downloaded toolchains, source caches, or prebuilt binaries.
6
+
7
+ ## Outputs
8
+
9
+ | Target | Artifact content | Baseline |
10
+ | --- | --- | --- |
11
+ | Android | `app-android/libs/<abi>/libaozora_apm.so` and C header | API 28, NDK r27c; ARM64 default |
12
+ | iOS | `app-ios/Frameworks/AozoraApm.xcframework` | iPhoneOS ARM64, iOS 14.0; no simulator |
13
+ | HarmonyOS | `app-harmony/libs/arm64-v8a/libaozora_apm.so`, required C++ runtime, N-API types and C header | ARM64 Linux-host Native SDK |
14
+
15
+ Android optionally builds the existing ARMv7 and x86 ABIs. No AAR, HAR or APK is
16
+ produced. Each ZIP includes license notices, `manifest.json`, per-file hashes,
17
+ architecture/dependency checks, and a separate archive SHA-256 file.
18
+
19
+ The common processing profile is mono signed PCM16, 10 ms frames, at 8/16/32/48
20
+ kHz. AEC3 is enabled; NS and AGC2 are optional. Render reference, capture
21
+ processing, stream delay and voice-detection state are exposed. The library
22
+ does not capture or play audio by itself.
23
+
24
+ ## Manual GitHub builds
25
+
26
+ 1. Open Actions, then **Build WebRTC APM native libraries**.
27
+ 2. Choose **Run workflow** on the latest `main`.
28
+ 3. Select `all` (default), `android`, `ios`, or `harmony`.
29
+ 4. Check any combination of `android_arm64` (ARM64), `android_armv7` (ARMv7),
30
+ and `android_x86` (x86). Only ARM64 is checked by default. Select at least
31
+ one ABI when building Android; the checkboxes are ignored for iOS and Harmony.
32
+ Choosing platform `all` builds all three platforms, not all Android ABIs.
33
+ 5. Download the platform artifact from that run. Retention is seven days.
34
+
35
+ Platform jobs are independent. One failure does not cancel the others. A
36
+ separate Linux host smoke job exercises the shared C API on every manual run;
37
+ that is not a phone-device test. Native builds are **manual-only**. Push/PR only
38
+ runs Python syntax, configuration, archive-safety and workflow-routing checks.
39
+ Start a new run after fixes; re-running an old record uses its original commit.
40
+
41
+ ### Harmony SDK configuration
42
+
43
+ Configure **this repository's** Settings / Secrets and variables / Actions:
44
+
45
+ - Secret `HARMONY_SDK_URL`: authorized HTTPS download URL for the Linux x64
46
+ `commandline-tools-linux-x64-26.0.0.851.zip` bundle. A signed URL may expire.
47
+ - Variable `HARMONY_SDK_SHA256`:
48
+ `ab604bd92721d5cbcafd154e6461d46b9f1b105e7b89eab04a9d046681198082`
49
+
50
+ Secrets in another repository are not automatically inherited. Set the URL
51
+ again here; do not post it in an issue or commit its query parameters. The script
52
+ verifies the archive and only extracts the Native SDK subtree. A `.har` package
53
+ or a Windows/macOS host SDK is not a Linux C/C++ toolchain. A local Linux build
54
+ may instead set `OHOS_SDK_NATIVE_DIR` to an already installed Native SDK.
55
+
56
+ If a run reports `Missing HARMONY_SDK_URL`, open
57
+ [this repository's Actions secrets](https://github.com/restia-aozora/webrtc-apm-deps-build/settings/secrets/actions),
58
+ choose **New repository secret**, enter `HARMONY_SDK_URL` as the name, and
59
+ paste a current, authorized HTTPS SDK download URL as the value without quotes.
60
+ The checksum belongs in the separate `HARMONY_SDK_SHA256` variable; a valid
61
+ checksum does not replace the download URL. This error is a configuration
62
+ preflight failure, not a native compiler failure. Start a new workflow run on
63
+ the updated `main` after configuring the secret to use the current inputs.
64
+
65
+ ## Integration
66
+
67
+ ### Android
68
+
69
+ Keep the existing Java/Kotlin class `com.aozora.audio.AozoraWebRtcApm` and its six
70
+ native methods: `nativeCreate`, `nativeProcessReverse`, `nativeProcessCapture`,
71
+ `nativeSetStreamDelay`, `nativeGetVoiceDetected`, and `nativeRelease`. Load
72
+ `aozora_apm` and install the `.so` for each supported ABI in the plugin's libs
73
+ directory. Preserve these class and method names in R8/ProGuard rules. Do not
74
+ rename JNI methods or install a library built for a different ABI.
75
+
76
+ ### iOS
77
+
78
+ Add and embed/sign `AozoraApm.xcframework` with your application, then import
79
+ `AozoraApm` from Swift. The build only ad-hoc signs the library; it does not sign
80
+ your application or provide an Apple distribution identity.
81
+
82
+ ```swift
83
+ import AozoraApm
84
+ let processor = aozora_apm_create(16000, 1, 1, 0)
85
+ // Feed 160 Int16 samples per render/capture call at 16 kHz.
86
+ aozora_apm_destroy(processor)
87
+ ```
88
+
89
+ ### HarmonyOS
90
+
91
+ Copy `app-harmony/libs/arm64-v8a` into the native libs location of your consuming
92
+ module, including any packaged `libc++_shared.so`. Add the bundled
93
+ `types/libaozora_apm` local type package as the module dependency named
94
+ `libaozora_apm.so`, then import it from ArkTS. The package's `index.d.ts` describes
95
+ `create`, `processReverse`, `processCapture`, `setStreamDelay`,
96
+ `getVoiceDetected` and `release`. Audio buffers are `Int16Array`, not raw pointer
97
+ numbers. This repository provides the native interface and types, not a full
98
+ UTS recorder implementation or microphone permissions configuration.
99
+
100
+ ### Frame and lifetime rules
101
+
102
+ Feed the actual playback-reference PCM to the reverse-stream API and microphone
103
+ PCM to the capture API in matching 10 ms frames. Supply measured playback-path
104
+ delay before capture processing. Processing is in-place. A return of zero or
105
+ the WebRTC bad-stream-parameter warning indicates an accepted frame; other
106
+ negative results indicate errors. Voice state is -1 (unknown), 0 or 1.
107
+
108
+ Do not destroy a C/JNI handle concurrently with processing, and never reuse a
109
+ destroyed pointer/long handle. Release N-API handles explicitly when finished;
110
+ their finalizer also handles garbage collection. The wrapper serializes
111
+ processing on one instance but does not manage application audio threads.
112
+
113
+ ## Local builds
114
+
115
+ Use Python 3.12+, Git, and the platform compiler. The script clones a fresh
116
+ pinned upstream commit and never edits an existing source checkout.
117
+
118
+ ```bash
119
+ python -m pip install -r requirements-build.txt
120
+ python -m unittest discover -s tests -p 'test_*.py' -v
121
+ python scripts/build.py android --android-abis arm64-v8a --jobs 3
122
+ python scripts/build.py android --android-abis arm64-v8a armeabi-v7a --jobs 3
123
+ python scripts/build.py ios --jobs 3
124
+ python scripts/build.py harmony --jobs 3
125
+ python scripts/build.py host --jobs 3
126
+ ```
127
+
128
+ Android requires `ANDROID_NDK_HOME` pointing to NDK `27.2.12479018`. Android
129
+ cross-compilation also supports Windows. iOS requires macOS/Xcode. Harmony and
130
+ the host smoke test require Linux. `--source-repository /path/to/local/clone`
131
+ can use a local clone without modifying it; the exact pinned commit remains
132
+ mandatory. Work files remain in ignored `.work/` for diagnosis; artifacts go to
133
+ ignored `dist/`. Do not upload work directories or SDK archives.
134
+
135
+ ## Provenance and validation limits
136
+
137
+ The source commit and dependency hashes match the reference local build.
138
+ The known `absl_crc` dependency fix is applied with an exact-match, fail-closed
139
+ patch. The wrapper compiles inside upstream Meson using the same architecture
140
+ and platform definitions; static dependencies, including private architecture
141
+ libraries, are resolved by Meson's dependency graph rather than a guessed list.
142
+
143
+ Native build scripts check exports, architecture, dynamic dependencies and
144
+ Android 16 KB ELF load alignment. iOS also checks a Swift module import. Those
145
+ checks do **not** establish HBuilderX/UTS integration, 16 KB APK zip alignment,
146
+ device loading, acoustic echo-cancellation quality, or upload quota compliance.
147
+ `manifest.json` explicitly reports device runtime and UTS validation as
148
+ `NOT RUN`. Complete native CI success is known only after an actual platform
149
+ run succeeds; this repository's existence is not evidence of that success.
150
+
151
+ Keep `licenses/` with redistributed artifacts. See `THIRD_PARTY_NOTICES.md`.
@@ -0,0 +1,25 @@
1
+ # Third-party notices
2
+
3
+ The repository contains build scripts and an APM wrapper, not a vendored WebRTC
4
+ tree or redistributable SDK. Native builds retrieve the pinned dependency source
5
+ in `dependencies.json` and must ship its original notices with their artifacts.
6
+
7
+ - WebRTC Audio Processing: the helloooideeeeea/webrtc-audio-processing fork,
8
+ commit `f8efa8486ac0dd463fb84e4e99be2e072c28adb8`, derived from the freedesktop
9
+ AudioProcessing distribution and the WebRTC project. Preserve its COPYING,
10
+ LICENSE, AUTHORS, PATENTS and included third-party notices.
11
+ - Abseil C++ 20230125.1 and Meson wrapdb port: Apache-2.0 source dependency;
12
+ preserve its LICENSE and any notices from the pinned source/port.
13
+ - The upstream tree includes PFFFT, RNNoise and other components. The build
14
+ collects their license/notice files with source-relative paths rather than
15
+ assuming all embedded code has the top-level license.
16
+ - Android NDK C++ runtime is linked into the Android wrapper. Its upstream
17
+ license notices must accompany redistribution; the build collects the NDK
18
+ runtime/toolchain notice files separately.
19
+ - Harmony SDK and Apple SDK are external toolchains, not published in this
20
+ repository. Only bundle the required target runtime when permitted, preserve
21
+ its notices, and comply with the toolchain provider's distribution terms.
22
+
23
+ `LICENSE` in this repository covers the new wrapper/build code, not third-party
24
+ source, toolchains, or linked dependencies. Do not remove `licenses/` from a
25
+ published native artifact.
@@ -0,0 +1,7 @@
1
+ # Names should be added to this file like so:
2
+ # Name or Organization <email address>
3
+
4
+ Google Inc.
5
+
6
+ # autofoo-based build system
7
+ Arun Raghavan <arun.raghavan@collabora.co.uk>
@@ -0,0 +1,29 @@
1
+ Copyright (c) 2011, Google Inc. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are
5
+ met:
6
+
7
+ * Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in
12
+ the documentation and/or other materials provided with the
13
+ distribution.
14
+
15
+ * Neither the name of Google nor the names of its contributors may
16
+ be used to endorse or promote products derived from this software
17
+ without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.