/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioRecord-JNI"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "utils/Log.h"
#include "media/AudioRecord.h"
#include "media/mediarecorder.h"
// ----------------------------------------------------------------------------
using namespace android;
// ----------------------------------------------------------------------------
static const char* const kClassPathName = "android/media/AudioRecord";
struct fields_t {
// these fields provide access from C++ to the...
jclass audioRecordClass; //... AudioRecord class
jmethodID postNativeEventInJava; //... event post callback method
int PCM16; //... format constants
int PCM8; //... format constants
jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
};
static fields_t javaAudioRecordFields;
struct audiorecord_callback_cookie {
jclass audioRecord_class;
jobject audioRecord_ref;
};
Mutex sLock;
// ----------------------------------------------------------------------------
#define AUDIORECORD_SUCCESS 0
#define AUDIORECORD_ERROR -1
#define AUDIORECORD_ERROR_BAD_VALUE -2
#define AUDIORECORD_ERROR_INVALID_OPERATION -3
#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
jint android_media_translateRecorderErrorCode(int code) {
switch(code) {
case NO_ERROR:
return AUDIORECORD_SUCCESS;
case BAD_VALUE:
return AUDIORECORD_ERROR_BAD_VALUE;
case INVALID_OPERATION:
return AUDIORECORD_ERROR_INVALID_OPERATION;
default:
return AUDIORECORD_ERROR;
}
}
// ----------------------------------------------------------------------------
static void recorderCallback(int event, void* user, void *info) {
if (event == AudioRecord::EVENT_MORE_DATA) {
// set size to 0 to signal we're not using the callback to read more data
AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
pBuff->size = 0;
} else if (event == AudioRecord::EVENT_MARKER) {
audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
callbackInfo->audioRecord_class,
javaAudioRecordFields.postNativeEventInJava,
callbackInfo->audioRecord_ref, event, 0,0, NULL);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
} else if (event == AudioRecord::EVENT_NEW_POS) {
audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
callbackInfo->audioRecord_class,
javaAudioRecordFields.postNativeEventInJava,
callbackInfo->audioRecord_ref, event, 0,0, NULL);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
}
}
// ----------------------------------------------------------------------------
static int
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jint source, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes)
{
//LOGV(">> Entering android_media_AudioRecord_setup");
//LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
// sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
if (!AudioSystem::isInputChannel(channels)) {
LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
uint32_t nbChannels = AudioSystem::popCount(channels);
// compare the format against the Java constants
if ((audioFormat != javaAudioRecordFields.PCM16)
&& (audioFormat != javaAudioRecordFields.PCM8)) {
LOGE("Error creating AudioRecord: unsupported audio format.");
return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
}
int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1;
int format = audioFormat==javaAudioRecordFields.PCM16 ?
AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
if (buffSizeInBytes == 0) {
LOGE("Error creating AudioRecord: frameCount is 0.");
return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
}
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
if (source >= AUDIO_SOURCE_LIST_END) {
LOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
audiorecord_callback_cookie *lpCallbackData = NULL;
AudioRecord* lpRecorder = NULL;
// create an uninitialized AudioRecord object
lpRecorder = new AudioRecord();
if(lpRecorder == NULL) {
LOGE("Error creating AudioRecord instance.");
return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
// create the callback information:
// this data will be passed with every AudioRecord callback
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
LOGE("Can't find %s when setting up callback.", kClassPathName);
goto native_track_failure;
}
lpCallbackData = new audiorecord_callback_cookie;
lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
lpRecorder->set(source,
sampleRateInHertz,
format, // word length, PCM
channels,
frameCount,
0, // flags
recorderCallback,// callback_t
lpCallbackData,// void* user
0, // notificationFrames,
true); // threadCanCallJava)
if(lpRecorder->initCheck() != NO_ERROR) {
LOGE("Error creating AudioRecord instance: initialization check failed.");
goto native_init_failure;
}
// save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
// of the Java object
env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder);
// save our newly created callback information in the "nativeCallbackCookie" field
// of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, (int)lpCallbackData);
return AUDIORECORD_SUCCESS;
// failure:
native_init_failure:
env->DeleteGlobalRef(lpCallbackDat
android_media_AudioRecord.rar_android_audiorecord
版权申诉
63 浏览量
2022-09-19
20:28:18
上传
评论
收藏 5KB RAR 举报
JaniceLu
- 粉丝: 78
- 资源: 1万+
最新资源
- MyBatis动态SQL是一种强大的特性,它允许我们在SQL语句中根据条件动态地添加或删除某些部分,从而实现更加灵活和高效的数据
- MyBatis动态SQL是一种强大的特性,它允许我们在SQL语句中根据条件动态地添加或删除某些部分,从而实现更加灵活和高效的数据
- MyBatis动态SQL是一种强大的特性,它允许我们在SQL语句中根据条件动态地添加或删除某些部分,从而实现更加灵活和高效的数据
- Docker在Ubuntu16.04上安装和部署Apache Storm
- test_kong.zip
- springboot权限验证学习-下
- SeetaFace6人脸质量评估C++代码实现Demo
- OCAuxiliaryTools
- 制药公司QC顶岗实习专题报告
- Rust 全面指南:从基础到高级,一网打尽 Rust 的编程知识
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