- 浏览: 229159 次
- 性别:
- 来自: 北京
最新评论
-
qq452739204:
如果构造的报文大于mtu值,是否需要分片之后再发送出去列?
Linux内核构造数据包并发送(二)(dev_queue_xmit方式) -
xingzengmou:
你好,我搞的原理跟你差不多,但播放的时候有papapa的声音, ...
AudioRecord和AudioTrack类的使用 -
wenjiefeng:
楼主,你有录制pcm格式和播放pcm格式的录音器的demo吗, ...
AudioRecord和AudioTrack类的使用 -
lovepeakingA:
...
AudioRecord和AudioTrack类的使用 -
ZaneLee007:
假的,不学无术
Android禁用键盘的所有按键
AudioRecord和AudioTrack类是Android获取和播放音频流的重要类,放置在android.media包中。与该包中的MediaRecorder和MediaPlayer类不同,AudioRecord和AudioTrack类在获取和播放音频数据流时无需通过文件保存和文件读取,可以动态地直接获取和播放音频流,在实时处理音频数据流时非常有用。
当然,如果用户只想录音后写入文件或从文件中取得音频流进行播放,那么直接使用MediaRecorder和MediaPlayer类是首选方案,因为这两个类使用非常方便,而且成功率很高。而AudioRecord和AudioTrack类的使用却比较复杂,我们发现很多人都不能成功地使用这两个类,甚至认为Android的这两个类是不能工作的。
其实,AudioRecord和AudioTrack类的使用虽然比较复杂,但是可以工作,我们不仅可以很好地使用了这两个类,而且还通过套接字(Socket)实现了音频数据的网络传输,做到了一端使用AudioRecord获取音频流然后通过套接字传输出去,而另一端通过套接字接收后使用AudioTrack类播放。
下面是我们对AudioRecord和AudioTrack类在使用方面的经验总结:
(1)创建AudioRecord和AudioTrack类对象:创建这两个类的对象比较复杂,通过对文档的反复和仔细理解,并通过多次失败的尝试,并在北理工的某个Android大牛的网上的文章启发下,我们也最终成功地创建了这两个类的对象。创建AudioRecord和AudioTrack类对象的代码如下:
AudioRecord类:
m_in_buf_size =AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,
8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
m_in_buf_size) ;
AudioTrack类:
m_out_buf_size = android.media.AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
m_out_buf_size,
AudioTrack.MODE_STREAM);
(2)关于AudioRecord和AudioTrack类的监听函数,不用也行。
(3)调试方面,包括初始化后看logcat信息,以确定类的工作状态,初始化是否成功等。
编写好代码,没有语法错误,调用模拟器运行、调试代码时,logcat发挥了很好的功用。刚调试时,经常会出现模拟器显示出现异常,这时我们可以在代码的一些关键语句后添加如Log.d("test1","OK");这样的语句进行标识,出现异常时我们就可以在logcat窗口观察代码执行到哪里出现异常,然后进行相应的修改、调试。模拟器不会出现异常时,又遇到了录放音的问题。录音方面,刚开始选择将语音编码数据存放在多个固定大小的文件中进行传送,但是这种情况下会出现声音断续的现象,而且要反复的建立文件,比较麻烦,后来想到要进行网上传输,直接将语音编码数据以数据流的形式传送,经过验证,这种方法可行并且使代码更加简洁。放音方面,将接收到的数据流存放在一个数组中,然后将数组中数据写到AudioTrack中。刚开始只是“嘟”几声,经过检查发现只是把数据写一次,加入循环,让数据反复写到AudioTrack中,就可以听到正常的语音了。接下来的工作主要是改善话音质量与话音延迟,在进行通话的过程中,观察logcat窗口,发现向数组中写数据时会出现Bufferflow的情况,于是把重心转移到数组大小的影响上,经过试验,发现 AudioRecord一次会读640个数据,然后就对录音和放音中有数组的地方进行实验修改。AudioRecord和AudioTrack进行实例化时,参数中各有一个数组大小,经过试验这个数组大小和AudioRecord和AudioTrack能正常实例化所需的最小Buffer大小(即上面实例化时的m_in_buf_size和m_out_buf_size参数)相等且服务器方进行缓存数据的数组尺寸是上述数值的2倍时,语音质量最好。由于录音和放音的速度不一致,受到北理工大牛的启发,在录音方面,将存放录音数据的数组放到LinkedList中,当LinkedList中数组个数达到2(这个也是经过试验验证话音质量最好时的数据)时,将先录好的数组中数据传送出去。经过上述反复试验和修改,最终使双方通话质量较好,且延时较短(大概有2秒钟)。
(4)通过套接字传输和接收数据
数据传送部分,使用的是套接字。通信双方,通过不同的端口向服务器发送请求,与服务器连接上后,开始通话向服务器发送数据,服务器通过一个套接字接收到一方的数据后,先存在一个数组中,然后将该数组中数据以数据流的形式再通过另一个套接字传送到另一方。这样就实现了双方数据的传送。
(5)代码架构
为避免反复录入和读取数据占用较多资源,使程序在进行录放音时不能执行其他命令,故将录音和放音各写成一个线程类,然后在主程序中,通过MENU控制通话的开始、停止、结束。
最后说明,AudioRecord和AudioTrack类可以用,只是稍微复杂些。以下贴出双方通信的源码,希望对大家有所帮助:
主程序Daudioclient:
package cn.Daudioclient;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class Daudioclient extends Activity {
public static final int MENU_START_ID = Menu.FIRST ;
public static final int MENU_STOP_ID = Menu.FIRST + 1 ;
public static final int MENU_EXIT_ID = Menu.FIRST + 2 ;
protected Saudioserver m_player ;
protected Saudioclient m_recorder ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public boolean onCreateOptionsMenu(Menu aMenu)
{
boolean res = super.onCreateOptionsMenu(aMenu) ;
aMenu.add(0, MENU_START_ID, 0, "START") ;
aMenu.add(0, MENU_STOP_ID, 0, "STOP") ;
aMenu.add(0, MENU_EXIT_ID, 0, "EXIT") ;
return res ;
}
public boolean onOptionsItemSelected(MenuItem aMenuItem)
{
switch (aMenuItem.getItemId()) {
case MENU_START_ID:
{
m_player = new Saudioserver() ;
m_recorder = new Saudioclient() ;
m_player.init() ;
m_recorder.init() ;
m_recorder.start() ;
m_player.start() ;
}
break ;
case MENU_STOP_ID:
{
m_recorder.free() ;
m_player.free() ;
m_player = null ;
m_recorder = null ;
}
break ;
case MENU_EXIT_ID:
{
int pid = android.os.Process.myPid() ;
android.os.Process.killProcess(pid) ;
}
break ;
default:
break ;
}
return super.onOptionsItemSelected(aMenuItem);
}
}
录音程序Saudioclient:
package cn.Daudioclient;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;
public class Saudioclient extends Thread
{
protected AudioRecord m_in_rec ;
protected int m_in_buf_size ;
protected byte [] m_in_bytes ;
protected boolean m_keep_running ;
protected Socket s;
protected DataOutputStream dout;
protected LinkedList<byte[]> m_in_q ;
public void run()
{
try
{
byte [] bytes_pkg ;
m_in_rec.startRecording() ;
while(m_keep_running)
{
m_in_rec.read(m_in_bytes, 0, m_in_buf_size) ;
bytes_pkg = m_in_bytes.clone() ;
if(m_in_q.size() >= 2)
{
dout.write(m_in_q.removeFirst() , 0, m_in_q.removeFirst() .length);
}
m_in_q.add(bytes_pkg) ;
}
m_in_rec.stop() ;
m_in_rec = null ;
m_in_bytes = null ;
dout.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void init()
{
m_in_buf_size = AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,
8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
m_in_buf_size) ;
m_in_bytes = new byte [m_in_buf_size] ;
m_keep_running = true ;
m_in_q=new LinkedList<byte[]>();
try
{
s=new Socket("192.168.1.100",4332);
dout=new DataOutputStream(s.getOutputStream());
//new Thread(R1).start();
}
catch (UnknownHostException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void free()
{
m_keep_running = false ;
try {
Thread.sleep(1000) ;
} catch(Exception e) {
Log.d("sleep exceptions...\n","") ;
}
}
}
放音程序Saudioserver:
package cn.Daudioclient;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
public class Saudioserver extends Thread
{
protected AudioTrack m_out_trk ;
protected int m_out_buf_size ;
protected byte [] m_out_bytes ;
protected boolean m_keep_running ;
private Socket s;
private DataInputStream din;
public void init()
{
try
{
s=new Socket("192.168.1.100",4331);
din=new DataInputStream(s.getInputStream());
m_keep_running = true ;
m_out_buf_size = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
m_out_buf_size,
AudioTrack.MODE_STREAM);
m_out_bytes=new byte[m_out_buf_size];
// new Thread(R1).start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void free()
{
m_keep_running = false ;
try {
Thread.sleep(1000) ;
} catch(Exception e) {
Log.d("sleep exceptions...\n","") ;
}
}
public void run()
{
byte [] bytes_pkg = null ;
m_out_trk.play() ;
while(m_keep_running) {
try
{
din.read(m_out_bytes);
bytes_pkg = m_out_bytes.clone() ;
m_out_trk.write(bytes_pkg, 0, bytes_pkg.length) ;
}
catch(Exception e)
{
e.printStackTrace();
}
}
m_out_trk.stop() ;
m_out_trk = null ;
try {
din.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
评论
发表评论
-
从assets文件夹中读取txt文件
2010-08-23 14:37 2658Android除了提供/res目录存放资源文件外,在/asse ... -
AndroidManifest.xml文件综合详解
2010-08-18 09:59 1067一,重要性AndroidManifest. ... -
总结Content Provider的使用
2010-08-18 09:47 1704Android中的Content provider机制可支持在 ... -
Android动态创建一个个组件
2010-08-12 00:11 2942Android 界面编程有两种基本的方法,一种是在代码中,动态 ... -
LinearLayout+EditText+Button+AlertDialog简单应用
2010-08-11 22:08 2266这个简单的例子是EditText中默认有个字符串text,单击 ... -
android实现底部菜单栏
2010-08-11 20:43 1742android程序,许多时候需要菜单栏显示在底部或顶部,但是没 ... -
Android permission 访问权限大全
2010-08-11 20:41 1011androidmanifest.xml中声明相关权限请求, 完 ... -
Android的几种布局方式
2010-08-11 20:27 4960通常我们开发的应用程序都是需要具有友好的用户界面,那么Andr ... -
Android的系统架构
2010-08-11 20:10 1564Android的系统架构是怎么样的呢?从下图我们可以从整体上有 ... -
Android响应按钮的程序结构
2010-08-11 20:07 1944图形界面的按钮是最普通的控件,Android响应按钮的程序结构 ... -
Android资源文件
2010-08-10 10:34 1363资源是您在代码中使用 ... -
SMS Messaging in Android(接1)
2010-08-09 00:12 1090就是它了!测试应用程序,按下F11。为每个Android模拟器 ... -
SMS Messaging in Android(1)
2010-08-08 23:54 1764可以安全的说,在过去的近20年里卖的每一款移动电话都拥有SMS ... -
Android sms 发送、接收及格式
2010-08-08 21:49 2195一、 android sms所要的权限 Java代码 ... -
Android Button按钮控件美化方法
2010-08-08 21:11 2810对于Android自带的Button按钮控件很多网友感觉不是很 ... -
Android布局之AbsoluteLayout
2010-08-08 18:34 1836AbsoluteLayout也就是绝对布局,又称坐标布局,在布 ... -
Android移植: wifi设计原理(源码分析)
2010-08-08 02:22 2344初始化在 SystemServer 启动的时候,会生成一个 ... -
Android禁用键盘的所有按键
2010-08-07 23:52 4257KeyguardManager keyguardManager ...
相关推荐
`AudioRecord`和`AudioTrack`是Android SDK提供的一对关键类,分别用于录音和播放音频数据。这两个类允许开发者进行低级别的音频操作,实现更加灵活和高效的声音处理。接下来,我们将深入探讨如何使用`AudioRecord`...
在Android平台上,AudioRecord和AudioTrack是两个非常重要的音频处理类,它们分别用于音频的录制和播放。在本文中,我们将深入探讨这两个类的工作原理、使用方法以及如何结合它们实现一个简单的音频处理流程。 首先...
RecordDemo这个文件名可能是指一个示例项目,它可能包含了使用AudioRecord进行录音和AudioTrack进行播放的完整代码。在实际开发中,开发者通常会结合这两个类,构建一个完整的录音和回放功能。例如,用户触发录音...
在`AudioRecordPlay`这个项目中,可能包含了实现这种同步机制的代码示例,以及如何设置和使用AudioRecord和AudioTrack的详细步骤。通过学习和分析这个项目,开发者可以更好地理解和掌握Android音频处理的核心技术,...
Android 使用 AudioRecord 和 AudioTrack 完成音频PCM数据的采集和播放,并读写音频wav文件。 封装好的Java代码,可同时录制PCM和WAV文件。自己定义存储位置。 Android提供了AudioRecord和MediaRecord。MediaRecord...
AudioRecord和AudioTrack是Android SDK提供的两个核心类,分别用于音频输入和输出。本示例程序旨在帮助开发者深入理解这两个类的用法,以便在自己的应用中实现高质量的音频功能。 AudioRecord类是用于从设备麦克风...
本文将深入探讨如何使用`AudioRecord`和`AudioTrack`这两个核心类来实现语音录音和播放功能。 `AudioRecord`是Android SDK提供的一种用于录制音频的API,它允许开发者从设备的麦克风捕获声音数据。这个类提供了多种...
在Android平台上,开发声音相关的应用时,我们经常会用到`AudioRecord`和`AudioTrack`这两个核心类。它们是Android SDK提供的一对音频输入和输出API,分别用于录音和播放。下面将详细介绍这两个类的工作原理以及如何...
在给定的压缩包文件“andless”中,很可能包含了一个示例项目或库,用于展示如何在JNI层使用`AudioTrack`和`AudioRecord`。这个项目可能包含了以下部分: 1. **Java层代码**:定义了JNI接口,供C++层调用。通常会有...
android AudioRecord AudioTrack实现录音并播放 并支持参数选择(频率、编码格式、声道) 更多信息可参考http://blog.sina.com.cn/u/1788464665
AudioRecord和AudioTrack是Android SDK提供的两个核心类,分别用于音频录制和播放。本篇文章将详细解析如何利用这两个类在Android中实现一个完整的录音和播放功能的Demo。 首先,我们来了解AudioRecord。Audio...
这个程序的核心技术涉及到了`AudioRecord`和`AudioTrack`这两个关键组件,以及无线局域网(WiFi)通信。以下是对这些知识点的详细解释: 1. **AudioRecord**: `AudioRecord`是Android提供的一个类,用于录制音频...
在这个项目中,“利用AudioRecord录制音频并播放”,我们将会探讨如何使用AudioRecord实现录音功能,以及如何配合MediaPlayer或AudioTrack类来播放录制的音频。 1. **AudioRecord的基本概念** AudioRecord类允许...
这个"AudioRecord.zip"项目显然是一个关于使用`AudioRecord`进行音频录制和播放的实践示例,具有高度的灵活性,可以调整采样率和文件格式。 1. **AudioRecord类的使用**:`AudioRecord`是Android系统中用于音频输入...
这个"Android AudioRecord Demo.zip"文件很可能包含了演示如何使用AudioRecord类的一个示例项目。让我们深入了解一下Android AudioRecord类以及如何创建一个录音应用。 1. **AudioRecord类介绍** - AudioRecord是...
本文将深入探讨如何使用Android的`AudioRecord`类进行录音,并利用`MediaPlayer`或`AudioTrack`进行播放。`AudioRecord`是Android SDK中的一个关键组件,它允许开发者捕获原始音频数据,而`MediaPlayer`则用于播放...
在使用AudioRecord之前,我们需要设置音频源(如麦克风)、音频格式(如PCM 16位)和缓冲区大小。初始化AudioRecord时,需要调用`new AudioRecord()`,传入这些参数。例如: ```java int sampleRate = 44100; // ...
如果你的应用需要实时处理音频或进行流媒体传输,可以考虑使用AudioTrack类配合AudioRecord,实现双向通信或者在线直播功能。 这份源码可能包含了一个简单的Android应用,展示了如何使用AudioRecord进行录音操作,...
在本文中,我们使用 AudioRecord 和 AudioTrack 两个工具,实现了一个简单的助听器程序。该程序可以读取麦克风的音频流,并将其播放出来,同时允许用户对音频音量进行调节。该程序可以广泛应用于音频处理和播放领域...
计算机网络期末复习Android使用AudioRecord录制PCM音频原始数据,并使用AudioTrack播放.zipAndroid使用AudioRecord录制PCM音频原始数据,并使用AudioTrack播放.zip