DSP

Android学习(6)音频管理AudioManager-3

2019-07-13 15:36发布

上面两篇简单的分析了,android系统中FrameWork中对于音量的调节的部分代码,可能有些更深入的东西并没有涉及,因为初次尝试分析,并不是所有东西都能完全明白和透彻的理解,所以暂时只能将我所了解到并用到的部分做了解析。          这篇主要想解析下在AudioManager中对于音频竞争机制的部分内容和使用方式。          首先来说下这中竞争机制的产生原因,根据我的理解因为Android系统中存在众多音频类型,并且他们相互之间都保持独立的存在,并不会相互影响。如音乐的声音,按键的触摸声音,响铃的声音,通话的声音,蓝牙通话的声音,错误报警的声音等等。都会有一个响应的声音类型。因此他们之间也会有独立的音频流来控制播放。为了防止这些声音会相互产生影响,竞争机制就产生了,这个机制有效的控制了这部分声音的播放的优先级已经是否存在互斥,共存等独立的关系,每个音频流在播放时都会通过这中机制获取播放的许可,使其可以被监控状态,便于管理。          对于这种机制,其中核心内容就是音频焦点的管理。          下面会贴出部分代码           [java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 
  3.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  4.  * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 
  5.  */  
  6. public static final int AUDIOFOCUS_GAIN = 1;  
  7. /** 
  8.  * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 
  9.  * amount of time. Examples of temporary changes are the playback of driving directions, or an 
  10.  * event notification. 
  11.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  12.  * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 
  13.  */  
  14. public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;  
  15. /** 
  16.  * Used to indicate a temporary request of audio focus, anticipated to last a short 
  17.  * amount of time, and where it is acceptable for other audio applications to keep playing 
  18.  * after having lowered their output level (also referred to as "ducking"). 
  19.  * Examples of temporary changes are the playback of driving directions where playback of music 
  20.  * in the background is acceptable. 
  21.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  22.  * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 
  23.  */  
  24. public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;  
  25. /** 
  26.  * Used to indicate a loss of audio focus of unknown duration. 
  27.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  28.  */  
  29. public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;  
  30. /** 
  31.  * Used to indicate a transient loss of audio focus. 
  32.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  33.  */  
  34. public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;  
  35. /** 
  36.  * Used to indicate a transient loss of audio focus where the loser of the audio focus can 
  37.  * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 
  38.  * the new focus owner doesn't require others to be silent. 
  39.  * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 
  40.  */  
  41. public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =  
  42.         -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;  
        上述代码也是存在于androidframeworksasemediajavaandroidmediaAudioManager.java中的,先给出部分定义。          AUDIOFOCUS_GAIN -- 持久焦点,详情见注释部分,用来播放较长一段时间的音频,之前的音频焦点使用者需停止声音。          AUDIOFOCUS_GAIN_TRANSIENT --瞬态焦点,用来播放很短时间的音频,之前的焦点使用者需暂停声音。         AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK --瞬态焦点,用来播放时间较短的音频,之前的音频焦点使用者需降低本身音量。         AUDIOFOCUS_LOSS -- 失去焦点,表明持续焦点使用者失去音频焦点。         AUDIOFOCUS_LOSS_TRANSIENT -- 失去焦点,表明瞬态焦点使用者失去音频焦点。         AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -- 失去焦点,表明瞬态焦点使用者即降低本身音量的焦点使用者失去音频焦点。        上述定义都是需要在请求音频焦点时指定的参数,接下来继续解析音频焦点的请求。          [java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * A failed focus change request. 
  3.  */  
  4. public static final int AUDIOFOCUS_REQUEST_FAILED = 0;  
  5. /** 
  6.  * A successful focus change request. 
  7.  */  
  8. public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;  
  9.   
  10. /** 
  11.  *  Request audio focus. 
  12.  *  Send a request to obtain the audio focus 
  13.  *  @param l the listener to be notified of audio focus changes 
  14.  *  @param streamType the main audio stream type affected by the focus request 
  15.  *  @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 
  16.  *      is temporary, and focus will be abandonned shortly. Examples of transient requests are 
  17.  *      for the playback of driving directions, or notifications sounds. 
  18.  *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 
  19.  *      the previous focus owner to keep playing if it ducks its audio output. 
  20.  *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 
  21.  *      as the playback of a song or a video. 
  22.  *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 
  23.  */  
  24. public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {  
  25.     int status = AUDIOFOCUS_REQUEST_FAILED;  
  26.     if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK))  
  27.     {  
  28.         Log.e(TAG, "Invalid duration hint, audio focus request denied");  
  29.         return status;  
  30.     }  
  31.     registerAudioFocusListener(l);  
  32.     //TODO protect request by permission check?  
  33.     IAudioService service = getService();  
  34.     try {  
  35.         status = service.requestAudioFocus(streamType, durationHint, mICallBack,  
  36.                 mAudioFocusDispatcher, getIdForAudioFocusListener(l),  
  37.                 mContext.getPackageName() /* package name */);  
  38.     }catch (RemoteException e) {  
  39.         Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);  
  40.     }  
  41.     return status;  
  42. }  
  43.   
  44. /** 
  45.  * @hide 
  46.  * Used internally by telephony package to request audio focus. Will cause the focus request 
  47.  * to be associated with the "voice communication" identifier only used in AudioService 
  48.  * to identify this use case. 
  49.  * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 
  50.  *    the establishment of the call 
  51.  * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 
  52.  *    media applications resume after a call 
  53.  */  
  54. public void requestAudioFocusForCall(int streamType, int durationHint) {  
  55.     IAudioService service = getService();  
  56.     try {  
  57.         service.requestAudioFocus(streamType, durationHint, mICallBack, null,  
  58.                 AudioService.IN_VOICE_COMM_FOCUS_ID,  
  59.                 "system" /* dump-friendly package name */);  
  60.     }catch (RemoteException e) {  
  61.         Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);  
  62.     }  
  63. }  
  64.   
  65. /** 
  66.  * @hide 
  67.  * Used internally by telephony package to abandon audio focus, typically after a call or 
  68.  * when ringing ends and the call is rejected or not answered. 
  69.  * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 
  70.  */  
  71. public void abandonAudioFocusForCall() {  
  72.     IAudioService service = getService();  
  73.     try {  
  74.         service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);  
  75.     } catch (RemoteException e) {  
  76.         Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);  
  77.     }  
  78. }  
  79.   
  80. /** 
  81.  *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 
  82.  *  @param l the listener with which focus was requested. 
  83.  *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 
  84.  */  
  85. public int abandonAudioFocus(OnAudioFocusChangeListener l) {  
  86.     int status = AUDIOFOCUS_REQUEST_FAILED;  
  87.     unregisterAudioFocusListener(l);  
  88.     IAudioService service = getService();  
  89.     try {  
  90.         status = service.abandonAudioFocus(mAudioFocusDispatcher,  
  91.                 getIdForAudioFocusListener(l));  
  92.     } catch (RemoteException e) {  
  93.         Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);  
  94.     }  
  95.     return status;  
  96. }  
         上面的代码主要贴出了请求和释放音频焦点的两个操作的函数,对于请求操作          requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)有三个参数          第一个参数:需要写一个音频焦点的监听,可以如下                                [java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {   
  2.   public void onAudioFocusChange(int focusChange) {   
  3.     if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT   
  4.        // Pause playback   
  5.     } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {   
  6.       // Resume playback   
  7.     } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {   
  8.       am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);   
  9.       am.abandonAudioFocus(afChangeListener);   
  10.       // Stop playback   
  11.     }   
  12.   }   
  13. };  
        第二个参数:需要制定音频流的类型,如第一篇所描述的STREAM_MUSIC,STREAM_RING,STREAM_SYSTEM等等。         第三个参数:这个参数就是这篇开始的时候所列举的前三个音频焦点类型了。      请求函数如果成功的话会返回AUDIOFOCUS_REQUEST_GRANTED 失败则返回 AUDIOFOCUS_REQUEST_FAILED       请求的方法可参考如下:        [java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);   
  2. ...   
  3.    
  4.    // Request audio focus for playback