From a99dfd80ccff8b39ca7014d42c93586dbe6e7edf Mon Sep 17 00:00:00 2001 From: Mis012 Date: Sun, 28 Apr 2024 23:39:04 +0200 Subject: [PATCH] AudioTrack: fix getPlaybackHeadPosition and write this fixes audio sync in exoplayer --- .../audio/android_media_AudioTrack.c | 17 +++++++++++---- .../android_media_AudioTrack.h | 10 +++++++++ src/api-impl/android/media/AudioTrack.java | 21 ++++++++++++++----- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/api-impl-jni/audio/android_media_AudioTrack.c b/src/api-impl-jni/audio/android_media_AudioTrack.c index d0255c0e..f29d1d41 100644 --- a/src/api-impl-jni/audio/android_media_AudioTrack.c +++ b/src/api-impl-jni/audio/android_media_AudioTrack.c @@ -217,7 +217,7 @@ JNIEXPORT void JNICALL Java_android_media_AudioTrack_native_1play(JNIEnv *env, j /*--↑*/ } -JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1write(JNIEnv *env, jobject this, jbyteArray audioData, jint offsetInBytes, jint frames_to_write) +JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1write(JNIEnv *env, jobject this, jbyteArray audio_data, jint offset_in_bytes, jint frames_to_write) { int ret; @@ -225,9 +225,9 @@ JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1write(JNIEnv *env, snd_pcm_sframes_t frames_written; - jbyte *buffer = _GET_BYTE_ARRAY_ELEMENTS(audioData); + jbyte *buffer = _GET_BYTE_ARRAY_ELEMENTS(audio_data); - ret = frames_written = snd_pcm_writei(pcm_handle, buffer, frames_to_write); + ret = frames_written = snd_pcm_writei(pcm_handle, buffer + offset_in_bytes, frames_to_write); if (ret < 0) { if (ret == -EPIPE) { printf("XRUN.\n"); @@ -239,7 +239,7 @@ JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1write(JNIEnv *env, // printf("::::> tried to write %d frames, actually wrote %d frames.\n", frames_to_write, frames_written); - _RELEASE_BYTE_ARRAY_ELEMENTS(audioData, buffer); + _RELEASE_BYTE_ARRAY_ELEMENTS(audio_data, buffer); return frames_written; } @@ -254,3 +254,12 @@ JNIEXPORT void JNICALL Java_android_media_AudioTrack_native_1release(JNIEnv *env snd_pcm_t *pcm_handle = _PTR(_GET_LONG_FIELD(this, "pcm_handle")); snd_pcm_close(pcm_handle); } + +JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1getPlaybackHeadPosition(JNIEnv *env, jobject this) +{ + snd_pcm_t *pcm_handle = _PTR(_GET_LONG_FIELD(this, "pcm_handle")); + snd_pcm_sframes_t delay; + snd_pcm_delay(pcm_handle, &delay); + + return delay; +} diff --git a/src/api-impl-jni/generated_headers/android_media_AudioTrack.h b/src/api-impl-jni/generated_headers/android_media_AudioTrack.h index 4795849c..3de6ac64 100644 --- a/src/api-impl-jni/generated_headers/android_media_AudioTrack.h +++ b/src/api-impl-jni/generated_headers/android_media_AudioTrack.h @@ -7,6 +7,8 @@ #ifdef __cplusplus extern "C" { #endif +#undef android_media_AudioTrack_ERROR_BAD_VALUE +#define android_media_AudioTrack_ERROR_BAD_VALUE -2L #undef android_media_AudioTrack_PLAYSTATE_STOPPED #define android_media_AudioTrack_PLAYSTATE_STOPPED 1L #undef android_media_AudioTrack_PLAYSTATE_PAUSED @@ -29,6 +31,14 @@ JNIEXPORT void JNICALL Java_android_media_AudioTrack_native_1constructor JNIEXPORT jint JNICALL Java_android_media_AudioTrack_getMinBufferSize (JNIEnv *, jclass, jint, jint, jint); +/* + * Class: android_media_AudioTrack + * Method: native_getPlaybackHeadPosition + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_media_AudioTrack_native_1getPlaybackHeadPosition + (JNIEnv *, jobject); + /* * Class: android_media_AudioTrack * Method: native_play diff --git a/src/api-impl/android/media/AudioTrack.java b/src/api-impl/android/media/AudioTrack.java index bfa11c6b..5323fc0c 100644 --- a/src/api-impl/android/media/AudioTrack.java +++ b/src/api-impl/android/media/AudioTrack.java @@ -6,6 +6,8 @@ public class AudioTrack { void onPeriodicNotification(AudioTrack track); } + public static final int ERROR_BAD_VALUE = -2; // basically EINVAL + public static final int PLAYSTATE_STOPPED = 1; public static final int PLAYSTATE_PAUSED = 2; public static final int PLAYSTATE_PLAYING = 3; @@ -67,7 +69,7 @@ public class AudioTrack { } public int setPositionNotificationPeriod(int periodInFrames) { - System.out.println("\n\n\nsetPositionNotificationPeriod(" + periodInFrames + "); called\n\n\n\n"); + System.out.println("\n\nAudioTrack.nsetPositionNotificationPeriod(" + periodInFrames + "); called\n\n\n\n"); return 0; // SUCCESS } @@ -82,16 +84,16 @@ public class AudioTrack { } public void stop() { - System.out.println("calling stop(), how did this not get reported before DIDREEEEEEEEEEEEEEEEEEEEEEEEE\n"); + System.out.println("STUB: AudioTrack.stop()\n"); playbackState = PLAYSTATE_STOPPED; } public void flush() { - System.out.println("calling flush(), how did this not get reported before DIDREEEEEEEEEEEEEEEEEEEEEEEEE\n"); + System.out.println("STUB: AudioTrack.flush()\n"); } public void release() { - System.out.println("calling release(), how did this not get reported before DIDREEEEEEEEEEEEEEEEEEEEEEEEE\n"); + System.out.println("calling AudioTrack.release()\n"); native_release(); } @@ -100,6 +102,14 @@ public class AudioTrack { } public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) { + /* sanity check the parameters before calling native_write */ + if ((audioData == null) + || (offsetInBytes < 0) || (sizeInBytes < 0) + || (offsetInBytes + sizeInBytes < 0) + || (offsetInBytes + sizeInBytes > audioData.length)) { + return ERROR_BAD_VALUE; + } + int framesToWrite = sizeInBytes / channels / 2; // 2 means PCM16 int ret = native_write(audioData, offsetInBytes, framesToWrite); if (ret > 0) { @@ -131,9 +141,10 @@ public class AudioTrack { } public int getPlaybackHeadPosition() { - return playbackHeadPosition; + return playbackHeadPosition - native_getPlaybackHeadPosition(); } + private native int native_getPlaybackHeadPosition(); public native void native_play(); public native void native_pause(); private native int native_write(byte[] audioData, int offsetInBytes, int sizeInBytes);