提交 8f685451 编写于 作者: Z Zhang Rui

ijksdl: implement android_audiotrack

上级 c246983a
......@@ -24,6 +24,7 @@ LOCAL_LDLIBS += -llog -landroid
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)
LOCAL_C_INCLUDES += $(MY_APP_JNI_ROOT)
LOCAL_SRC_FILES += ijksdl_aout.c
LOCAL_SRC_FILES += ijksdl_audio.c
......@@ -38,6 +39,7 @@ LOCAL_SRC_FILES += ijksdl_vout_ffmpeg.c
LOCAL_SRC_FILES += ijksdl_aout_android.c
LOCAL_SRC_FILES += ijksdl_vout_android.c
LOCAL_SRC_FILES += android/android_audiotrack.c
LOCAL_SHARED_LIBRARIES := ffmpeg ijkutil
......
/*****************************************************************************
* ijksdl_android_audiotrack.c
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "android_audiotrack.h"
#include <assert.h>
#include "ijkutil/ijkutil.h"
typedef struct SDL_AndroidAudioTrack {
jobject thiz;
SDL_AndroidAudioTrack_Spec spec;
jbyteArray buffer;
int buffer_capacity;
int min_buffer_size;
} SDL_AndroidAudioTrack;
typedef struct audio_track_fields_t {
jclass clazz;
jmethodID constructor;
jmethodID getMinBufferSize;
jmethodID play;
jmethodID pause;
jmethodID flush;
jmethodID stop;
jmethodID release;
jmethodID write_byte;
} audio_track_fields_t;
static audio_track_fields_t g_clazz;
#define AT_CHECK_RET(condition__, retval__, ...) \
if (!(condition__)) { \
ALOGE(__VA_ARGS__); \
return (retval__); \
}
int sdl_audiotrack_global_init(JNIEnv *env)
{
g_clazz.clazz = (*env)->FindClass(env, "android.media.AudioTrack");
AT_CHECK_RET(g_clazz.clazz, -1, "missing AudioTrack");
g_clazz.constructor = (*env)->GetMethodID(env, g_clazz.clazz, "<init>", "(IIIIII)V");
AT_CHECK_RET(g_clazz.constructor, -1, "missing AudioTrack.<init>");
g_clazz.getMinBufferSize = (*env)->GetStaticMethodID(env, g_clazz.clazz, "getMinBufferSize", "(III)V");
AT_CHECK_RET(g_clazz.getMinBufferSize, -1, "missing AudioTrack.getMinBufferSize");
g_clazz.play = (*env)->GetMethodID(env, g_clazz.clazz, "play", "(V)V");
AT_CHECK_RET(g_clazz.play, -1, "missing AudioTrack.play");
g_clazz.pause = (*env)->GetMethodID(env, g_clazz.clazz, "pause", "(V)V");
AT_CHECK_RET(g_clazz.pause, -1, "missing AudioTrack.pause");
g_clazz.flush = (*env)->GetMethodID(env, g_clazz.clazz, "flush", "(V)V");
JNI_CHECK_RET(g_clazz.flush, env, NULL, NULL, -1);
g_clazz.stop = (*env)->GetMethodID(env, g_clazz.clazz, "stop", "(V)V");
JNI_CHECK_RET(g_clazz.stop, env, NULL, NULL, -1);
g_clazz.release = (*env)->GetMethodID(env, g_clazz.clazz, "release", "(V)V");
JNI_CHECK_RET(g_clazz.release, env, NULL, NULL, -1);
g_clazz.write_byte = (*env)->GetMethodID(env, g_clazz.clazz, "write", "([BII)V");
JNI_CHECK_RET(g_clazz.write_byte, env, NULL, NULL, -1);
return 0;
}
void sdl_audiotrack_get_default_spec(SDL_AndroidAudioTrack_Spec *spec)
{
assert(spec);
spec->stream_type = STREAM_MUSIC;
spec->sample_rate_in_hz = 0;
spec->channel_config = CHANNEL_OUT_STEREO;
spec->audio_format = ENCODING_PCM_16BIT;
spec->buffer_size_in_bytes = 0;
spec->mode = MODE_STREAM;
}
SDL_AndroidAudioTrack *sdl_audiotrack_new(JNIEnv *env, SDL_AndroidAudioTrack_Spec *spec)
{
assert(spec);
SDL_AndroidAudioTrack *atrack = (SDL_AndroidAudioTrack*) malloc(sizeof(SDL_AndroidAudioTrack));
if (!atrack)
return NULL;
memset(atrack, 0, sizeof(SDL_AndroidAudioTrack));
atrack->spec = *spec;
jobject thiz = (*env)->NewObject(env, g_clazz.clazz, g_clazz.constructor,
spec->stream_type, spec->sample_rate_in_hz, spec->channel_config,
spec->audio_format, spec->buffer_size_in_bytes, spec->mode);
if (!thiz || (*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_new: NewObject: Exception:");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
free(atrack);
return NULL;
}
atrack->thiz = (*env)->NewGlobalRef(env, thiz);
(*env)->DeleteLocalRef(env, thiz);
atrack->min_buffer_size = sdl_audiotrack_get_min_buffer_size(env, atrack);
return atrack;
}
int sdl_audiotrack_get_min_buffer_size(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
int retval = (*env)->CallStaticIntMethod(env, g_clazz.clazz, g_clazz.getMinBufferSize,
(int) atrack->spec.sample_rate_in_hz,
(int) atrack->spec.channel_config,
(int) atrack->spec.audio_format);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_get_min_buffer_size: getMinBufferSize: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return -1;
}
return retval;
}
void sdl_audiotrack_play(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
(*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.play);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_play: play: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
}
void sdl_audiotrack_pause(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
(*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.pause);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_pause: pause: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
}
void sdl_audiotrack_flush(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
(*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.flush);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_flush: flush: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
}
void sdl_audiotrack_stop(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
(*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.stop);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_stop: stop: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
}
void sdl_audiotrack_release(JNIEnv *env, SDL_AndroidAudioTrack *atrack)
{
(*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.release);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_release: release: Exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
}
int sdl_audiotrack_reserve_buffer(JNIEnv *env, SDL_AndroidAudioTrack *atrack, int len)
{
if (atrack->buffer && len <= atrack->buffer_capacity)
return len;
if (atrack->buffer) {
(*env)->DeleteLocalRef(env, atrack->buffer);
atrack->buffer = NULL;
atrack->buffer_capacity = 0;
}
int capacity = IJKMAX(len, atrack->min_buffer_size);
jbyteArray buffer = (*env)->NewByteArray(env, capacity);
if (!buffer || (*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_reserve_buffer: NewByteArray: Exception:");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
return -1;
}
atrack->buffer_capacity = capacity;
atrack->buffer = (*env)->NewGlobalRef(env, buffer);
(*env)->DeleteLocalRef(env, buffer);
return capacity;
}
int sdl_audiotrack_write_byte(JNIEnv *env, SDL_AndroidAudioTrack *atrack, uint8_t *data, int len)
{
if (len <= 0)
return len;
int reserved = sdl_audiotrack_reserve_buffer(env, atrack, len);
if (reserved < len)
return -1;
(*env)->SetByteArrayRegion(env, atrack->buffer, 0, len, (jbyte*) data);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_write_byte: SetByteArrayRegion: Exception:");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
return -1;
}
int retval = (*env)->CallIntMethod(env, atrack->thiz, g_clazz.write_byte,
atrack->buffer, 0, len);
if ((*env)->ExceptionCheck(env)) {
ALOGE("sdl_audiotrack_write_byte: flush: Exception:");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
return -1;
}
return retval;
}
/*****************************************************************************
* ijksdl_android_audiotrack.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDL__IJKSDL_ANDROID_AUDIOTRACK_H
#define IJKSDL__IJKSDL_ANDROID_AUDIOTRACK_H
#include <stdint.h>
#include <jni.h>
typedef struct SDL_AndroidAudioTrack_Spec {
enum StreamType {
STREAM_VOICE_CALL = 0,
STREAM_SYSTEM = 1,
STREAM_RING = 2,
STREAM_MUSIC = 3,
STREAM_ALARM = 4,
STREAM_NOTIFICATION = 5,
} stream_type;
int sample_rate_in_hz;
enum ChannelConfig {
CHANNEL_OUT_DEFAULT = 0x1, /* f-l */
CHANNEL_OUT_MONO = 0x4, /* f-l, f-r */
CHANNEL_OUT_STEREO = 0xc, /* f-l, f-r, b-l, b-r */
CHANNEL_OUT_QUAD = 0xcc, /* f-l, f-r, b-l, b-r, f-c, low */
CHANNEL_OUT_SURROUND = 0x41c, /* f-l, f-r, f-c, b-c */
CHANNEL_OUT_5POINT1 = 0xfc, /* f-l, f-r, b-l, b-r, f-c, low */
CHANNEL_OUT_7POINT1 = 0x3fc, /* f-l, f-r, b-l, b-r, f-c, low, f-lc, f-rc */
CHANNEL_OUT_FRONT_LEFT = 0x4,
CHANNEL_OUT_FRONT_RIGHT = 0x8,
CHANNEL_OUT_BACK_LEFT = 0x40,
CHANNEL_OUT_BACK_RIGHT = 0x80,
CHANNEL_OUT_FRONT_CENTER = 0x10,
CHANNEL_OUT_LOW_FREQUENCY = 0x20,
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
CHANNEL_OUT_BACK_CENTER = 0x400,
} channel_config;
enum AudioFormat {
ENCODING_INVALID = 0,
ENCODING_DEFAULT = 1,
ENCODING_PCM_16BIT = 2,
ENCODING_PCM_8BIT = 3,
} audio_format;
int buffer_size_in_bytes;
enum Mode {
MODE_STATIC = 0,
MODE_STREAM = 1,
} mode;
} SDL_AndroidAudioTrack_Spec;
typedef struct SDL_AndroidAudioTrack SDL_AndroidAudioTrack;
int sdl_audiotrack_global_init(JNIEnv *env);
void sdl_audiotrack_get_default_spec(SDL_AndroidAudioTrack_Spec *spec);
SDL_AndroidAudioTrack *sdl_audiotrack_new(JNIEnv *env, SDL_AndroidAudioTrack_Spec *spec);
int sdl_audiotrack_get_min_buffer_size(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
void sdl_audiotrack_play(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
void sdl_audiotrack_pause(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
void sdl_audiotrack_flush(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
void sdl_audiotrack_stop(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
void sdl_audiotrack_release(JNIEnv *env, SDL_AndroidAudioTrack *atrack);
int sdl_audiotrack_reserve_buffer(JNIEnv *env, SDL_AndroidAudioTrack *atrack, int len);
int sdl_audiotrack_write_byte(JNIEnv *env, SDL_AndroidAudioTrack *atrack, uint8_t *data, int len);
#endif
......@@ -31,16 +31,10 @@ int SDL_AoutOpenAudio(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obt
return -1;
}
void SDL_AoutPlayAudio(SDL_Aout *aout)
{
if (aout && aout->play_audio)
return aout->play_audio(aout);
}
void SDL_AoutPauseAudio(SDL_Aout *aout)
void SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on)
{
if (aout && aout->pause_audio)
return aout->pause_audio(aout);
aout->pause_audio(aout, pause_on);
}
void SDL_AoutCloseAudio(SDL_Aout *aout)
......
......@@ -35,14 +35,12 @@ typedef struct SDL_Aout {
SDL_Aout_Opaque *opaque;
void (*free_l)(SDL_Aout *vout);
int (*open_audio)(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obtained);
void (*play_audio)(SDL_Aout *aout);
void (*pause_audio)(SDL_Aout *aout);
void (*pause_audio)(SDL_Aout *aout, int pause_on);
void (*close_audio)(SDL_Aout *aout);
} SDL_Aout;
int SDL_AoutOpenAudio(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obtained);
void SDL_AoutPlayAudio(SDL_Aout *aout);
void SDL_AoutPauseAudio(SDL_Aout *aout);
void SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on);
void SDL_AoutCloseAudio(SDL_Aout *aout);
void SDL_AoutFreeAudio(SDL_Aout *aout);
......
......@@ -23,14 +23,37 @@
#include "ijksdl_aout_android.h"
#include "ijksdl_thread.h"
#include "ijksdl_aout_internal.h"
typedef struct SDL_Aout_Opaque {
JavaVM *jvm;
SDL_cond *wakeup;
int abort_request;
SDL_Thread *audio_thread;
SDL_Thread _audio_tid;
} SDL_Aout_Opaque;
void aout_free_l(SDL_Aout *vout)
int aout_thread(void *arg)
{
SDL_Aout *aout = arg;
SDL_Aout_Opaque *opaque = aout->opaque;
return 0;
}
void aout_free_l(SDL_Aout *aout)
{
if (!aout)
return;
SDL_Aout_Opaque *opaque = aout->opaque;
if (opaque) {
SDL_DestroyCond(opaque->wakeup);
}
SDL_Aout_FreeInternal(aout);
}
int aout_open_audio(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
......@@ -38,32 +61,33 @@ int aout_open_audio(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obtai
return -1;
}
void aout_play_audio(SDL_Aout *aout)
void aout_pause_audio(SDL_Aout *aout, int pause_on)
{
}
void aout_pause_audio(SDL_Aout *aout)
void aout_close_audio(SDL_Aout *aout)
{
}
void aout_close_audio(SDL_Aout *aout)
void SDL_Init_AoutAndroid(JNIEnv *env)
{
}
SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack(JNIEnv *env)
SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack(JavaVM* jvm)
{
SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));
if (!aout)
return NULL;
SDL_Aout_Opaque *opaque = aout->opaque;
opaque->jvm = jvm;
opaque->wakeup = SDL_CreateCond();
aout->free_l = aout_free_l;
aout->open_audio = aout_open_audio;
aout->play_audio = aout_play_audio;
aout->pause_audio = aout_pause_audio;
aout->close_audio = aout_close_audio;
......
......@@ -27,6 +27,7 @@
#include <jni.h>
#include "ijksdl_aout.h"
SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack(JNIEnv *env);
void SDL_Init_AoutAndroid(JNIEnv *env);
SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack(JavaVM* jvm);
#endif
......@@ -27,4 +27,8 @@
#include "loghelp.h"
#include "jnihelp.h"
#ifndef IJKMAX
#define IJKMAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册