From d952c252750b67718ad67800f74060306fc50c8a Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Fri, 6 Feb 2015 18:05:09 +0100 Subject: [PATCH] Remove AudioTrack Java and use AudioTrack by default There is a new audiotrack module that use AudioTrack API by JNI. Use it per default because of the problems we have with Open Sles. AudioTrack (Java) and AudioTrack (Native) are now merged. --- libvlc/jni/Android.mk | 2 +- libvlc/jni/aout.c | 260 ------------------ libvlc/jni/aout.h | 35 --- libvlc/jni/libvlcjni.c | 27 +- .../src/org/videolan/libvlc/AudioOutput.java | 74 ----- libvlc/src/org/videolan/libvlc/LibVLC.java | 51 +--- vlc-android/res/values/strings.xml | 15 +- vlc-android/res/xml/preferences.xml | 3 +- .../videolan/vlc/gui/PreferencesActivity.java | 26 +- 9 files changed, 47 insertions(+), 446 deletions(-) delete mode 100644 libvlc/jni/aout.c delete mode 100644 libvlc/jni/aout.h delete mode 100644 libvlc/src/org/videolan/libvlc/AudioOutput.java diff --git a/libvlc/jni/Android.mk b/libvlc/jni/Android.mk index dbc561456..4134bb709 100644 --- a/libvlc/jni/Android.mk +++ b/libvlc/jni/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES += libvlcjni-equalizer.c LOCAL_SRC_FILES += libvlcjni-vlcobject.c LOCAL_SRC_FILES += java_event_thread.c LOCAL_SRC_FILES += libvlcjni-media.c libvlcjni-medialist.c libvlcjni-mediadiscoverer.c -LOCAL_SRC_FILES += aout.c vout.c native_crash_handler.c thumbnailer.c +LOCAL_SRC_FILES += vout.c native_crash_handler.c thumbnailer.c ifneq ($(APP_PLATFORM),android-21) # compat functions not needed after android-21 LOCAL_SRC_FILES += compat/pthread-condattr.c compat/pthread-rwlocks.c diff --git a/libvlc/jni/aout.c b/libvlc/jni/aout.c deleted file mode 100644 index 7d4d8ce15..000000000 --- a/libvlc/jni/aout.c +++ /dev/null @@ -1,260 +0,0 @@ -/***************************************************************************** - * aout.c - ***************************************************************************** - * Copyright © 2011-2012 VLC authors and VideoLAN - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -#include -#include -#include -#include - -#include - -#include - -#include "aout.h" - -#define LOG_TAG "VLC/JNI/aout" -#include "log.h" - -// An audio frame will contain FRAME_SIZE samples -#define FRAME_SIZE (4096*2) - -typedef struct -{ - jobject j_libVlc; /// Pointer to the LibVLC Java object - jmethodID play; /// Java method to play audio buffers - jbyteArray buffer; /// Raw audio data to be played -} aout_sys_t; - -#define THREAD_NAME "jni_aout" -extern int jni_attach_thread(JNIEnv **env, const char *thread_name); -extern void jni_detach_thread(); - -int aout_open(void **opaque, char *format, unsigned *rate, unsigned *nb_channels) -{ - LOGI ("Opening the JNI audio output"); - - aout_sys_t *p_sys = calloc (1, sizeof (*p_sys)); - if (!p_sys) - goto enomem; - - p_sys->j_libVlc = *opaque; // Keep a reference to our Java object - *opaque = (void*) p_sys; // The callback will need aout_sys_t - - LOGI ("Parameters: %u channels, FOURCC '%4.4s', sample rate: %uHz", - *nb_channels, format, *rate); - - JNIEnv *p_env; - if (jni_attach_thread (&p_env, THREAD_NAME) != 0) - { - LOGE("Could not attach the display thread to the JVM !"); - goto eattach; - } - - // Call the init function. - jclass cls = (*p_env)->GetObjectClass (p_env, p_sys->j_libVlc); - jmethodID methodIdInitAout = (*p_env)->GetMethodID (p_env, cls, - "initAout", "(III)V"); - if (!methodIdInitAout) - { - LOGE ("Method initAout() could not be found!"); - goto error; - } - - LOGV ("Number of channels forced to 2, number of samples to %d", FRAME_SIZE); - *nb_channels = 2; - - int aout_rate = *rate; - while (1) { - (*p_env)->CallVoidMethod (p_env, p_sys->j_libVlc, methodIdInitAout, - aout_rate, *nb_channels, FRAME_SIZE); - if ((*p_env)->ExceptionCheck (p_env) == 0) { - *rate = aout_rate; - break; - } - - if (aout_rate <= 0) { - LOGE ("initAout failed, invalid sample rate %dHz", aout_rate); - } else if (aout_rate != 44100) { - if (aout_rate < 4000) { - do { - aout_rate *= 2; - } while (aout_rate < 4000); - } else if (aout_rate > 48000) { - do { - aout_rate /= 2; - } while (aout_rate > 48000); - } else { - aout_rate = 44100; - } - - LOGE ("initAout failed, try next sample rate %dHz", aout_rate); - (*p_env)->ExceptionClear (p_env); - continue; - } - - LOGE ("Unable to create audio player!"); -#ifndef NDEBUG - (*p_env)->ExceptionDescribe (p_env); -#endif - (*p_env)->ExceptionClear (p_env); - goto error; - } - - /* Create a new byte array to store the audio data. */ - jbyteArray buffer = (*p_env)->NewByteArray (p_env, - *nb_channels * - FRAME_SIZE * - sizeof (uint16_t) /* =2 */); - if (buffer == NULL) - { - LOGE ("Could not allocate the Java byte array to store the audio data!"); - goto error; - } - - /* Use a global reference to not reallocate memory each time we run - the play function. */ - p_sys->buffer = (*p_env)->NewGlobalRef (p_env, buffer); - /* The local reference is no longer useful. */ - (*p_env)->DeleteLocalRef (p_env, buffer); - if (p_sys->buffer == NULL) - { - LOGE ("Could not create the global reference!"); - goto error; - } - - // Get the play methodId - p_sys->play = (*p_env)->GetMethodID (p_env, cls, "playAudio", "([BI)V"); - assert (p_sys->play != NULL); - jni_detach_thread (); - return 0; - -error: - jni_detach_thread (); -eattach: - *opaque = NULL; - free (p_sys); -enomem: - return -1; -} - -/** - * Play an audio frame - **/ -void aout_play(void *opaque, const void *samples, unsigned count, int64_t pts) -{ - aout_sys_t *p_sys = opaque; - JNIEnv *p_env; - - /* How ugly: we constantly attach/detach this thread to/from the JVM - * because it will be killed before aout_close is called. - * aout_close will actually be called in an different thread! - */ - jni_attach_thread (&p_env, THREAD_NAME); - - (*p_env)->SetByteArrayRegion (p_env, p_sys->buffer, 0, - 2 /*nb_channels*/ * count * sizeof (uint16_t), - (jbyte*) samples); - if ((*p_env)->ExceptionCheck (p_env)) - { - // This can happen if for some reason the size of the input buffer - // is larger than the size of the output buffer - LOGE ("An exception occurred while calling SetByteArrayRegion"); - (*p_env)->ExceptionDescribe (p_env); - (*p_env)->ExceptionClear (p_env); - return; - } - - (*p_env)->CallVoidMethod (p_env, p_sys->j_libVlc, p_sys->play, - p_sys->buffer, - 2 /*nb_channels*/ * count * sizeof (uint16_t), - FRAME_SIZE); - // FIXME: check for errors - - jni_detach_thread (); -} - -void aout_pause(void *opaque, int64_t pts) -{ - LOGI ("Pausing audio output"); - aout_sys_t *p_sys = opaque; - assert(p_sys); - - JNIEnv *p_env; - jni_attach_thread (&p_env, THREAD_NAME); - - // Call the pause function. - jclass cls = (*p_env)->GetObjectClass (p_env, p_sys->j_libVlc); - jmethodID methodIdPauseAout = (*p_env)->GetMethodID (p_env, cls, "pauseAout", "()V"); - if (!methodIdPauseAout) - LOGE ("Method pauseAout() could not be found!"); - (*p_env)->CallVoidMethod (p_env, p_sys->j_libVlc, methodIdPauseAout); - if ((*p_env)->ExceptionCheck (p_env)) - { - LOGE ("Unable to pause audio player!"); -#ifndef NDEBUG - (*p_env)->ExceptionDescribe (p_env); -#endif - (*p_env)->ExceptionClear (p_env); - } - - jni_detach_thread (); -} - -void aout_close(void *opaque) -{ - LOGI ("Closing audio output"); - aout_sys_t *p_sys = opaque; - assert(p_sys); - assert(p_sys->buffer); - - JNIEnv *p_env; - jni_attach_thread (&p_env, THREAD_NAME); - - // Call the close function. - jclass cls = (*p_env)->GetObjectClass (p_env, p_sys->j_libVlc); - jmethodID methodIdCloseAout = (*p_env)->GetMethodID (p_env, cls, "closeAout", "()V"); - if (!methodIdCloseAout) - LOGE ("Method closeAout() could not be found!"); - (*p_env)->CallVoidMethod (p_env, p_sys->j_libVlc, methodIdCloseAout); - if ((*p_env)->ExceptionCheck (p_env)) - { - LOGE ("Unable to close audio player!"); -#ifndef NDEBUG - (*p_env)->ExceptionDescribe (p_env); -#endif - (*p_env)->ExceptionClear (p_env); - } - - (*p_env)->DeleteGlobalRef (p_env, p_sys->buffer); - (*p_env)->DeleteGlobalRef (p_env, p_sys->j_libVlc); - jni_detach_thread (); - free (p_sys); -} - -int aout_get_native_sample_rate(void) -{ - JNIEnv *p_env; - jni_attach_thread (&p_env, THREAD_NAME); - jclass cls = (*p_env)->FindClass (p_env, "android/media/AudioTrack"); - jmethodID method = (*p_env)->GetStaticMethodID (p_env, cls, "getNativeOutputSampleRate", "(I)I"); - int sample_rate = (*p_env)->CallStaticIntMethod (p_env, cls, method, 3); // AudioManager.STREAM_MUSIC - jni_detach_thread (); - return sample_rate; -} diff --git a/libvlc/jni/aout.h b/libvlc/jni/aout.h deleted file mode 100644 index 3fa38335c..000000000 --- a/libvlc/jni/aout.h +++ /dev/null @@ -1,35 +0,0 @@ -/***************************************************************************** - * aout.h - ***************************************************************************** - * Copyright © 2011-2012 VLC authors and VideoLAN - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -#ifndef LIBVLCJNI_AOUT_H -#define LIBVLCJNI_AOUT_H - -#include - -#define AOUT_AUDIOTRACK_JAVA 0 -#define AOUT_AUDIOTRACK 1 -#define AOUT_OPENSLES 2 - -int aout_open(void **opaque, char *format, unsigned *rate, unsigned *nb_channels); -void aout_play(void *opaque, const void *samples, unsigned count, int64_t pts); -void aout_pause(void *opaque, int64_t pts); -void aout_close(void *opaque); - -#endif // LIBVLCJNI_AOUT_H diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c index 27d4e0698..96df260da 100644 --- a/libvlc/jni/libvlcjni.c +++ b/libvlc/jni/libvlcjni.c @@ -36,7 +36,6 @@ #include #include "libvlcjni.h" -#include "aout.h" #include "vout.h" #include "utils.h" #include "native_crash_handler.h" @@ -45,6 +44,9 @@ #define VOUT_OPENGLES2 1 #define VOUT_ANDROID_WINDOW 2 +#define AOUT_AUDIOTRACK 0 +#define AOUT_OPENSLES 1 + #define LOG_TAG "VLC/JNI/main" #include "log.h" @@ -498,6 +500,7 @@ void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jstring mrl, jobjectArray mediaOptions) { + jclass cls; /* Release previous media player, if any */ releaseMediaPlayer(env, thiz); @@ -508,16 +511,6 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0); jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz); // freed in aout_close - // If AOUT_AUDIOTRACK_JAVA, use amem - jclass cls = (*env)->GetObjectClass(env, thiz); - jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I"); - if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA ) - { - libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL, - (void*) myJavaLibVLC); - libvlc_audio_set_format_callbacks(mp, aout_open, aout_close); - } - /* Connect the event manager */ libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp); static const libvlc_event_type_t mp_events[] = { @@ -818,3 +811,15 @@ int jni_GetWindowSize(int *width, int *height) pthread_mutex_unlock(&vout_android_lock); return 0; } + +/* used by opensles module */ +int aout_get_native_sample_rate(void) +{ + JNIEnv *p_env; + jni_attach_thread (&p_env, THREAD_NAME); + jclass cls = (*p_env)->FindClass (p_env, "android/media/AudioTrack"); + jmethodID method = (*p_env)->GetStaticMethodID (p_env, cls, "getNativeOutputSampleRate", "(I)I"); + int sample_rate = (*p_env)->CallStaticIntMethod (p_env, cls, method, 3); // AudioManager.STREAM_MUSIC + jni_detach_thread (); + return sample_rate; +} diff --git a/libvlc/src/org/videolan/libvlc/AudioOutput.java b/libvlc/src/org/videolan/libvlc/AudioOutput.java deleted file mode 100644 index 06955ac7a..000000000 --- a/libvlc/src/org/videolan/libvlc/AudioOutput.java +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * Aout.java - ***************************************************************************** - * Copyright © 2011-2012 VLC authors and VideoLAN - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -package org.videolan.libvlc; - -import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.util.Log; - -public class AudioOutput { - /** - * Java side of the audio output module for Android. - * Uses an AudioTrack to play decoded audio buffers. - * - * TODO Use MODE_STATIC instead of MODE_STREAM with a MemoryFile (ashmem) - */ - - public AudioOutput() { - } - - private AudioTrack mAudioTrack; - private static final String TAG = "LibVLC/aout"; - - public void init(int sampleRateInHz, int channels, int samples) { - Log.d(TAG, sampleRateInHz + ", " + channels + ", " + samples + "=>" + channels * samples); - int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, - AudioFormat.CHANNEL_OUT_STEREO, - AudioFormat.ENCODING_PCM_16BIT); - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, - sampleRateInHz, - AudioFormat.CHANNEL_OUT_STEREO, - AudioFormat.ENCODING_PCM_16BIT, - Math.max(minBufferSize, channels * samples * 2), - AudioTrack.MODE_STREAM); - } - - public void release() { - if (mAudioTrack != null) { - mAudioTrack.release(); - } - mAudioTrack = null; - } - - public void playBuffer(byte[] audioData, int bufferSize) { - if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) - return; - if (mAudioTrack.write(audioData, 0, bufferSize) != bufferSize) { - Log.w(TAG, "Could not write all the samples to the audio device"); - } - mAudioTrack.play(); - } - - public void pause() { - mAudioTrack.pause(); - } -} diff --git a/libvlc/src/org/videolan/libvlc/LibVLC.java b/libvlc/src/org/videolan/libvlc/LibVLC.java index e7284ead1..986043631 100644 --- a/libvlc/src/org/videolan/libvlc/LibVLC.java +++ b/libvlc/src/org/videolan/libvlc/LibVLC.java @@ -31,9 +31,8 @@ import android.view.Surface; public class LibVLC { private static final String TAG = "VLC/LibVLC"; - public static final int AOUT_AUDIOTRACK_JAVA = 0; - public static final int AOUT_AUDIOTRACK = 1; - public static final int AOUT_OPENSLES = 2; + public static final int AOUT_AUDIOTRACK = 0; + public static final int AOUT_OPENSLES = 1; public static final int VOUT_ANDROID_SURFACE = 0; public static final int VOUT_OPEGLES2 = 1; @@ -73,8 +72,6 @@ public class LibVLC { private StringBuffer mDebugLogBuffer; private boolean mIsBufferingLog = false; - private AudioOutput mAout; - /** Keep screen bright */ //private WakeLock mWakeLock; @@ -84,7 +81,7 @@ public class LibVLC { private String codecList = DEFAULT_CODEC_LIST; private String devCodecList = null; private String subtitlesEncoding = ""; - private int aout = LibVlcUtil.isGingerbreadOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA; + private int aout = AOUT_AUDIOTRACK; private int vout = VOUT_ANDROID_SURFACE; private boolean timeStretching = false; private int deblocking = -1; @@ -196,7 +193,6 @@ public class LibVLC { * It is private because this class is a singleton. */ private LibVLC() { - mAout = new AudioOutput(); } /** @@ -363,10 +359,10 @@ public class LibVLC { } public void setAout(int aout) { - if (aout < 0) - this.aout = LibVlcUtil.isICSOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA; + if (aout == AOUT_OPENSLES && LibVlcUtil.isICSOrLater()) + this.aout = AOUT_OPENSLES; else - this.aout = aout; + this.aout = AOUT_AUDIOTRACK; } public int getVout() { @@ -518,41 +514,6 @@ public class LibVLC { mIsInitialized = false; } - /** - * Open the Java audio output. - * This function is called by the native code - */ - public void initAout(int sampleRateInHz, int channels, int samples) { - Log.d(TAG, "Opening the java audio output"); - mAout.init(sampleRateInHz, channels, samples); - } - - /** - * Play an audio buffer taken from the native code - * This function is called by the native code - */ - public void playAudio(byte[] audioData, int bufferSize) { - mAout.playBuffer(audioData, bufferSize); - } - - /** - * Pause the Java audio output - * This function is called by the native code - */ - public void pauseAout() { - Log.d(TAG, "Pausing the java audio output"); - mAout.pause(); - } - - /** - * Close the Java audio output - * This function is called by the native code - */ - public void closeAout() { - Log.d(TAG, "Closing the java audio output"); - mAout.release(); - } - /** * Play an MRL directly. * diff --git a/vlc-android/res/values/strings.xml b/vlc-android/res/values/strings.xml index 666b1b660..9454d4e86 100644 --- a/vlc-android/res/values/strings.xml +++ b/vlc-android/res/values/strings.xml @@ -268,9 +268,8 @@ Advanced Audio output Change the method that VLC uses to output audio. - AudioTrack (native) - AudioTrack (Java) - OpenSL ES + AudioTrack + OpenSL ES Video output Change the method that VLC uses to output video. Android surface @@ -476,23 +475,13 @@ Windows-1258 - - @string/aout_audiotrack_java - @string/aout_audiotrack - - @string/aout_audiotrack_java @string/aout_audiotrack @string/aout_opensles - - 0 - 1 - 0 1 - 2 diff --git a/vlc-android/res/xml/preferences.xml b/vlc-android/res/xml/preferences.xml index 510833efc..4aec0ac69 100644 --- a/vlc-android/res/xml/preferences.xml +++ b/vlc-android/res/xml/preferences.xml @@ -108,7 +108,8 @@ - +