当前位置: 移动技术网 > 移动技术>移动开发>Android > Android音频可视化开发案例说明

Android音频可视化开发案例说明

2019年07月24日  | 移动技术网移动技术  | 我要评论
android 调用自带的录制音频程序
android中有自带的音频录制程序,我们可以通过指定一个action mediastore.audio.media.record_sound_action的intent来
启动它就可以了。然后在onactivityresult()方法中,获取intent的data,就是录制的音频对应的uri。
java代码:
复制代码 代码如下:

package eoe.demo;
import android.app.activity;
import android.content.intent;
import android.net.uri;
import android.os.bundle;
import android.provider.mediastore;
import android.view.view;
import android.widget.toast;
/**
* 被实例演示如何调用android自带的应用来完成audio的录入
* 其实很简单,我们需要指定一个mediastore.audio.media.record_sound_action的action来启动就可以
* 返回的data数据就是我们录制的音频的uri了
*
* 通过上面这种方式,灵活性不够高,我们可以利用mediarecorder类来实现自己的音频录制程序
* mediarecorder既可以用来录制音频,也可以用来录制视频
* 创建了一个mediarecorder实例后,需要调用setaudiosource和setaudioencoder来初始化
* 通常情况下,在准备录制前,我们还需要调用setoutputformat()方法来决定使用的音频格式,同时调用
* setoutputfile()来指定存放录制内容的文件
*
* 这几个方法的调用顺序是:setaudiosource,setoutputformat,setaudioencoder,setoutputfile
*
*
*
* @author administrator
*
*/
public class audiorecorddemo extends activity {
public void oncreate(bundle savedinstancestate){
super.oncreate(savedinstancestate);
setcontentview(r.layout.audio_record);
}
public void onactivityresult(int requestcode, int resultcode, intent data){
//super.onactivityresult(requestcode, resultcode, data);
//这里我们就可以获取到刚刚录制的音频的uri,可以进行播放等操作,这里显示返回的uri
if(resultcode == result_ok){
uri audiopath = data.getdata();
toast.maketext(this, audiopath.tostring(), toast.length_long).show();
}
}
public void onclick(view v){
int id = v.getid();
switch(id){
case r.id.btn1: //调用android自带的音频录制应用
intent intent = new intent(mediastore.audio.media.record_sound_action);
startactivityforresult(intent, 0);
break;
case r.id.btn2:
//通过mediarecorder类来实现自己的音频录制程序
intent intent2 = new intent();
intent2.setclass(this, myaudiorecord.class);
startactivityforresult(intent2, 1);
break;
case r.id.btn3:
//通过audiorecord类实现自己的音频录制程序
intent intent3 = new intent();
intent3.setclass(this, myaudiorecord2.class);
startactivityforresult(intent3, 2);
break;
}
}
}

android 音频的介绍
最近移植android,当android能够在设备上面运行之后,首先想到的是让音频设备跑起来。“没有声音,再好的戏也出不来”。本文简单介绍一下android音频适配层。
这个世界音频设备千变万化,android也不可能为每种设备都提供支持。android定义了一个框架,这个框架来适配底层的音频设备。该适配层的定义位于:
java代码:
复制代码 代码如下:

hardware/libhardware_legacy/include/hardware_legacy/audiohardwareinterface.h

要想视频底层的音频设备必须要继承该文件中定义的audiostreamout,audiostreamin,audiohardwareinterface等类,并实现createaudiohardware函数。
下面我们看一下android创建音频设备的代码,代码位于:
java代码:
复制代码 代码如下:

frameworks/base/libs/audioflinger/audiohardwareinterface.cpp

该文件有如下代码:
java代码:
复制代码 代码如下:

