第七章 深入解析android网络编程
第九章 android多媒体编程
9.1 音频处理
上述为google为开发者提供的音频开发框架,
在应用层,开发者可以调用MediaPlayer, MediaRecorder, SoundPool 等进行音频的播放,
记录以及游戏的特效音制作等。
在框架层,AudioFlinger, AudioPolicyManager, AudioSerivce AudioHardwareInterface构成了对音频控制的基本骨架。框架层本身包括java,C++两部分,并通过JNI 进行通信,其中对服务的调用是基于C/S框架实现的。内核层提供不同音频设备的驱动和ALSA框架等。音频本身的播放涉及的多媒体引擎是 Stagefright。
AudioPolicyService 所负责的工作在早期版本中是在AudioFlinger中实现的。随着场景的复杂化,Google 将关于音频设备的连接状态,音频的并发策略,音量的处理等工作放置到
AudioPolicyService 中,而
AudioFlinger更侧重于音频流的控制
。
AudioHardwareInterface则是对不同设备产商的音频设备的驱动与框架层的适配接口,为框架层提供一个与驱动通信的统一接口
。
下面对音频播放,音频录制,音频管理,音效处理等几个方面进行介绍:
9.1.1 音频播放
根据播放方式的不同,android为应用层提供了多个播放接口,如MediaPlayer, SoundPool , AudioTrack , AsyncPlayer, JetPlayer, ToneGenerator 等, 他们适用于不同的场景。
1. 基于MediaPlayer 播放
功能强大,对音频视频都支持,为保证播放期间系统正常工作,需要设置
android.permission.WAKE_LOCK权限。
MediaPlayer支持的音频格式包括 AAC, AMR, FLAC MP3 MIDI, OGG, PCM等。
在原生层 MediaPlayer 由状态机控制,其状态机如下图:
注意: 当调用reset()方法时,MediaPlayer会返回到MEDIA_PLAYER_IDLE状态,除了图中所示的状态外,MediaPlayer还存在一个出错的状态,即 Media_Player_STATE_ERROR。监听出错的监听器为 MediaPlayer.OnErrorListener。
对于背景音乐,将MediaPlayer封装在Service中即可实现。
对于背景音乐,将MediaPlayer封装在Service中即可实现。
MediaPlayer支持元数据,音频文件,音频流等形式的源数据的播放。
(1)播放元数据
所谓
元数据即 raw 文件夹下的资源文件,调用方法如下:
mMediaPlayer = MediaPlayer.create( this, R.raw.test.cbr );
mMediaPlayer.start();
(2)播放音频文件
对于本地文件,其数据源可通过 Uri 来表示,在开始播放前需要设置播放类型并加载缓冲,实例如下:
Uri myUri = ... ;
MediaPlayer mediaPlayer = new
MediaPlayer();
mediaPlayer.setAudioStreamType( AudioManager.STREAM_MUSIC );
mediaPlayer.setDataSource( getApplicationContext(), myUri );
mediaPlayer.prepare(); //加载缓冲
mediaPlayer.start();
(3)播放流
MediaPlayer 支持基于网络的流播放,其支持的协议包括 RSTP, HTTP渐进流, HTTP生活流等。在网络播放和本地文件播放略有不同,实例如下:
String url = "http://zhangmenshiting.baidu.com/****.mp3";
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType( AudioManager.STREAM_MUSIC );
mediaPlayer.setDataSource( url );
mediaPlayer.prepareAsync();
.................. mediaPlayer.start();
考虑到网络情况的发杂性,以及获取数据和解码的时间比较长,不推荐在播放流时通过 prepare() 方法加载缓冲,尤其不能再UI主线程中调用。应通过 prepareAsync() 方法将缓冲的工作放置在非UI主线程中进行,当准备完成时,MediaPlayer通过 MediaPlayer.OnPreparedListener 监听器可以监听到该时间。设置方法如下:
mMediaPlayer.setOnpreparedListener( mPreparedListener );
通常在准备工作完成后开始进行播放。监听器处理加载缓冲结束的消息的方法:
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.onPreparedListener(){
public void onPrepared( MediaPlayer mp ){
mediaPlayer.start();
}
}
当播放结束时,通过MediaPlayer.OnCompletionListener 可以监听到播放结束的消息,实例如下:
mMediaPlayer.setOnCompletionListenr( new MediaPlayer.OnCompletionListener(){
public void onCompletion( MediaPlayer mediaPlayer ){
}
} );
2. 基于SoundPool 播放
SoundPool 能够播放音频流的组合音,这对游戏应用很有用,其对应的JNI接口为 android_media_SoundPool.cpp
SoundPool 可通过APK包中的资源文件或文件系统中的文件将音频资源加载到内存中。在底层实现上,SoundPool 通过媒体播放服务(MediaPlaybackService)可以将音频资源解码为一个 16位的单声道或立体声的 PCM流,使应用避免了再回放过程中进行解码造成的延迟。
除了回放过程中延迟小的优点外,SoundPool 还能够对一定数量的音频流进行同时播放。当要播放的音频流数量超过
SoundPool 所设置的最大值时,SoundPool 将会停止已播放的一条低优先级的音频流。SoundPool 对最大音频流数量的设置(默认为32),可避免CPU过载。
对游戏等应用而言,MediaPlayer会使性能减低。在android中,专门提供了SoundPool 类来执行此类音频播放,SoundPool 类占用的CPU资源较少,反应较快。
与其他音频播放类相比,SoundPool 类可自行设置音频播放时的品质,音量,播放速率等,并可管理多个音频流,每个流均拥有自己独立的ID,对单个音频流的管理均是通过其ID 来进行的。 SoundPool 类使用的场景包括应用程序中的音效。
SoundPool 组合音频流的实例如下:
int srcQulity = 100;
mSoundPool = new SoundPool( SOUNDPOOL_STREAMS, AudioManager.STREAM_MUSIC, srcQuality );//创建SoundPool对象
//架子音频流
int sampleId1 = mSoundPool.load( mContext, R.raw.a_4, PRIORITY );
AssetFileDescriptor afd = mContext.getResources().openRawResourceFd( R.raw.c_sharp_5 )
;
int smapleId2 = mSoundPool.load( afd, PRIORITY );
FileDescriptor fd = afd.getFileDescriptor();
long offset = afd.getStartOffset();
long length = afd.getLength();
int sampleId3;
sampleId3 = mSoundPool.load( fd, offset, length, PRIORITY );
String path = mFile.getAbsolutePath();
int sampleId4;
sampleId4 = mSoundPool.load( path, PRIORITY );
mSoundPool.unload( sampleId4 );
通过 SoundPool 播放某音频流的方法如下:
float leftVolume = SILENT;
float rightVolume = LOUD;
int priority = 1;
int loop = 0 ;
int rate = 1f;
int streamID = mSoundPool.play( sampleID, leftVolume, rightVolume, priority, loop, rate );
3. 基于AudioTrack播放
AudioTrack主要用于管理单个音频,这是一个较底层的音频播放方法。在构建AudioTrack时,需要明确流类型,采样率,通道配置,音频格式,缓冲大小,播放模式等参数。
AudioTrack 支持 STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC 和 STREAM_ALARM等流类型。
AudioTrack支持 44100Hz , 22050Hz, 11025Hz等采样率。
AudioTrack支持单声道(CHANNEL_OUT_MONO)和立体声(CHANNEL_OUT_STEREO)两种声道。
AudioTrack支持 ENCODING_PCM_16BIT 和 ENCODING_PCM_8BIT 两种编码格式。
AudioTrack支持静态模式(Static Mode)和流模式(Streaming Mode)两种播放模式。静态模式由于没有从java层向原生层传递数据造成的延迟,因此时延很小。当然,受限于音频缓冲的大小,静态模式常在游戏场景中用于播放时长很短的音频资源。当音频流较大不足以在音频缓冲证一些写入时,可采用流模式。AudioTrack的应用实例如下:
track = new