Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
- "src/**"
- "tests/test_amy_unix_socket.c"
- "tests/run_amy_unix_socket_test.sh"
- "tests/check_android_audio_capture.py"
- ".github/workflows/android.yml"

permissions:
Expand Down Expand Up @@ -84,26 +85,51 @@ jobs:
adb logcat -c
adb shell am start -W -n org.amy.hello/.MainActivity
sleep 10
adb logcat -d -s AmyAndroid:I AmyService:I AmyHelloWorld:I '*:S' > /tmp/amy-first.log
adb logcat -d -s AmyAndroid:I AmyAudioCapture:I AmyService:I AmyHelloWorld:I '*:S' > /tmp/amy-first.log
test "$(grep -c 'AMY/Oboe started' /tmp/amy-first.log)" -eq 1
grep -q 'AMY output route: deviceId=' /tmp/amy-first.log
test "$(grep -c 'C scale complete' /tmp/amy-first.log)" -eq 1
! grep -q 'C scale failed' /tmp/amy-first.log
grep -q 'wire: v0w0V2.0Z' /tmp/amy-first.log
grep -q 'wire: v0w0V10.0Z' /tmp/amy-first.log
test "$(grep -Ec 'wire: v0n(60|62|64|65|67|69|71|72)l1Z' /tmp/amy-first.log)" -eq 8
grep -q 'wire: v0n60l1Z' /tmp/amy-first.log
grep -q 'wire: v0n72l1Z' /tmp/amy-first.log
grep -q 'Audio capture complete:' /tmp/amy-first.log

adb uninstall org.amy.hello
adb install android/hello-world/build/outputs/apk/debug/hello-world-debug.apk
adb logcat -c
adb shell am start -W -n org.amy.hello/.MainActivity
sleep 10
adb logcat -d -s AmyAndroid:I AmyService:I AmyHelloWorld:I '*:S' > /tmp/amy-second.log
adb logcat -d -s AmyAndroid:I AmyAudioCapture:I AmyService:I AmyHelloWorld:I '*:S' > /tmp/amy-second.log
test "$(grep -c 'AMY/Oboe started' /tmp/amy-second.log)" -eq 1
grep -q 'AMY output route: deviceId=' /tmp/amy-second.log
test "$(grep -c 'C scale complete' /tmp/amy-second.log)" -eq 1
! grep -q 'C scale failed' /tmp/amy-second.log
grep -q 'wire: v0w0V2.0Z' /tmp/amy-second.log
grep -q 'wire: v0w0V10.0Z' /tmp/amy-second.log
test "$(grep -Ec 'wire: v0n(60|62|64|65|67|69|71|72)l1Z' /tmp/amy-second.log)" -eq 8
grep -q 'wire: v0n60l1Z' /tmp/amy-second.log
grep -q 'wire: v0n72l1Z' /tmp/amy-second.log
grep -q 'Audio capture complete:' /tmp/amy-second.log

mkdir -p android/audio-capture
adb exec-out run-as org.amy.hello cat files/amy-render.wav > android/audio-capture/amy-render.wav
adb exec-out run-as org.amy.hello cat files/amy-oboe.wav > android/audio-capture/amy-oboe.wav
adb exec-out run-as org.amy.hello cat files/amy-audio-levels.txt > android/audio-capture/amy-audio-levels.txt
test -s android/audio-capture/amy-render.wav
test -s android/audio-capture/amy-oboe.wav
test -s android/audio-capture/amy-audio-levels.txt
cat android/audio-capture/amy-audio-levels.txt

- name: Analyze captured AMY and Oboe audio levels
run: |
python3 tests/check_android_audio_capture.py \
android/audio-capture/amy-render.wav \
android/audio-capture/amy-oboe.wav

- name: Upload Android audio captures
uses: actions/upload-artifact@v4
with:
name: amy-android-audio-capture
path: android/audio-capture/
if-no-files-found: error
1 change: 1 addition & 0 deletions android/amy-service/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(AMY_SOURCES

add_library(amy_android SHARED
amy_android.cpp
amy_android_capture.cpp
amy_android_profile.cpp
${AMY_SOURCES}
)
Expand Down
21 changes: 21 additions & 0 deletions android/amy-service/src/main/cpp/amy_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <mutex>
#include <thread>

#include "amy_android_capture.h"

extern "C" {
#include "amy.h"
#include "amy_unix_socket.h"
Expand Down Expand Up @@ -73,6 +75,12 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,
amy_start(config);
mAmyStarted = true;

// The helper remains dormant unless the hello-world test has created
// its one-shot private capture marker. It captures the exact samples
// returned by AMY and the exact I16 samples handed to Oboe.
mCapture = std::make_unique<AmyAndroidAudioCapture>(
socketPath, AMY_SAMPLE_RATE, AMY_NCHANS);

oboe::AudioStreamBuilder builder;
builder.setDirection(oboe::Direction::Output);
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
Expand Down Expand Up @@ -188,6 +196,12 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,
mStream.reset();
}

// No callback can touch the capture buffers after the stream closes.
if (mCapture) {
mCapture->stop();
mCapture.reset();
}

cleanupSocketAndAmy();
mAudioCallbackSeen.store(false, std::memory_order_release);
mBlock = nullptr;
Expand All @@ -206,6 +220,7 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,
}

mAudioCallbackSeen.store(true, std::memory_order_release);
if (mCapture && mCapture->enabled()) mCapture->beginCallback(numFrames);

int32_t outputFrame = 0;
while (outputFrame < numFrames) {
Expand All @@ -223,6 +238,10 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,

const int32_t available = AMY_BLOCK_SIZE - mBlockFrame;
const int32_t frames = std::min(available, numFrames - outputFrame);
if (mCapture && mCapture->enabled()) {
mCapture->captureAmyChunk(
mBlock + mBlockFrame * AMY_NCHANS, frames, outputFrame);
}
std::memcpy(
output + outputFrame * AMY_NCHANS,
mBlock + mBlockFrame * AMY_NCHANS,
Expand All @@ -231,6 +250,7 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,
mBlockFrame += frames;
}

if (mCapture && mCapture->enabled()) mCapture->finishCallback(output, numFrames);
return oboe::DataCallbackResult::Continue;
}

Expand Down Expand Up @@ -281,6 +301,7 @@ class AmyAndroidEngine final : public oboe::AudioStreamDataCallback,
bool mAmyStarted = false;
std::atomic<amy_unix_socket_server_t *> mSocket{nullptr};
std::shared_ptr<oboe::AudioStream> mStream;
std::unique_ptr<AmyAndroidAudioCapture> mCapture;
int16_t *mBlock = nullptr;
int32_t mBlockFrame = AMY_BLOCK_SIZE;
};
Expand Down
Loading
Loading