audiohardwareinterface* audiohardwareinterface::create()
{
/*
* fixme: this code needs to instantiate the correct audio device
* interface. for now - we use compile-time switches.
*/
audiohardwareinterface* hw = 0;
char value[property_value_max];
#ifdef generic_audio
hw = new audiohardwaregeneric();
#else
// 如果运行在仿真中——用这个模拟器
if (property_get("ro.kernel.qemu", value, 0)) {
logd("running in emulation - using generic audio driver");
hw = new audiohardwaregeneric();
}
else {
logv("creating vendor specific audiohardware");
hw = createaudiohardware();
}
#endif
if (hw->initcheck() != no_error) {
logw("using stubbed audio hardware. no sound will be produced.");
delete hw;
hw = new audiohardwarestub();
}
#ifdef with_a2dp
hw = new a2dpaudiointerface(hw);
#endif
#ifdef enable_audio_dump
recorded in the file.
logv("opening pcm dump interface");
hw = new audiodumpinterface(hw); // replace interface
#endif
return hw;
}

从代码中我们可以看出如果定义了generic_audio的宏,则会创建audiohardwaregeneric,如果是模拟器的话,audiohardwaregeneric会不能初始化,进而创建audiohardwarestub。这两个类都是audio设备的适配层,是android默认提供的。模拟器都是用audiohardwarestub,不会有声音输出。设备都是用audiohardwaregeneric,因为默认generic_audio是设置的。
一般我们只关心audiohardwaregeneric实现,谁会去给模拟器去调试声音呢,反正我没这个闲心。首先说明一下这个音频适配层是android自带的,可以保证你的音频设备正常运行,但是不能发挥设备的最佳性能。通过后面的描述你将会了解。audiohardwaregeneric的定义位于:
java代码:
复制代码 代码如下:

frameworks/base/libs/audioflinger/audiohardwaregeneric.cpp

上面就是eoe给我们介绍音频用途,如果有什么不明白的就多看看android的源码,这样有助与你对音频的理解。
先看一下效果图
 
复制代码 代码如下:

public class fftactivity extends activity implements onclicklistener{
private button button;
private imageview imageview;
private int frequency = 8000;
private int channelconfiguration = audioformat.channel_configuration_mono;
private int audioencoding = audioformat.encoding_pcm_16bit;
private realdoublefft transformer;
private int blocksize = 256;
private boolean started = false;
private canvas canvas;
private paint paint;
private bitmap bitmap;
@override
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.fft);
button = (button) findviewbyid(r.id.fft_button);
button.setonclicklistener(this);
imageview = (imageview) findviewbyid(r.id.fft_imageview);
transformer = new realdoublefft(blocksize);
bitmap = bitmap.createbitmap(256, 100, bitmap.config.argb_8888);
canvas = new canvas(bitmap);
paint = new paint();
paint.setcolor(color.green);
imageview.setimagebitmap(bitmap);
}
private class recordaudio extends asynctask<void, double[], void> {
@override
protected void doinbackground(void... params) {
int buffersize = audiorecord.getminbuffersize(frequency,
channelconfiguration, audioencoding);
audiorecord audiorecord = new audiorecord(
mediarecorder.audiosource.mic, frequency,
channelconfiguration, audioencoding, buffersize);
short[] buffer = new short[blocksize];
double[] totransform = new double[blocksize];
audiorecord.startrecording();
while (started) {
//将record的数据 读到buffer中,但是我认为叫做write可能会比较合适些。
int bufferresult = audiorecord.read(buffer, 0, blocksize);
for (int i = 0; i < bufferresult; i++) {
totransform<i> = (double) buffer<i> / short.max_value;
}
transformer.ft(totransform);
publishprogress(totransform);
}
audiorecord.stop();
return null;
}
@override
protected void onprogressupdate(double[]... values) {
super.onprogressupdate(values);
canvas.drawcolor(color.black);
for (int i = 0; i < values[0].length; i++) {
int x=i;
int downy=(int)(100-(values[0]<i>)*10);
int upy=100;
canvas.drawline(x, downy, x, upy, paint);
}
imageview.invalidate();
}
}
@override
public void onclick(view v) {
started=true;
new recordaudio().execute();
}
}

android音频可视化的原理是使用离散傅里叶变换,但是数学不好的同学不要担心,有开源的java离散傅里叶变换的代码!!直接到www.netlib.org/fftpack/jfftpack.tgz,直接将里面javasource目录拖动到(ca目录)src即可!!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网