시리즈

[Android][번역] 오디오 인터럽트 다루기

20180314
번역
android
audio
interrupt

원문 : https://medium.com/google-developers/how-to-properly-handle-audio-interruptions-3a13540d18fa (How to _properly_ handle audio interruption)

"적절하게" 오디오 인터럽트를 다루는 방법


당신의 앱이 아무리 좋아도 전화를 받을 때 오디오 재생이 멈추지 않았다면 유저는 싫어할 것이다. 기기는 정말 중요한 것을 재생하도록 내버려 두지 않을 것이므로,  그 유저는 전화를 끊고 나서야 지난 12분간 그 팟캐스트를 놓친 걸 발견하고 무슨 일이 일어났는지도 모를 것이다. 이건 전부 당신의 책임이다.
그러니, 오디오 포커스를 잃을 때는 오디오 재생을 중지하라.  오디오 포커스 문서에서는 한번에 딱 하나만 재생하는 것을 가정하고 있다. 이 뜻은 시스템이 현재 오디오를 재생하고 있고 관심 있는 앱을 추적할 방법이 필요하다는 뜻이다. 오디오 포커스는 소라 고동 역할을 수행함으로써 도움을 준다. — 그것을 잡고 있을 때에는 말을 할 수 있다. 그러나 시스템은 다른 누군가의 차례가 되면 그걸 다시 가져갈 것이다. 
당신의 앱이 음악을 스트리밍하는 상황을 생각해보자. 유저는 대부분의 경우에 방해받지 않고 싶을 것이다.
오디오 포커스는 당신에게 이런 상황들을 알려줄 수 있는 소라 고동입니다!
다행히 이안 레이크의 BabbQ에서의 미디어 재생 대화에 오디오 초점이 상당히 철저하게 파괴되었기 때문에 이것을 확실히 확인해 보세요. 하지만 여기 오디오에 초점을 맞춘 변화에 대응하는 것에 대한 분석이 있습니다.
이안 레이크(Ian Lake) 가 다행히도 오디오 포커스에 대해서 꽤 철저한 명세서를 Media Playback talk at BABBQ에 남겨두었습니다. 꼭 확인해보세요. 하지만 여기에도 오디오 포커스가 변화하는 것에 대응하는 방법이 있습니다.
당신의 앱에 오디오 포커스를 다루기 위해서는 AudioManager 를 이용할 수 있습니다. 어떤 것을 재생할 준비가 됐을 때, 그저 요청(request)하기만 하면 됩니다. (재생이 끝나면 release하는 것을 꼭 기억하세요.)  (역자 주 - requestAudioFocus, abandonAudioFocus)

  오디오 포커스가 인정되면, 소라고둥을 잡고 재생하면 됩니다. 하지만 아까 말한대로 시스템은 일시적이든 영구적이든 오디오 포커스를 다시 가져갈 수 있습니다.  따라서 상태를 계속 파악하고 이런 변화에 대응하기 위해서 OnAudioFocusChangeListener 가 필요합니다! 아마도 그건 이런 모양일 것입니다:
