问题
I want to play an audio file in .wav format using AudioTrack and C++. I have searched for it a lot but I couldn't find any relevant tutorial.
The only I could find, were all using Java/JNI layer. I want to do it at the native level in C++.
Something like :
file = path_to_file
play(file)
Please point me to some good tutorial if you are aware of or please provide me some code snippets to get the idea.
回答1:
Your Native Code (NativeCode.cpp) should look like below: *Include required header files and libs.
JavaVM *gJavaVM = NULL;
static jobject gCallbackObject = NULL;
jmethodID audio_dataCb_methodid = 0;
static pthread_t ThreadAudio = NULL;
struct pthread_args_structs {
int buf_size;
};
void *nativeAudioData(void *args) {
struct pthread_args_structs *pargs = (pthread_args_structs *) args;
int status;
JNIEnv *env;
status = gJavaVM_->AttachCurrentThread(&env, NULL);
FILE *fp = fopen("/sdcard/sample.wav", "rb");
if (fp == NULL) {
LOGE("file open failed!");
return NULL;
}
int numReadBytes = pargs->buf_size;
jbyteArray data = env->NewByteArray(numReadBytes);
char buf[numReadBytes] = {0};
int res = 0;
jboolean EOFA = JNI_FALSE;
while (!EOFA) {
res = fread(buf, 1, numReadBytes, fp);
if (res > 0) {
env->SetByteArrayRegion(data, 0, res, (jbyte *) buf);
jint ret = env->CallIntMethod(gCallbackObject, audio_dataCb_methodid, data);
if (ret < 0) {
LOGV("callback failed from jni");
break;
}
}
else {
break;
}
usleep(33 * 1000);
}
fclose(fp);
env->DeleteLocalRef(data);
gJavaVM->DetachCurrentThread();
pthread_exit(NULL);
free(args);
ThreadAudio = NULL;
return NULL;
}
JNIEXPORT jint JNICALL
Java_com_app_example_NativeCode_AudioStreaming(JNIEnv *env, jobject instance, jint buf_size) {
struct pthread_args_structs *args = (struct pthread_args_structs *) malloc(
sizeof(struct pthread_args_structs));
args->buf_size = buf_size;
jint rs = env->GetJavaVM(&gJavaVM);
gCallbackObject = env->NewGlobalRef(instance);
jclass javaInterfaceClass = env->FindClass("com/app/example/NativeCode");
audio_dataCb_methodid = env->GetMethodID(javaInterfaceClass, "AudioDataCb",
"([B)I");
if (pthread_create(&ThreadAudio, NULL, &nativeAudioData, (void *) args) != 0) {
LOGE("Error: Uh-oh! JNI Thread Creation Failed \n");
return -1;
}
LOGV("ThreadAudio running...");
return 0;
}
Your Java Code should look like below snippet: Call to start the native audio streaming:
int bufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
mAudioTrack.play();
pcmAudioStreaming(bufferSize);
And Callback Implementation:
AudioTrack mAudioTrack;
public int nativeAudioData(byte[] buffer) {
Log.v(TAG, "nativeAudioData() data len: " +buffer.length);
mAudioTrack.write(buffer, 0, buffer.length);
return 0;
}
来源:https://stackoverflow.com/questions/32323516/playing-audio-wav-file-in-android-natively-using-audiotrack-and-c