Android FrameWork 오디오 관리 Audio Manager에 대한 약간의 해결(계속)

위의 두 편에서 간단히 분석한 바와 같이 android 시스템에서 FrameWork에서 음량 조절에 대한 일부 코드는 언급되지 않았을 수도 있다. 첫 번째 분석을 시도했을 때 모든 것을 완전히 이해하고 철저하게 이해할 수 있는 것은 아니기 때문에 당분간 내가 알고 사용한 부분만 분석할 수 있다.
이 글은 오디오 매니저에서 오디오 경쟁 메커니즘에 대한 부분적인 내용과 사용 방식을 분석하고자 한다.
먼저 이 경쟁 메커니즘의 발생 원인을 말씀드리자면 안드로이드 시스템에 많은 오디오 유형이 존재하고 서로 독립된 존재를 유지하며 서로 영향을 주지 않기 때문입니다.음악 소리, 버튼 터치 소리, 벨 울리는 소리, 통화 소리, 블루투스 통화 소리, 오류 경보 소리 등등.응답하는 소리 유형이 있습니다.따라서 그들 사이에도 재생을 제어하기 위한 독립된 오디오 흐름이 있을 것이다.이러한 소리가 서로 영향을 미치는 것을 방지하기 위해 경쟁 메커니즘이 생겼다. 이 메커니즘은 이 부분의 소리의 재생 우선순위가 서로 배척되고 공존하는 등 독립된 관계가 있는지 효과적으로 제어한다. 모든 오디오 흐름은 재생할 때 이 메커니즘을 통해 방송 허가를 받아 상태를 감시하고 관리하기 편리하게 한다.
이런 메커니즘에 있어 핵심 내용은 바로 오디오 초점의 관리이다.
밑에 부분 코드가 붙어요.
         
    /**
     * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
     */
    public static final int AUDIOFOCUS_GAIN = 1;
    /**
     * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
     * amount of time. Examples of temporary changes are the playback of driving directions, or an
     * event notification.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
     */
    public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
    /**
     * Used to indicate a temporary request of audio focus, anticipated to last a short
     * amount of time, and where it is acceptable for other audio applications to keep playing
     * after having lowered their output level (also referred to as "ducking").
     * Examples of temporary changes are the playback of driving directions where playback of music
     * in the background is acceptable.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
     */
    public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
    /**
     * Used to indicate a loss of audio focus of unknown duration.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     */
    public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
    /**
     * Used to indicate a transient loss of audio focus.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     */
    public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
    /**
     * Used to indicate a transient loss of audio focus where the loser of the audio focus can
     * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
     * the new focus owner doesn't require others to be silent.
     * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
     */
    public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
            -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
상술한 코드도android\brameworks\base\media\java\android\media\AudioManager에 존재한다.java에서 먼저 부분적인 정의를 내립니다.
         AUDIOFOCUS_GAIN - 지속적인 초점, 상세한 내용은 주석 부분을 보십시오. 비교적 긴 시간의 오디오를 재생하기 위해 이전의 오디오 초점 사용자는 소리를 멈춰야 합니다.
         AUDIOFOCUS_GAIN_TRANSIENT - 짧은 시간 동안 오디오를 재생하기 위해 순간적인 초점, 이전의 초점 사용자는 소리를 멈춰야 한다.
        AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK - 짧은 오디오를 재생하기 위해 순식간에 초점을 맞추고 이전의 오디오 초점 사용자는 자신의 음량을 낮춰야 한다.
        AUDIOFOCUS_LOSS - 초점을 잃는 것은 지속적인 초점 사용자가 오디오 초점을 잃는 것을 나타낸다.
        AUDIOFOCUS_LOSS_TRANSIENT - 초점을 잃는 것은 순간적인 초점 사용자가 오디오 초점을 잃는 것을 나타낸다.
        AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK - 초점을 잃는 것은 순간적인 초점 사용자가 자신의 음량을 낮추는 초점 사용자가 오디오 초점을 잃는다는 것을 나타낸다.
상기 정의는 오디오 초점을 요청할 때 지정해야 하는 매개 변수입니다. 다음에 오디오 초점의 요청을 계속 해석합니다.
        
    /**
     * A failed focus change request.
     */
    public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
    /**
     * A successful focus change request.
     */
    public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;

    /**
     *  Request audio focus.
     *  Send a request to obtain the audio focus
     *  @param l the listener to be notified of audio focus changes
     *  @param streamType the main audio stream type affected by the focus request
     *  @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
     *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
     *      for the playback of driving directions, or notifications sounds.
     *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
     *      the previous focus owner to keep playing if it ducks its audio output.
     *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
     *      as the playback of a song or a video.
     *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
     */
    public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
        int status = AUDIOFOCUS_REQUEST_FAILED;
        if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK))
        {
            Log.e(TAG, "Invalid duration hint, audio focus request denied");
            return status;
        }
        registerAudioFocusListener(l);
        //TODO protect request by permission check?
        IAudioService service = getService();
        try {
            status = service.requestAudioFocus(streamType, durationHint, mICallBack,
                    mAudioFocusDispatcher, getIdForAudioFocusListener(l),
                    mContext.getPackageName() /* package name */);
        }catch (RemoteException e) {
            Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
        }
        return status;
    }

    /**
     * @hide
     * Used internally by telephony package to request audio focus. Will cause the focus request
     * to be associated with the "voice communication" identifier only used in AudioService
     * to identify this use case.
     * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
     *    the establishment of the call
     * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
     *    media applications resume after a call
     */
    public void requestAudioFocusForCall(int streamType, int durationHint) {
        IAudioService service = getService();
        try {
            service.requestAudioFocus(streamType, durationHint, mICallBack, null,
                    AudioService.IN_VOICE_COMM_FOCUS_ID,
                    "system" /* dump-friendly package name */);
        }catch (RemoteException e) {
            Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
        }
    }

    /**
     * @hide
     * Used internally by telephony package to abandon audio focus, typically after a call or
     * when ringing ends and the call is rejected or not answered.
     * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
     */
    public void abandonAudioFocusForCall() {
        IAudioService service = getService();
        try {
            service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
        } catch (RemoteException e) {
            Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
        }
    }

    /**
     *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
     *  @param l the listener with which focus was requested.
     *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
     */
    public int abandonAudioFocus(OnAudioFocusChangeListener l) {
        int status = AUDIOFOCUS_REQUEST_FAILED;
        unregisterAudioFocusListener(l);
        IAudioService service = getService();
        try {
            status = service.abandonAudioFocus(mAudioFocusDispatcher,
                    getIdForAudioFocusListener(l));
        } catch (RemoteException e) {
            Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
        }
        return status;
    }
