Audio的系统结构

  摘要:Audio系统负责Android中的PCM数据的录制输入流和播放输出流的传输和控制,以及音频设备的管理和设置。这里主要介绍播放和录制环节在各个层次的内容,整个结构层次分明,包括了java接口层,JNI层,本地框架层,audio服务层,硬件抽象层等5层。它的结构图如下
图1-1 Audio系统结构                                                       图1-1 Audio系统结构

  一、java接口层

    AudioManager:音频管理对外的接口,提供了音量和ringtone模式的管理,由getSystemService(Context.AUDIO_SERVICE)返回。
    Audioservice:是一个非常重要的java层的系统服务,所有的用户发起的调用都是由它往底层转发的。
    AudioSystem:提供管理native接口,只时提供在media包的AudioService内部使用,不对用户直接提供接口。
    AudioTrack:提供用户从java层直接输出pcm数据的接口write函数,以及部分播放控制函数。
    AudioRecord:提供用户在java层直接从外部获取pcm数据的接口read函数。
    下面贴一段边录边播放的例子代码说明这些函数的使用

View Code
  1 package test.Record;  
  2   
  3 import java.io.BufferedInputStream;
  4 import java.io.File;
  5 import java.io.FileInputStream;
  6 import java.io.FileOutputStream;
  7 import java.io.InputStream;
  8 import java.io.OutputStream;
  9 
 10 import android.app.Activity;
 11 import android.content.Intent;
 12 import android.media.AudioFormat;
 13 import android.media.AudioManager;
 14 import android.media.AudioRecord;
 15 import android.media.AudioTrack;
 16 import android.media.MediaRecorder;
 17 import android.os.Bundle;
 18 import android.util.Log;
 19 import android.view.View;
 20 import android.widget.Button;
 21 import android.widget.SeekBar;
 22 import android.widget.Toast;
 23   
 24 public class testRecord extends Activity {  
 25     /** Called when the activity is first created. */  
 26     Button btnRecord, btnStop, btnExit;  
 27     SeekBar skbVolume;//调节音量  
 28     boolean isRecording = false;//是否录放的标记  
 29     static final int frequency = 44100;  
 30     static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
 31     static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
 32     int recBufSize,playBufSize;  
 33     AudioRecord audioRecord;  
 34     AudioTrack audioTrack;  
 35   
 36     @Override  
 37     public void onCreate(Bundle savedInstanceState) {  
 38         super.onCreate(savedInstanceState);  
 39         setContentView(R.layout.main);  
 40         setTitle("助听器");  
 41       
 42         //------------------------------------------  
 43         btnRecord = (Button) this.findViewById(R.id.btnRecord);  
 44         btnRecord.setOnClickListener(new ClickEvent());  
 45         btnStop = (Button) this.findViewById(R.id.btnStop);  
 46         btnStop.setOnClickListener(new ClickEvent());  
 47         btnExit = (Button) this.findViewById(R.id.btnExit);  
 48         btnExit.setOnClickListener(new ClickEvent());  
 49         skbVolume=(SeekBar)this.findViewById(R.id.skbVolume);  
 50         skbVolume.setMax(100);//音量调节的极限  
 51         skbVolume.setProgress(100);//设置seekbar的位置值  
 52         //audioTrack.setStereoVolume(1.0f, 1.0f);//设置当前音量大小  
 53         skbVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {  
 54               
 55               
 56             public void onStopTrackingTouch(SeekBar seekBar) {  
 57                 float vol=(float)(seekBar.getProgress())/(float)(seekBar.getMax());  
 58                 //audioTrack.setStereoVolume(vol, vol);//设置音量  
 59             }  
 60               
 61               
 62             public void onStartTrackingTouch(SeekBar seekBar) {  
 63                 // TODO Auto-generated method stub  
 64             }  
 65               
 66               
 67             public void onProgressChanged(SeekBar seekBar, int progress,  
 68                     boolean fromUser) {  
 69                 // TODO Auto-generated method stub  
 70             }  
 71         });  
 72     }  
 73   
 74     @Override  
 75     protected void onDestroy() {  
 76         super.onDestroy();  
 77         android.os.Process.killProcess(android.os.Process.myPid());  
 78     }  
 79   
 80     class ClickEvent implements View.OnClickListener {  
 81   
 82           
 83         public void onClick(View v) {  
 84             if (v == btnRecord) {                
 85                 if(!isRecording) {
 86                     isRecording = true; 
 87                     AudioManager audioManager = (AudioManager) getSystemService(getApplicationContext().AUDIO_SERVICE);
 88                     audioManager.setMode(AudioManager.MODE_NORMAL);
 89                 recBufSize = AudioRecord.getMinBufferSize(frequency,  
 90                             channelConfiguration, audioEncoding);
 91                     playBufSize=AudioTrack.getMinBufferSize(frequency,  
 92                             channelConfiguration, audioEncoding);
 93 
 94                     audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,  
 95                             channelConfiguration, audioEncoding, recBufSize);  
 96               
 97                     audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,  
 98                             channelConfiguration, audioEncoding,  
 99                             playBufSize, AudioTrack.MODE_STREAM);  
100                     
101                     new RecordPlayThread().start();// 开一条线程边录边放 
102                 }                
103             } else if (v == btnStop) {                
104                 if(isRecording) {
105                     isRecording = false;
106                     AudioManager audioManager = (AudioManager) getSystemService(getApplicationContext().AUDIO_SERVICE);
107                     audioManager.setMode(AudioManager.MODE_NORMAL);
108                 }                
109             } else if (v == btnExit) {
110                 isRecording = false; 
111                 AudioManager audioManager = (AudioManager) getSystemService(getApplicationContext().AUDIO_SERVICE);
112                 audioManager.setMode(AudioManager.MODE_NORMAL);
113                 testRecord.this.finish();
114             }
115         }  
116     }  
117   
118     class RecordPlayThread extends Thread {  
119         public void run() {  
120             try {  
121                  byte[] buffer = new byte[recBufSize];  
122                 audioRecord.startRecording();//开始录制  
123                 audioTrack.play();//开始播放 
124                 while (isRecording) {  
125                     //从MIC保存数据到缓冲区  
126                     int bufferReadResult = audioRecord.read(buffer, 0,  
127                             recBufSize);
128                     byte[] tmpBuf = new byte[bufferReadResult];  
129                     System.arraycopy(buffer, 0, tmpBuf, 0, bufferReadResult);  
130                     //写入数据即播放  
131                     audioTrack.write(tmpBuf, 0, tmpBuf.length);
132                 }  
133                 audioTrack.stop();  
134                 audioTrack.release(); 
135                 audioRecord.stop();
136                 audioRecord.release();
137             } catch (Throwable t) {  
138                 Toast.makeText(testRecord.this, t.getMessage(), 1000);  
139             }  
140         }  
141     }
142 }

    这些java class接口类在android.media包中,源码目录:frameworks/base/media/java/android/media。这些接口为使用media包的用户提供了音量和路由设置,播放和录制的pcm数据的接口。

  JNI层

    (android_media_AudioSystem, android_audio_AudioTrack, android_audio_AudioRecord),在libandroid_runtime.so包中
  本地框架层

    AudioSystem:media库提供给上层的audio管理的接口,它的实现主要在audiopolicymanger和audioflinger中
    AudioTrack:放音部分对上层的接口,stagefright部分也是调用该接口创建和控制playback track
    AudioRecord:录音部分对上层的接口,stagefright部分也是调用该接口创建一路record track
    IAudioTrack, IAudioRecord, IAudioFlinger:这三个是声明需要底层audioflinger实现的接口函数
    这些c接口类在libmedia.so库中,源码目录:frameworks/av/media/libmedia

  audio服务层

    AudioFlinger:这一层主要实现了track的创建,Android层共享内存的分配,多路混音等
  硬件抽象层

    AudioHardwareInterface:这一层需要根据不同的硬件由厂商自己实现,如Primary,Usb,spdif,a2dp等,每一种硬件设备需要继承audioHardwareInterface,实现一个控制硬件so库。主要的类有AudioStreamOut和AudioStreamIn分别是audio输出环节和输入环节,负责write数据流到硬件和从硬件read数据流。

  六总结

    通过对各层一个概括性的介绍,对Audio系统的系统结构和源码分布有一个清楚的理解。

posted @ 2012-09-27 16:40  cerberspace  阅读(1478)  评论(0编辑  收藏  举报