AudioManager.OnAudioFocusChangeListener afChangeListener = 
    new AudioManager.OnAudioFocusChangeListener() {
  public void onAudioFocusChange(int focusChange) {
    if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
      // 오디오 포커스를 일시적으로 빼앗겼기에 재생을 잠깐 멈춥니다.
      // 하지만 곧 돌아올 것입니다.
      // (예시. 통화)
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
      // 오디오 포커스를 잃었기에 재생을 완전히 멈춥니다.
      // (예시. 유저가 다른 오디오 재생 앱을 시작했을 때)
      // Remember to unregister your controls/buttons here.
      // And release the kra — Audio Focus!
      // You’re done.
      am.abandonAudioFocus(afChangeListener);
    } else if (focusChange ==
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
      // 다른 것이 재생되고 있기 때문에 소리를 줄입니다.
      // (예시. 알림 또는 내비게이션의 지시)
      // 오디오 재생에 따라서 멈추는 것이 더 나은 경우도 있습니다.
    } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
      // 재생을 재개합니다, 오디오 포커스를 다시 얻었습니다!
      // (예시. 통화가 끝났을때 또는 내비 지시가 끝났을 때)
      // (만약 ducking과 볼륨을 줄이는 것으로 구현했다면.
      // 여기에서 볼륨을 원래대로 돌려야 합니다.
    }
  }
};
자유롭게 복사하고 붙여넣으세요. 아니면 switch 문으로 바꾸고 인터넷에서 저를 조롱하시면 됩니다. 어떤 방법이든 오디오 포커스를 적절하게 사용하게 될 겁니다!
구 버전 안드로이드는 PhoneStateListener 에 개발자들이 의존하도록 했지만, 롤리팝부터 바뀌었습니다. 롤리팝 이후의 기기에서는, 전화의 상태가 적절하게 오디오 포커스 상태로 통합되었고 당신의 앱은 통화가 시작될 때는 AUDIOFOCUS_LOSS_TRANSIENT , 통화가 끝날 때는 AUDIOFOCUS_GAIN 를 받게 될 겁니다. 바로 잡을 API가 하나 줄었습니다!
도움이 될지는 모르겠지만, 안드로이드 6.0 의 경우에는 LISTEN_CALL_STATE 는 더 이상   READ_PHONE_STATE permission 을 요구하지 않습니다. 하지만 다른 몇몇 전화 옵션들은 permission을 요구합니다. 음악을 정지하기만 하면 전화 사용 허가 여부를 묻는 잘못 쓰여진 코드를 원하지 않을 겁니다. 그건 끔찍합니다 . 
롤리팝 이전의 기기에서도 오디오 포커스를 이용해야 한다는 걸 기억하세요. 전화 상태에만 반응한다는 건 다른 오디오 신호들을 놓치고 있을 지도 모른다는 겁니다. 내비게이션 지시나 다른 앱이 시작되는 경우를 생각해보세요. 당신의 앱은 당신의 유저를 위해 있는 것이지 앱을 삭제할 때까지 유저를 화나게 하라고 있는게 아닙니다.
그러니 미디어 재생을 올바른 방법으로 시도하세요. 오디오 포커스에 따라 사용자에게 원활한 환경을 만들어 주세요. 그래야 더 나은 앱을 만들 수 있습니다.

.

piano (press key Q)

Categories