위의 코드는 주로 오디오 초점을 요청하고 방출하는 두 가지 조작의 함수를 붙여서 요청 조작에 대해
requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)에는 세 가지 매개변수가 있습니다.
첫 번째 매개 변수: 오디오 초점의 감청을 써야 합니다. 다음과 같습니다.
                              
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 
    } 
  } 
};
두 번째 매개 변수: 첫 번째 편에서 설명한 STREAMMUSIC,STREAM_RING,STREAM_SYSTEM 등등.
세 번째 매개 변수: 이 매개 변수는 이 편이 시작되었을 때 열거한 세 번째 오디오 초점 유형입니다.
요청 함수가 성공하면 AUDIOFOCUSREQUEST_GRANTED가 실패하면 AUDIOFOCUS 로 돌아갑니다.REQUEST_FAILED
요청 방법은 다음과 같습니다.
      
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. 
   } 
이 성공적으로 되돌아오면 우리가 재생해야 할 오디오 흐름을 재생할 수 있습니다.그러나 재생이 끝난 후에 abandon Audio Focus () 를 호출해서 오디오 초점을 맞추고 로그아웃해야 합니다
     AudioManager.OnAudioFocusChangeListener.이렇게 하면 프로그램이 오디오 초점을 풀면 중단된 다른 프로그램들은 초점을 가져와서 계속 재생할 수 있습니다.아래와 같이 하면 된다
     
   // Abandon audio focus when playback complete 
   am.abandonAudioFocus(afChangeListener); 
앞에서 오디오 초점의 유형을 소개했을 때 짧은 순간의 오디오 초점에 대해 두 가지를 언급했다. 하나는 초점을 잃을 때 멈추는 것이고, 다른 하나는 초점을 잃을 때 자체 재생 음량을 낮추는 것이다.이 두 가지 용도는 주로 두 가지 오디오 흐름이 공존할 수 있는지, 그리고 그 다음의 구분이 있는지에 있다.
       AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK와 같은 순간적인 오디오 초점은 짧은 경고류, 방송류의 오디오 흐름, 예를 들어 내비게이션 소리, 제시어 등에 적합하다.
매번 이런 오디오 초점이 다른 프로그램에 요청될 때마다 감청에서 알림을 받기 때문에 우리는 해당하는 조작을 할 수 있다.
예를 들어, AUDIOFOCUS를 받았을 때LOSS_TRANSIENT 같은 소식은 우리가 잠시 오디오 초점을 잃었을 뿐입니다. 다른 쪽에서 오디오 초점을 사용하면 이 프로그램은 오디오 초점을 다시 얻고 오디오 흐름을 계속 재생할 수 있습니다.따라서 우리는 이 소식을 받을 때 현재 소리를 멈추고 AUDIOFOCUS를 받을 때까지 기다려야 한다GAIN 같은 메시지가 재생될 때 재생을 다시 시작합니다.
저희가 AUDIOFOCUS를 받았을 때...LOSS 이후에는 오디오 포커스를 다시 가져오지 못할 수도 있고 다른 프로그램이 오디오 포커스를 오래 차지할 수도 있습니다.이 때 우리는 오디오 스트리밍을 멈추고 오디오 초점의 감청을 멈추고 모든 미디어 단추 감청기를 취소해야 한다.이 때는 프로그램을 백그라운드로 돌려 이 프로그램을 멈추는 셈이다.재복구가 필요한 경우 애플리케이션을 다시 열어야 합니다.
저희가 AUDIOFOCUS를 받았을 때...LOSS_TRANSIENT_CAN_DUCK 이 소식은 저희가 자신의 오디오 재생 음량을 일정한 수치로 줄여야 합니다. AUDIOFOCUS를 다시 한 번 들으면GAIN에서는 사운드를 이전 수치로 다시 복원하면 됩니다.
상술한 해석은 전체 오디오 초점의 요청, 방출, 감청의 조작 절차이다.구체적인 상황은 응용에서 실제 상황에 따라 선택하여 더욱 좋은 체험을 해야 한다.또한 멀티미디어 버튼인 미디어 버턴에 대한 조작 감청은 원본에 언급되어 있으니 알고 싶은 것은 알아볼 수 있다.
이로써 내가 이해한 일부 오디오 제어 원본은 여기까지입니다. 잘못된 것이 있으면 알려 주십시오.

좋은 웹페이지 즐겨찾기