2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > java 双声道音频_一种多声道录音的实现方法(语音识别功能)

java 双声道音频_一种多声道录音的实现方法(语音识别功能)

时间:2024-05-19 12:11:34

相关推荐

java 双声道音频_一种多声道录音的实现方法(语音识别功能)

前段时间,在firefly3399开发板上实现了基于思必驰的语音识别功能。关于这个开发板的资料请查看官方网站http://www.t-/product/rk3399.html。

使用的是思必驰的多麦技术,6声道的音频(4个mic+2个回升参考音)直接进主控rk3399。讯飞也有专门的6麦克风阵列模块做语音处理直接出2声道音频给主控音频。我使用的这种多声道直接进主控的方式能够进一步省成本。

下面分享在android下如何获取多声道的音频数据。其实很简单,alsa本身已经支持多声道的录音了,android的tinycap也已经支持,我把tinycap封装成jni接口,应用程序使用我这个jni接口就直接能进行多声道录音了。

/* tinycap.c

**

** Copyright , The Android Open Source Project

**

** Redistribution and use in source and binary forms, with or without

** modification, are permitted provided that the following conditions are met:

** * Redistributions of source code must retain the above copyright

** notice, this list of conditions and the following disclaimer.

** * Redistributions in binary form must reproduce the above copyright

** notice, this list of conditions and the following disclaimer in the

** documentation and/or other materials provided with the distribution.

** * Neither the name of The Android Open Source Project nor the names of

** its contributors may be used to endorse or promote products derived

** from this software without specific prior written permission.

**

** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND

** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE

** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH

** DAMAGE.

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define LOGD(...) \

__android_log_print(ANDROID_LOG_DEBUG, "AudioHubNative", __VA_ARGS__)

#define UNUSED __attribute__((unused))

#ifndef false

#define false 0

#define true 1

#endif

static JavaVM* java_vm = NULL;

static jclass com_andorid_audiohub_AudioCapture = NULL;

static jmethodID com_andorid_audiohub_AudioCapture_read;

int capturing = 1;

static void volume_process(const void *buffer, size_t length, float volume, unsigned int channels) {

short * buffer_end = (short*)buffer + (length/2);

short * pcmData = (short *)buffer;

unsigned int i = 1;

while (pcmData < buffer_end) {

if(i >= channels-1){

*pcmData = (short)((float)*pcmData * 0.6);

}

else

*pcmData = (short)((float)*pcmData * volume);

if(*pcmData > 32767)

*pcmData = 32767;

++pcmData;

if(i == channels){

i = 1;

}else{

i++;

}

}

}

unsigned int do_capture(unsigned int card, unsigned int device,

unsigned int channels, unsigned int rate,

enum pcm_format format, unsigned int period_size,

unsigned int period_count)

{

struct pcm_config config;

struct pcm *pcm;

char *buffer;

unsigned int size;

unsigned int bytes_read = 0;

memset(&config, 0, sizeof(config));

config.channels = channels;

config.rate = rate;

config.period_size = period_size;

config.period_count = period_count;

config.format = format;

config.start_threshold = 0;

config.stop_threshold = 0;

config.silence_threshold = 0;

pcm = pcm_open(card, device, PCM_IN, &config);

if (!pcm || !pcm_is_ready(pcm)) {

fprintf(stderr, "Unable to open PCM device (%s)\n",

pcm_get_error(pcm));

return 0;

}

size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));

buffer = malloc(size);

if (!buffer) {

fprintf(stderr, "Unable to allocate %d bytes\n", size);

free(buffer);

pcm_close(pcm);

return 0;

}

LOGD("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,

pcm_format_to_bits(format));

JNIEnv * env;

void * void_env;

bool had_to_attach = false;

jint status = (*java_vm)->GetEnv(java_vm, &void_env, JNI_VERSION_1_6);

if (status == JNI_EDETACHED) {

(*java_vm)->AttachCurrentThread(java_vm, &env, NULL);

had_to_attach = true;

} else {

env = void_env;

}

jbyteArray audioByteArray = (*env)->NewByteArray(env, size);

capturing = 1;

while (capturing && !pcm_read(pcm, buffer, size)) {

volume_process(buffer, size, 4.0, channels);

// Call write()

(*env)->SetByteArrayRegion(env, audioByteArray, 0, size, (jbyte *)buffer);

(*env)->CallStaticVoidMethod(env, com_andorid_audiohub_AudioCapture,

com_andorid_audiohub_AudioCapture_read, audioByteArray);

bytes_read += size;

}

(*env)->DeleteLocalRef(env, audioByteArray);

if (had_to_attach) {

(*java_vm)->DetachCurrentThread(java_vm);

}

free(buffer);

pcm_close(pcm);

return pcm_bytes_to_frames(pcm, bytes_read);

}

static void* read_thread()

{

do_capture(0, 0, 6, 16000, PCM_FORMAT_S16_LE, 512, 6);

return NULL;

}

JNIEXPORT jint JNICALL

JNI_OnLoad(JavaVM* vm, void* reserved UNUSED)

{

LOGD("libAudioHub: loaded");

java_vm = vm;

return JNI_VERSION_1_6;

}

JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved UNUSED)

{

JNIEnv * env;

void * void_env;

(*java_vm)->GetEnv(vm, &void_env, JNI_VERSION_1_6);

env = void_env;

(*env)->DeleteGlobalRef(env, com_andorid_audiohub_AudioCapture);

LOGD("libAudioHub: unloaded");

}

JNIEXPORT jboolean JNICALL

Java_com_android_audiohub_AudioHub_setup(JNIEnv* env UNUSED, jobject foo UNUSED)

{

// Get write callback handle

jclass clazz = (*env)->FindClass(env, "com/android/audiohub/AudioCapture");

if (!clazz) {

LOGD("Could not find AudioCapture");

return false;

}

com_andorid_audiohub_AudioCapture = (*env)->NewGlobalRef(env, clazz);

com_andorid_audiohub_AudioCapture_read = (*env)->GetStaticMethodID(env,

com_andorid_audiohub_AudioCapture, "read", "([B)V");

if (!com_andorid_audiohub_AudioCapture_read) {

LOGD("Could not find com.android.audiohub.AudioCapture");

(*env)->DeleteGlobalRef(env, com_andorid_audiohub_AudioCapture);

return false;

}

// Good to go

LOGD("Starting capture");

int ret;

pthread_t id;

pthread_attr_t attr;

pthread_attr_init (&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&id, &attr, read_thread, NULL);

return true;

}

JNIEXPORT void JNICALL

Java_com_android_audiohub_AudioHub_close(JNIEnv* env UNUSED, jobject foo UNUSED) {

capturing = 0;

}

上面的jni使用在android平台都是通用的,具体到不同的开发板只要修改不同的参数即可。

对于firefly3399的开发板,i2s0可支持最多8声道录音。我直接利用了hdmi这张声卡,这样少写代码。

diff --git a/kernel/sound/soc/codecs/hdmi-codec.c b/kernel/sound/soc/codecs/hdmi-code

old mode 100644

new mode 100755

index ad750f4..8dc0857

--- a/kernel/sound/soc/codecs/hdmi-codec.c

+++ b/kernel/sound/soc/codecs/hdmi-codec.c

@@ -302,7 +302,7 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {

};

-#define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\

+#define HDMI_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE

SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\

SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\

SNDRV_PCM_RATE_192000)

@@ -337,7 +337,14 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {

.formats = I2S_FORMATS,

.sig_bits = 24,

},

- .ops = &hdmi_dai_ops,

+ .capture = {

+ .stream_name = "Capture",

+ .channels_min = 1,

+ .channels_max = 8,

+ .rates = SNDRV_PCM_RATE_8000_192000,

+ .formats = I2S_FORMATS,

+ },

+// .ops = &hdmi_dai_ops,

};

diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-core.dtsi b/kernel/ar

old mode 100644

new mode 100755

index 39f2be7..f621794

--- a/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-core.dtsi

+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-core.dtsi

@@ -109,7 +109,7 @@

simple-audio-card,name = "rockchip,hdmi";

simple-audio-card,cpu {

- sound-dai = ;

+ sound-dai = ;

};

simple-audio-card,codec {

sound-dai = ;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。