android app读写音频数据时如何控制音频解码器? android音频解码器通过alsa来控制;电话语音的流入流出、麦克风语音的流入、耳机语音的流出,app读写语音的流入流出都连着音频解码器。 我想要做到的是在电话已拨通,从而语音已可流入流出解码器后,让app也可读写语音。 从而让app写入的语音流到电话芯片里,让从电话芯片里流出的语音数据流到app里。 我的问题是如何在此时设置alsa呢? 或者如何实现自动应答的app? Android音频管理包括以下三个方面: 1)控制APP的声音和回放:确保用户可以通过硬件或者软件音量键来控制APP的音量以及对音频的一些控制例如播放、暂停、停止、浏览和上下媒体文件切换。 2)管理音频焦点:由于许多APP都可能播放音频,因此需要考虑它们之间的交互。为了避免同一时刻各个音频都播放,Android利用音频焦点来调节当前的音频播放。 3)处理音频输出硬件:音频可以被多个源播放,我们需要知道该音频是来自哪儿并且需要知道如何处理当回放音频的时候耳机断开连接的情况。 1)控制APP的声音和回放 (1)确定使用哪个音频流 Android对播放音乐、闹钟、提示、来电铃音、系统音、通话音以及DTMF音采取分割开的音频流管理,所以用户可以独立的控制每一个流的音量。这些流中的大多数都受限于系统响应,大多数情况下当播放我们的音频时,应该采用STREAM_MUSIC流。 (2)利用手机音量键控制APP音量 Android通过setVolumeControlStream()方法来管理你所指定的音频流对音量键的处理。当确定了音频流后,应该将该音频流传递给setVolumeControlStream()。值得注意的是,我们应当将该方法的调用放在APP生命周期的最前面,因为在你的Activity生命周期里它只需要调用一次,通常将其放置在onCreate()方法里。例如: setVolumeControlStream(AudioManager.STREAM_MUSIC); (3)利用硬件的控制键来控制音频回放 通过一些手持设备和其他想连接的耳机上的控制键,可以对音频进行控制。当用户按下某个键后,系统会广播ACTION_MEDIA_BUTTON行为的intent。为了对其作出反应,需要在manifest文件中登记BroadcastReceiver来监听这种广播行为。如下所示: 接着需要对intent作出处理。KeyEvent类包括代表按键类型的静态常量列表以KEYCODE_MEDIA_*打头。例如KEYCODE_MEDIA_PLAY_PAUSE和KEYCODE_MEDIA_NEXT。如下示例: public class RemoteControlReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intentintent) { if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())){ KeyEvent event =(KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()){ // Handle key press. } } } } 除了硬件上的按键来控制音频外,大多数应用都需要提供屏幕上的软控制,我们利用AudioManager类来为你的APP登记和注销media button事件的接收。如下: AudioManager am =mContext.getSystemService(Context.AUDIO_SERVICE); ... // Start listening for button presses am.registerMediaButtonEventReceiver(RemoteControlReceiver); ... // Stop listening for button presses am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); 通过应用获得和丢失audio focus来登记和注销media button事件是对该软控制的比较好的一个处理。 2)管理音频焦点 为了避免不同应用同时播放声音,Android采用audio focus来播放声音。 (1)请求Audio Focus app在播放任何音频前,需要获取audio focus。通过调用requestAudioFocus(),如果返回AUDIOFOCUS_REQUESST_GRANTED则表示请求成功。 同时,我们需要指定你所采用的流对audio focus的获取是暂时的还是持续的。暂时的表示仅仅希望流播放很短的时间,例如导航指令;持续的表示希望音频播放很长的一段时间,例如播放音乐。 如下是一个获取持续audio focus的例子。 AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE); ... // Request audio focus for playback int result = am.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); // Start playback. } 当结束播放后,应该调用abandAudioFocus()。它会告知系统不需要在占据audio focus,并且注销相关联的AudioManager.OnAudioFocusChangeListener. // Abandon audio focus when playback complete am.abandonAudioFocus(afChangeListener); 如下给出了获取暂时audio focus的例子。 // Request audio focus for playback int result = am.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback. } (3)处理Audio Focus的丢失 因为能获得audio focus,所以当其他app请求它的时候,你的app可能会失去它,app如何去应对这样一种情况取决于丢失的行为。 一般来说,当短暂丢失时,应该让app对其流静音,同时要维护其状态。此时要监测audio focus的状态改变,记录暂停的地方,从而在获得focus后继续播放。 如果是持续的丢失,一般假定另一个应用需要监听音频。所以这时候我们一般要停止播放,注销掉相关的控件。 如下为上述两种过程的处理方法。 OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Resume playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); am.abandonAudioFocus(afChangeListener); // Stop playback } } }; 3)处理音频输出硬件 一般来说手机设备都有内置扬声器,有线耳机插口以及蓝牙。可以通过查询AudioManager来确定。 if (isBluetoothA2dpOn()) { // Adjust output for Bluetooth. } else if (isSpeakerphoneOn()) { // Adjust output for Speakerphone. } else if (isWiredHeadsetOn()) { // Adjust output for headsets } else { // If audio plays and noone can hear it, is it still playing? } |