Android Audio 系统的主要内容:
- AudioManager:这个主要是用来管理Audio系统的,需要考虑整个系统上声音的策略问题,例如来电话铃声,短信铃声等,主要是策略上的问题。
- AudioTrack:这个主要是用来播放声音的
- AudioRecord:这个主要是用来录音的
当前分析AudioTrack的文章较多,先以AudioTrack为例进行分析。
JAVA层的AudioTrack class:framework\base\media\java\android\media\AudioTrack.java中。
AudioTrack的使用方法实例:
1 //根据采样率,采样精度,单双声道来得到frame的大小。 2 int bufsize = AudioTrack.getMinBufferSize(8000,//每秒8K个点 3 AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道 4 AudioFormat.ENCODING_PCM_16BIT);//一个采样点16比特-2个字节 5 //注意,按照数字音频的知识,这个算出来的是一秒钟buffer的大小。 6 //创建AudioTrack 7 AudioTrack trackplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 8 AudioFormat.CHANNEL_CONFIGURATION_ STEREO, 9 AudioFormat.ENCODING_PCM_16BIT,bufsize,AudioTrack.MODE_STREAM);// 10 trackplayer.play() ;//开始 11 trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ;//往track中写数据 12 …. 13 trackplayer.stop();//停止播放 14 trackplayer.release();//释放底层资源。
AudioTrack.MODE_STREAM:AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。
StreamType:这个在构造AudioTrack的第一个参数中使用。这个参数和Android中的AudioManager有关系,涉及到手机上的音频管理策略。Android将系统的声音分为以下几类常见的(未写全):
- STREAM_ALARM:警告声
- STREAM_MUSCI:音乐声,例如music等
- STREAM_RING:铃声
- STREAM_SYSTEM:系统声音
- STREAM_VOCIE_CALL:电话声音
为什么要分这么多呢?以前在台式机上开发的时候很少知道有这么多的声音类型,不过仔细思考下,发现这样做是有道理的。例如你在听music的时候接到电话,这个时候music播放肯定会停止,此时你只能听到电话,如果你调节音量的话,这个调节肯定只对电话起作用。当电话打完了,再回到music,你肯定不用再调节音量了。其实系统将这几种声音的数据分开管理,所以,这个参数对AudioTrack来说,它的含义就是告诉系统,我现在想使用的是哪种类型的声音,这样系统就可以对应管理他们了。
从AudioTrack的使用实例来逐个分析其中用到的方法,首先是getMinBufferSize:
getMinBufferSize
/** * Returns the minimum buffer size required for the successful creation of an AudioTrack * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't * guarantee a smooth playback under load, and higher values should be chosen according to * the expected frequency at which the buffer will be refilled with additional data to play. * For example, if you intend to dynamically set the source sample rate of an AudioTrack * to a higher value than the initial source sample rate, be sure to configure the buffer size * based on the highest planned sample rate. * @param sampleRateInHz the source sample rate expressed in Hz. * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_OUT_MONO} and * {@link AudioFormat#CHANNEL_OUT_STEREO} * @param audioFormat the format in which the audio data is represented. * See {@link AudioFormat#ENCODING_PCM_16BIT} and * {@link AudioFormat#ENCODING_PCM_8BIT} * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed, * or {@link #ERROR} if unable to query for output properties, * or the minimum buffer size expressed in bytes. */ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; switch(channelConfig) { case AudioFormat.CHANNEL_OUT_MONO: case AudioFormat.CHANNEL_CONFIGURATION_MONO: channelCount = 1; break; case AudioFormat.CHANNEL_OUT_STEREO: case AudioFormat.CHANNEL_CONFIGURATION_STEREO: channelCount = 2; break; default: if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) { // input channel configuration features unsupported channels loge("getMinBufferSize(): Invalid channel configuration."); return ERROR_BAD_VALUE; } else { channelCount = Integer.bitCount(channelConfig); } } //目前只支持PCM8和PCM16精度的音频 if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { loge("getMinBufferSize(): Invalid audio format."); return ERROR_BAD_VALUE; } //ft,对采样频率也有要求,太低或太高都不行,人耳分辨率在20HZ到40KHZ之间 // sample rate, note these values are subject to change if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) { loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate."); return ERROR_BAD_VALUE; } //调用native函数 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); if (size <= 0) { loge("getMinBufferSize(): error querying hardware"); return ERROR; } else { return size; } }