马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?快速注册
x
说到音频应用,首先想到的就是音乐播放器。有些播放器可以播放流媒体,有些可以播放本地音乐文件。随着Android平台的演变,需要更多高级的音频API。好在谷歌新增了这方面的API,支持低延迟的音频流媒体和录制。. |4 u. U/ @# m" u' H9 K
# B' a8 j0 X- p, s |1 S! t
Android音频API提供了一些高级的功能,开发者可以把它们集成到自己的应用中。有了这些API,现在可以更容易地实现VoIP应用程序,构建定制的流媒体音乐客户端,实现低延迟的游戏音效。此外,还有提供文本到语音转换以及语音识别的API,用户可以直接使用音频和应用交互,而不需要使用用户界面或者触控技术。4 y, R+ X+ Z$ B' a$ R" T; T
) _; X; P0 P' X4 {( Y4 k* ~) F
低延迟音频
5 P& ~! Q; {; kAndroid有四个用来播放音频的API(算上MIDI的话一共五个)和三个用来录音的API。接下来会简要的介绍这些API,以及一些高级用法示例。( c" q7 @7 g0 ]& I; G7 u- J$ N8 u2 g
# E& v* p5 m0 s1 s①音频播放API- _$ M6 E1 n# g ^ G7 d
, D' j+ Y0 C& y音乐播放默认使用MediaPlayer。该类适合播放音乐或者视频,既能播放流式资源,还可以播放本地文件。每个MediaPlayer都有一个关联的状态机,需要在应用程序中跟踪这些状态。开发者可以使用MediaPlayer类的API在自己应用中嵌入音乐或者视频播放功能,而无需额外处理或者考虑延迟要求。( Z4 G) s8 L. R3 t
2 w9 o: c2 b. @4 a* M0 m第二个选择是SoundPool类,它提供了低延迟支持,适合播放音效和其他比较短的音频,比如可以使用SoundPool播放游戏声音。但是,它不支持音频流,所以不适合那些需要实时音频流处理的应用,如VoIP。
% R: t5 D& t* z E; K4 m& R 6 n3 F& [( U( ~
第三个选择是AudioTrack类,它允许把音频流缓冲到硬件中,支持低延迟播放,甚至适合流媒体场景。AudioTrack类通常提供足够低的延迟,可在VoIP或类似应用中使用。' u g+ ?# m( L3 p
" N& s, L" y* _下面的代码展示了如何在VoIP应用中使用AudioTrack:! P$ l' I5 `2 z) x
7 Y T* U' { vpublic class AudioTrackDemo {+ R$ u. H7 O: I* o' q$ D2 v( `
private final int mMinBufferSize;
1 u& C' x& ]7 n0 Z; I# Q% Q private final AudioTrack mAudioTrack;
/ H$ O; G* c- _! q1 R6 \7 @8 k
! M k: h0 m: Y9 x9 s, m public AudioTrackDemo() {
6 z; a1 i' p% H+ Y+ Y! m/ V this.mMinBufferSize = AudioTrack.getMinBufferSize(16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);) n3 n6 R0 f1 e, `
this.mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, this.mMinBufferSize*2, AudioTrack.MODE_STREAM);" J, D5 F% O3 ]$ B
}
% s W3 h1 R1 H9 @: l, Z \
0 ^+ U1 m( ~/ I public void playPcmPacket(byte[] pcmData) {
* ~* D$ \# c8 n if (this.mAudioTrack != null && this.mAudioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
9 L" E6 ^ r+ C. I; B4 d% X if (this.mAudioTrack.getPlaybackRate() != AudioTrack.PLAYSTATE_PLAYING) {
$ f+ @, f: s- y this.mAudioTrack.play();- {3 K+ ~( ~$ H( Q3 ^7 _% }
}
4 Q0 f D) B" a- `% x) I this.mAudioTrack.write(pcmData, 0, pcmData.length);
/ W1 U1 G) A8 h5 ]* |* ]+ c }( y* N Z5 Q0 N5 s/ ^' O8 ~! x6 Y
} Y2 E- @; [6 J- T- |5 d- C$ Q
3 {; O% q( a7 X' Q+ P public void stopPlayback() {
0 n& z1 w$ r" b) t8 N if (this.mAudioTrack != null) {
& g* h. h7 E+ E6 A this.mAudioTrack.stop();# V" I! C) F8 K5 f6 y0 ^
this.mAudioTrack.release();
6 N' G" T" w9 }9 ^* [ }; k! A, V, {9 ~2 X0 J! P! k
}, k$ H) l0 s5 |/ V( d
}
# D" O+ V, {1 Q# b5 @8 L) y2 w! c
- |7 ]; q- n& J* p3 i3 L - X8 F9 Z# C. C! p) F3 k7 W1 M, c
首先,确定音频流的最小缓冲区大小。要做到这一点,需要知道采样率,数据是单声道还是立体声,以及是否使用8位或者16位PCM编码。然后以采样率和采样大小作为参数调用AudioTrack.getMinBufferSize(),该方法会以字节形式返回AudioTrack实例的最小缓冲区大小。/ W3 X) `* ?) K. D
* [$ I5 _0 k0 X# H
接下来,根据需要使用正确参数创建AudioTrack实例。第一个参数为音频的类型,不同的应用使用不同的值。对VoIP应用来说,使用STREAM_VOICE_CALL,而对于流媒体音乐应用则使用STREAM_MUSIC。9 c6 J' `6 U! d. p5 l1 ?- K
1 B7 v$ y |0 Z. r8 c) L具体的选择有:
7 E9 a1 d- g0 P5 }* V& o& a6 oSTREAM_ALARM:手机闹铃的声音. R% v4 I1 I, ~* ?! ~5 ?: [1 z
STREAM_MUSIC:手机音乐的声音1 R; ?. B) k% Z( w9 d* Q R8 \# d4 ^
STREAM_DTMF:DTMF音调的声音
, E9 h' C- Z1 k& bSTREAM_RING:电话铃声的声音
4 [( o. s9 V! t" V1 `: ESTREAM_NOTFICATION:系统提示的声音
2 Q9 W. B) ^ p. CSTREAM_SYSTEM:系统的声音, e% C# K/ V6 t! |3 N8 M; p v) t
STREAM_VOICE_CALL:语音电话声音0 o$ t' w( O/ D$ D
, Q3 _/ B+ }- y+ o4 z H第二,第三,第四个参数根据使用场景会有所不同。这些参数分别表示采样率,立体声或者单声道,以及采样大小。一般而言,一个VoIP应用会使用16KHZ的16位单声道,而常规的音乐CD可能采用44.1KHZ的16位立体声。16位立体声高采样率需要更大的缓冲区以及更多的数据传输,但是音质会更好。所有的Android设备都支持PCM以8KHZ,16KHZ,44.1KHZ的采样率播放8或者16位立体声。
. _' R/ Q& @9 b6 u! e8 P / j8 d: a: W9 m2 d
缓冲区大小参数应该是最小缓冲区的倍数,实际取决于具体的需求,有时网络延迟等因素也会影响缓冲区大小。
, k" H4 P5 r* @" p( r) O3 }* m2 i任何时候都应该避免使用空的缓冲区,因为可能导致播放出现故障。# y6 q: v9 {- P. z3 [/ r; E- O1 b2 y
6 b) l' E! _/ I- H* ?& w最后一个参数决定只发送一次音频数据(MODE_STATIC)还是连续发送数据流(MODE_STREAM)。第一种情况需要一次发送整个音频剪辑。对于持续发送音频流的情况,可以发送任大小块的PCM数据,处理流媒体音乐或者VoIP通话可以会使用这种方式。( X- P# c- l( Q
4 z- ~8 [/ M- z: T' R
②录制API! B2 c' g- t" z
( Y1 m$ t) @/ v( i6 f) @谈到录制音频,首先要考虑的API是MediaRecorder。和MediaPlayer类似,需要在应用代码中跟踪MediaRecorder类的内部状态。由于MediaRecorder只能把录音保存到文件中,所以它不适合录制流媒体。3 U7 P7 Y- N, _% C% m! ~8 c! ^
如果需要录制流媒体,可以使用AudioRecord,和刚才展示的代码非常类似。
( g) `4 t) E6 I t" Z( Q" ~
/ m9 E2 x; ?3 v8 ?$ h H4 `9 l下面的示例显示了如何创建AudioRecord实例录制16位单声道16KHZ的音频采样:
; A! S) D& W% ~$ Y; t4 X' H 2 |% K. f& d( a# B% S9 X" D: {
public class AudioRecordDemo {' Z7 t$ N8 V1 X: Q) \
private final AudioRecord mAudioRecord;
3 q2 Z5 Z. ]' I$ o2 j private final int mMinBufferSize;, _' s' f2 i; c: f
private boolean mDoRecord = false;
2 k/ e! G1 p; o" c7 i( Z
* g3 s9 z) X0 G& W( `9 D public AudioRecordDemo() {4 z5 I) |) m. Q; F" K
this.mMinBufferSize = AudioTrack.getMinBufferSize(16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
7 k {+ N/ ~4 C ^3 a# u this.mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, this.mMinBufferSize * 2);
$ ~! G8 T3 S x: Z6 P1 @ }5 }: y4 o* M. V. D
! t8 o) e. X; |# k! T) i1 Q7 X
public void writeAudioToStream(OutputStream stream){
8 |3 ]' L O; Z9 ^( s this.mDoRecord=true;# F2 j, i3 P3 m" ]; B
this.mAudioRecord.startRecording();
- a9 @: [0 n6 i2 L; S, l byte[] buffer=new byte[this.mMinBufferSize*2];
7 Z% `9 i H; e4 O c while(this.mDoRecord){! ]) g/ {8 Y: {& J
int byteWritten=this.mAudioRecord.read(buffer,0,buffer.length);: Y& k! J+ R' k% n! I+ C1 O
try{
7 a! Z5 j' |9 x, \: o$ L8 Q0 i stream.write(buffer,0,byteWritten);8 K3 }2 ~4 o2 y/ Q+ I
}catch(IOException e){) R) x$ |& }: O
this.mDoRecord=false;2 L6 Y# d) d4 h& G9 x$ m; U( O
}
, K% ? E2 w6 m- L }* n. [7 L+ a/ x' L1 X- X
this.mAudioRecord.stop();! t. {( W( c% b( \
this.mAudioRecord.release();
" B9 G }% C1 W, x4 M0 s3 C, o! [9 b }
- w2 }; Q& Z; B0 L `$ K* _! e+ n+ d' n' v8 A7 a) F
public void stopRecording(){
0 ^# T. w! P. U8 S this.mDoRecord=false;& U, `, a" R m, F& n7 ~/ f
}
1 _7 T1 @. k- b& Y* k% e( |' {: Q* h3 n* K
& Z( m1 e6 i7 X( [- L& a; }}% l u! ]% y! z! y* E
2 Y, e/ d6 _. U. D
& t' _, }8 d9 T
因为和AudioTrack的创建过程非常类似,在使用VoIP或者类似应用时可以很方便地把它们结合起来。
' W% S: M2 C. H" w( j7 _# Q, Q 8 i! h, B8 s1 d. P& M
相信学过多媒体的人对采样率等这些东西并不陌生,如果缺乏这方面的知识,可以适当的补充后在来看这段代码。: s9 q& b# _. J& R5 f
延伸阅读:: X7 ^7 |; M* N1 E+ |2 h
AndroidAnnnotations注入框架使用之最佳实践之Adapters和lists(5 s/ F8 k8 C# _; \
AndroidAnnnotations注入框架使用之第三方框架集成RoboGuice(十. [0 h0 v4 W" s0 Z. R# |
Android MVP开发模式详解(十九)
' m' \, F+ f3 }% a& h# E$ L谷歌发布会:Nexus 4\10 Android4.2正式发布
$ c9 u. s& F6 YAndroid 自定义对话框,进度条,下拉刷新等( ~& p. M5 X7 Y6 h
更多相关手机软件开发、安卓软件开发、Android软件开发教程学习请移步到手机软件开发频道。 |