flutter ( 82 ) dart ( 34 ) android ( 32 ) kotlin ( 11 ) plugin ( 8 ) provider ( 8 ) vim ( 7 ) bloc ( 6 ) iOS ( 6 ) state management ( 6 ) 플러터 ( 6 ) PS ( 5 ) algorithm ( 5 ) architecture ( 5 ) async ( 5 ) getx ( 5 ) java ( 5 ) API ( 4 ) BOJ ( 4 ) class ( 4 ) daily ( 4 ) git ( 4 ) golang ( 4 ) memo ( 4 ) riverpod ( 4 ) state ( 4 ) stream ( 4 ) test ( 4 ) web ( 4 ) widget ( 4 ) windows ( 4 ) HTTP ( 3 ) androidX ( 3 ) app state ( 3 ) context ( 3 ) crash ( 3 ) db ( 3 ) editor ( 3 ) error ( 3 ) extension ( 3 ) github ( 3 ) hive ( 3 ) ide ( 3 ) package ( 3 ) pubspec ( 3 ) python ( 3 ) syntax ( 3 ) vscode ( 3 ) app icon ( 2 ) await ( 2 ) chocolatey ( 2 ) consumer ( 2 ) cp949 ( 2 ) deployment ( 2 ) dev ( 2 ) flavor ( 2 ) gesture ( 2 ) globalkey ( 2 ) go ( 2 ) google ( 2 ) hack ( 2 ) js ( 2 ) json ( 2 ) key ( 2 ) keystore ( 2 ) list ( 2 ) listview ( 2 ) lock ( 2 ) mac ( 2 ) map ( 2 ) navigation ( 2 ) nosql ( 2 ) project ( 2 ) pub ( 2 ) recyclerview ( 2 ) rxdart ( 2 ) sdk ( 2 ) selector ( 2 ) setting ( 2 ) size ( 2 ) soc ( 2 ) synchronized ( 2 ) tdd ( 2 ) tip ( 2 ) version ( 2 ) viewmodel ( 2 ) vundle ( 2 ) webview ( 2 ) xcode ( 2 ) yaml ( 2 ) ( 2 ) 플러터 단점 ( 2 ) 16.0 ( 1 ) 2.0 ( 1 ) 2023 ( 1 ) AATP2 ( 1 ) ChangeNotifierProvider ( 1 ) Example ( 1 ) Guava ( 1 ) ImageReader ( 1 ) Mo's algorithm ( 1 ) OAuth2 ( 1 ) OpenGL ( 1 ) Oreo ( 1 ) ProgressBar ( 1 ) REST API ( 1 ) Trie ( 1 ) activity ( 1 ) adaptive ( 1 ) android P ( 1 ) android context ( 1 ) android11 ( 1 ) apktool2 ( 1 ) app exit ( 1 ) append ( 1 ) appicon ( 1 ) arkit ( 1 ) array ( 1 ) asciidoc ( 1 ) async * ( 1 ) async* ( 1 ) audio ( 1 ) authorization ( 1 ) await for ( 1 ) behaviorsubject ( 1 ) beta ( 1 ) binary ( 1 ) binarysearch ( 1 ) blender ( 1 ) book ( 1 ) bottomsheet ( 1 ) break ( 1 ) broadcast ( 1 ) browser ( 1 ) bubbles ( 1 ) bug ( 1 ) build ( 1 ) buildcontext ( 1 ) buildnumber ( 1 ) bundle ( 1 ) button ( 1 ) bytecode ( 1 ) cache ( 1 ) camera2 ( 1 ) cameramanager ( 1 ) cd ( 1 ) chrome ( 1 ) ci ( 1 ) circle ( 1 ) clean ( 1 ) clean architecture ( 1 ) cli ( 1 ) clip ( 1 ) clipboard ( 1 ) cloud ide ( 1 ) cmdlet ( 1 ) code ( 1 ) coding test ( 1 ) command ( 1 ) comparator ( 1 ) complexity ( 1 ) concurrency ( 1 ) conditional ( 1 ) const ( 1 ) constraint ( 1 ) constraintlayout ( 1 ) controlc ( 1 ) controlv ( 1 ) converter ( 1 ) copy ( 1 ) copy project ( 1 ) coupling ( 1 ) coverage ( 1 ) cp ( 1 ) css ( 1 ) cupertino ( 1 ) cursor ( 1 ) cv ( 1 ) data class ( 1 ) data structure ( 1 ) dataBinding ( 1 ) database ( 1 ) debounce ( 1 ) decompile ( 1 ) delegate ( 1 ) deno ( 1 ) design pattern ( 1 ) development ( 1 ) device ( 1 ) di ( 1 ) dialog ( 1 ) dio ( 1 ) drawable ( 1 ) drug ( 1 ) emmet ( 1 ) encoding ( 1 ) english ( 1 ) entries ( 1 ) environment ( 1 ) equality ( 1 ) equatable ( 1 ) euc-kr ( 1 ) euckr ( 1 ) exit ( 1 ) expand ( 1 ) expanded ( 1 ) export ( 1 ) extension method ( 1 ) facade ( 1 ) fake ( 1 ) field ( 1 ) figma ( 1 ) final ( 1 ) fixed ( 1 ) flutter pub ( 1 ) flutter web ( 1 ) flutter_inappwebview ( 1 ) flutter_test ( 1 ) flutterflow ( 1 ) fold ( 1 ) fonts ( 1 ) form ( 1 ) frame ( 1 ) future ( 1 ) gestureDetector ( 1 ) gestureRecognizer ( 1 ) gesturearena ( 1 ) get-command ( 1 ) get_cli ( 1 ) getbuilder ( 1 ) getx단점 ( 1 ) gitignore ( 1 ) glut ( 1 ) google fonts ( 1 ) gopath ( 1 ) goto ( 1 ) gradient ( 1 ) graphics ( 1 ) gvim ( 1 ) hackaton ( 1 ) hash ( 1 ) hashmap ( 1 ) hot reload ( 1 ) how to ( 1 ) html ( 1 ) i18n ( 1 ) icon ( 1 ) id ( 1 ) impeller ( 1 ) implementation ( 1 ) import ( 1 ) indicator ( 1 ) inkwell ( 1 ) interrupt ( 1 ) intl ( 1 ) introduction ( 1 ) io ( 1 ) isar ( 1 ) iterable ( 1 ) iteration ( 1 ) javascript ( 1 ) julia ( 1 ) juno ( 1 ) jupyter ( 1 ) kakaomap ( 1 ) keytool ( 1 ) korean ( 1 ) kotlin syntax ( 1 ) l10n ( 1 ) lambda ( 1 ) language ( 1 ) layer ( 1 ) layout ( 1 ) lineageOS ( 1 ) localkey ( 1 ) localtoglobal ( 1 ) long list ( 1 ) ls ( 1 ) mac osx ( 1 ) markdown ( 1 ) markup ( 1 ) material ( 1 ) method ( 1 ) microtask ( 1 ) migrate ( 1 ) mintlify ( 1 ) mock ( 1 ) module ( 1 ) monitor ( 1 ) moor ( 1 ) mouse ( 1 ) mouseregion ( 1 ) multiplatform ( 1 ) multiset ( 1 ) multithread ( 1 ) mutable ( 1 ) mvvm ( 1 ) new ( 1 ) node ( 1 ) nodejs ( 1 ) nosuchmethod ( 1 ) null-safety ( 1 ) numberformat ( 1 ) nvim ( 1 ) object ( 1 ) objectbox ( 1 ) objectkey ( 1 ) obx ( 1 ) online ide ( 1 ) operator ( 1 ) orientation ( 1 ) parabeac ( 1 ) parse ( 1 ) paste ( 1 ) path ( 1 ) pattern ( 1 ) pitfall ( 1 ) play store ( 1 ) pod ( 1 ) podfile ( 1 ) pointer ( 1 ) pointers ( 1 ) powershell ( 1 ) private ( 1 ) programming ( 1 ) pull to refresh ( 1 ) puzzle ( 1 ) pycharm ( 1 ) realitykit ( 1 ) recursion ( 1 ) reduce ( 1 ) reference ( 1 ) regex ( 1 ) regular expression ( 1 ) release note ( 1 ) renderbox ( 1 ) renderobject ( 1 ) repl ( 1 ) repository ( 1 ) response ( 1 ) rm ( 1 ) rotue ( 1 ) round ( 1 ) run ( 1 ) scope ( 1 ) scroll ( 1 ) search ( 1 ) server ( 1 ) serverless ( 1 ) service ( 1 ) sharp ( 1 ) singlerepo ( 1 ) singleton ( 1 ) sketch ( 1 ) sliver ( 1 ) sliverlist ( 1 ) snippets ( 1 ) sogae ( 1 ) sorting ( 1 ) source ( 1 ) sparse ( 1 ) sparse array ( 1 ) spec ( 1 ) split ( 1 ) sqflite ( 1 ) sqlite ( 1 ) sqrt decomposition ( 1 ) stateful ( 1 ) statefulwidget ( 1 ) step ( 1 ) stepper ( 1 ) string ( 1 ) stringbuffer ( 1 ) stringbuilder ( 1 ) studio ( 1 ) study ( 1 ) sub-directory ( 1 ) svn ( 1 ) swiftui ( 1 ) swipe to refresh ( 1 ) system_alert_window ( 1 ) system_cache ( 1 ) systemnavigator ( 1 ) tail recursion ( 1 ) tailrec ( 1 ) tap test ( 1 ) text ( 1 ) texteditingcontroller ( 1 ) textfield ( 1 ) texttheme ( 1 ) themedata ( 1 ) then ( 1 ) thread ( 1 ) throttle ( 1 ) time ( 1 ) tool ( 1 ) tools ( 1 ) tooltip ( 1 ) ts ( 1 ) tutorial ( 1 ) typescript ( 1 ) ui ( 1 ) unittest ( 1 ) update ( 1 ) usb ( 1 ) utf8 ( 1 ) ux ( 1 ) valuekey ( 1 ) variable ( 1 ) vector ( 1 ) versioncode ( 1 ) very_good ( 1 ) view ( 1 ) vim plugin ( 1 ) vimrc ( 1 ) virtualenv ( 1 ) wasm ( 1 ) web app ( 1 ) webview_flutter ( 1 ) while ( 1 ) widget tree ( 1 ) window ( 1 ) wsl ( 1 ) yield ( 1 ) 강의 ( 1 ) 개발 ( 1 ) 개발 공부 ( 1 ) 공부법 ( 1 ) 그래픽스 ( 1 ) 꼬리재귀 ( 1 ) 꿀팁 ( 1 ) 데노 ( 1 ) 두줄 ( 1 ) 디노 ( 1 ) 번역 ( 1 ) 블록 ( 1 ) 상태관리 ( 1 ) 실험 ( 1 ) 안드로이드 ( 1 ) 안드로이드프로젝트 ( 1 ) 안드로이드프로젝트복사 ( 1 ) 어이없는 ( 1 ) 조건부 임포트 ( 1 ) 주절주절분노조절실패의식으흐름 ( 1 ) 패키지 ( 1 ) 프로젝트복사 ( 1 ) 플러그인 ( 1 )