что значит отключен фокус аудио
Русские Блоги
Два или более приложения Android могут одновременно воспроизводить звук в один и тот же выходной поток. Система все перемешивает. Хотя это технически впечатляет, пользователей это очень раздражает. Чтобы избежать одновременного воспроизведения всех музыкальных приложений, в Android введена концепция фокусировки звука. Только одно приложение может фокусировать звук одновременно.
Когда вашему приложению требуется вывод звука, оно должно запрашивать фокус звука. Когда он находится в фокусе, он может воспроизводить звук. Однако после фокусировки звука вы не сможете удерживать его, пока не закончите воспроизведение. Другое приложение может запросить фокус, и это вытеснит ваш аудио фокус. В этом случае ваше приложение должно приостановить воспроизведение или уменьшить громкость, чтобы пользователям было легче услышать новый источник звука.
Аудио ориентировано на сотрудничество. Приложениям рекомендуется следовать рекомендациям по аудиофокусу, но система не применяет эти правила. Если приложение хочет продолжить громкое воспроизведение после потери фокуса звука, ничто не может его остановить. Это плохой опыт, и пользователи, скорее всего, удалят приложения, у которых такой плохой опыт.
Хорошо работающее звуковое приложение должно управлять звуковым фокусом в соответствии со следующими общими рекомендациями:
Обработка аудиофокуса различается в зависимости от версии Android:
Аудио фокус на Android 8.0 и выше
Начиная с Android 8.0 (уровень API 26), когда вы вызываете requestAudioFocus (), вы должны предоставить параметр AudioFocusRequest. Чтобы освободить аудиофокус, вызовите метод AbandonAudioFocusRequest (), который также принимает AudioFocusRequest в качестве параметра. При запросе и отказе от фокуса следует использовать один и тот же экземпляр AudioFocusRequest.
Чтобы создать AudioFocusRequest, используйте AudioFocusRequest. Builder. Поскольку запрос фокуса всегда должен указывать запрошенный тип, этот тип включается в конструктор конструктора. Используйте метод построителя, чтобы задать другие поля запроса.
нужно FocusGain Поля; все остальные поля необязательны. Объясните основной метод:
audioattributes описывает варианты использования системных приложений. Когда приложение получает или теряет фокус звука, система будет смотреть на них. Атрибуты заменяют концепцию типов потоков. В Android 8.0 (уровень API 26) и выше любая операция, кроме регулировки громкости, не поддерживает тип потока. Используйте те же атрибуты в запросе фокуса, что и в аудиоплеере (как показано в таблице ниже).
Используйте одинAudioAttributes.BuilderСначала укажите атрибуты, а затем используйте этот метод для назначения атрибутов запросу.
Если не указано, AudioAttributes по умолчанию AudioAttributes.USAGE_MEDIA 。
Когда другое приложение запрашивает использование AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK При выполнении обработки фокуса сфокусированное приложение обычно не получает обратный вызов onAudioFocusChange (), потому что система может выполнить эту операцию сама. Если вам нужно приостановить воспроизведение вместо уменьшения громкости, вызовите setWillPauseWhenDucked (true), создайте и установите OnAudioFocusChangeListener, как описано в разделе «Автоматическое приглушение» ниже.
Когда фокус заблокирован другим приложением, запрос аудиофокуса может завершиться ошибкой. Этот метод допускает отложенное усиление фокуса: возможность асинхронного получения фокуса, когда фокус доступен.
Обратите внимание, что усиление с задержкой фокуса допустимо только при указании AudioManager.OnAudioFocusChangeListener. Поскольку ваше приложение должно получить обратный вызов, чтобы знать, что фокус был разрешен для получения.
OnAudioFocusChangeListener требуется только тогда, когда в запросе указано willPauseWhenDucked (true) или setAcceptsDelayedFocusGain (true).
В следующем примере показано, как использовать AudioFocusRequest.Bulder для создания AudioFocusRequest и запроса и отказа от фокуса звука:
Автоматическое ныряние
В Android 8.0 (уровень API 26), когда другое приложение использует AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK При запросе фокуса система может снизить громкость и возобновить воспроизведение звука, не вызывая приложение onAudioFocusChange() Перезвонить.
В приложениях для воспроизведения музыки и видео автоматическое уменьшение громкости является приемлемым поведением, но бесполезно при воспроизведении голосового содержимого (например, в приложении аудиокниги). В этом случае приложение следует приостановить.
Задержка в фокусе
Чтобы обрабатывать задержанное усиление фокуса, вы должны создать OnAudioFocusChangeListener, который использует метод обратного вызова onAudioFocusChange () для достижения желаемого поведения и зарегистрировать слушателя, вызвав setOnAudioFocusChangeListener ().
До Android 8.0 аудио фокус
Когда вы вызываете requestAudioFocus (), вы должны указать подсказку продолжительности, которая может использоваться другим приложением, которое в данный момент сфокусировано и воспроизводит:
Если вы планируете воспроизводить звук в обозримом будущем (например, при воспроизведении музыки), запросите постоянный звуковой фокус (AUDIOFOCUS_GAIN), и вы хотите, чтобы предыдущий держатель звукового фокуса прекратил воспроизведение.
Запросите временный фокус (AUDIOFOCUS_GAIN_TRANSIENT), если вы хотите воспроизводить звук только в течение короткого времени и хотите, чтобы предыдущий владелец приостановил воспроизведение.
Запросите переходный фокус приглушения (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK), чтобы указать, что вы хотите воспроизводить звук только в течение короткого периода времени, и если предыдущий владелец фокуса «пригнул» (опустил) свой аудиовыход, вы все равно можете продолжить воспроизведение. Оба аудиовыхода микшируются в аудиопоток. Ducking особенно подходит для приложений, которые периодически используют аудиопотоки, например, для звуковых дорожек.
Для метода requestAudioFocus () также требуется AudioManager.OnAudioFocusChangeListener. Этот слушатель должен быть создан в том же действии или службе, что и ваш медиа-сеанс. Он реализует обратный вызов onAudioFocusChange (), и ваше приложение получит этот обратный вызов, когда другие приложения получат или откажутся от аудио-фокуса.
Следующий фрагмент кода запрашивает постоянный фокус аудио на потоке STREAM_MUSIC и регистрирует OnAudioFocusChangeListener для обработки последующих изменений в фокусе звука. (ПодРеакция на изменение звукового фокусаЧасть обсуждает смену слушателей. )
Когда вы закончите играть, вызовите AbandonAudioFocus ().
Это уведомит систему о том, что вам больше не нужен фокус, и отменит регистрацию связанного OnAudioFocusChangeListener. Если вы запрашиваете временный фокус, это уведомит приостановленное или приглушенное приложение, что оно может продолжить воспроизведение или возобновить громкость.
Реакция на изменение звукового фокуса
Когда приложение получает звуковой фокус, оно должно иметь возможность освободить его, когда другое приложение запрашивает собственный звуковой фокус. Когда это происходит, ваше приложение получает вызов метода onAudioFocusChange () в AudioFocusChangeListener, который был указан при вызове requestAudioFocus ().
Параметр focusChange, переданный в onAudioFocusChange (), указывает на происходящее изменение. Он соответствует подсказке продолжительности, используемой приложением для получения фокуса. Ваше приложение должно ответить соответствующим образом.
Переходный не в фокусе
Если изменение фокуса временное (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK или AUDIOFOCUS_LOSS_TRANSIENT), приложение должно уменьшить громкость (если вы не полагаетесь на автоматическое приглушение) или приостановить воспроизведение, но сохранить то же состояние другими способами.
Во время временной потери фокуса звука вы должны продолжать отслеживать изменения в фокусе звука и подготовиться к возобновлению обычного воспроизведения после восстановления фокуса. Когда блокирующее приложение теряет фокус, вы получите обратный вызов ( AUDIOFOCUS_GAIN ). На этом этапе вы можете восстановить нормальный уровень громкости или возобновить воспроизведение.
Постоянная потеря внимания
Если потеря фокуса звука необратима ( AUDIOFOCUS_LOSS ), другое приложение воспроизводит звук. Ваше приложение должно немедленно приостановить воспроизведение, потому что оно никогда не получит AUDIOFOCUS_GAIN Перезвонить. Чтобы возобновить воспроизведение, пользователь должен предпринять явные действия, например нажать элемент управления воспроизведением в уведомлении или пользовательском интерфейсе приложения.
Следующий фрагмент кода демонстрирует, как реализовать OnAudioFocusChangeListener и его обратный вызов onAudioFocusChange (). Обратите внимание, что обработчик используется для задержки выполнения обратного вызова операции остановки, когда звуковой фокус теряется навсегда.
Обработчик использует Runnable, как показано ниже.
Режим фокусировки не работает на iOS 15? 8 быстрых исправлений
В iOS 15 Apple представила новую функцию под названием Focus, которая позволяет вам определять приоритеты ваших уведомлений на iPhone — от кого и когда вы их получаете. Однако что произойдет, если это не сработает так, как вы планировали? Если нежелательные уведомления все еще приходят, или наоборот. Вот несколько быстрых исправлений, чтобы обеспечить правильную работу режима фокусировки на вашем iPhone.
1. Отключите разделение фокуса на разных устройствах.
Экосистема Apple связывает каждое устройство, работающее с одной учетной записью iCloud. Таким образом, если вы включите определенный режим фокусировки на одном из устройств, он автоматически отразится на всех других устройствах Apple, на которых выполнен вход с той же учетной записью iCloud.
Это может быть причиной проблем с режимом фокусировки. Чтобы отключить совместное использование фокуса на других устройствах:
Вот и все! Теперь режим Focus этого устройства не будет синхронизироваться с другими вашими устройствами Apple. Если это не помогло, переходите к следующему исправлению!
2. Проверьте приложения и контакты из белого списка.
Хотя в режиме фокусировки уведомления не отвлекают вас, есть вероятность, что нежелательное приложение или контакт могли быть внесены в белый список. В таком случае Focus их не будет беспокоить, и они смогут отправлять уведомления в любое время. Чтобы проверить приложения и контакты из белого списка:
Это все! Соответствующее приложение или контакт будут удалены из белого списка и больше не будут обходить Focus.
3. Отключите своевременные уведомления.
В Focus Apple внедрила новую технологию машинного обучения для распознавания уведомлений, чувствительных ко времени и предназначенных для немедленной доставки. Сюда могут входить напоминания, одноразовые пароли, службы экстренной помощи и другие оповещения от основных приложений. Однако, если они вас раздражают, отключите их, выполнив следующие действия:
Теперь чувствительные ко времени уведомления больше не будут обходить ваш режим фокусировки.
4. Отключите повторные звонки.
Повторные звонки от любого контакта могут быть одной из основных причин, из-за которых может показаться, что ваш режим фокусировки не работает:
Вот и все! Теперь ваш Focus не обойдется без повторных звонков.
5. Обеспечьте правильное расписание.
Если вы используете запланированные режимы фокусировки, запланированное время могло быть неправильно истолковано. В этом случае проверьте запланированное время, чтобы убедиться, что оно установлено в нужное время.
Если все в порядке, отключите Focus и снова включите его. Теперь он должен работать! Если этого не произойдет, не паникуйте. У нас есть еще много хитростей в рукаве. Продолжай читать!
6. Отключите бесшумный переключатель.
Есть вероятность, что переключатель беззвучного режима на стороне iPhone может быть включен, что приведет к пропущенным уведомлениям. Следовательно, отключите его, если еще не сделали.
7. Перезагрузите iPhone.
Если ничего не помогает, перезагрузите устройство. Хотя это самое простое решение, оно обычно является наиболее эффективным для исправления мелких сбоев. Следовательно, возможно, сейчас самое время перезагрузить iPhone, прежде чем переходить к самому экстремальному шагу.
8. Сбросить все настройки.
Если ни одно из вышеперечисленных исправлений не помогло решить проблему, вам следует подумать о перезагрузке вашего iPhone. Он очистит iPhone от любых распространенных ошибок. Чтобы сбросить настройки iPhone:
Вот так! Я надеюсь, что эти исправления вернут работу Focus на вашем iPhone. Если это не так, ознакомьтесь с нижеприведенными наиболее часто задаваемыми вопросами.
В. Почему мне до сих пор звонят некоторые люди?
Возможно, вы разрешили звонки из избранного при настройке Focus. Чтобы исправить это, коснитесь желаемого режима фокусировки в разделе «Настройки»> нажмите «Люди» в разделе РАЗРЕШЕННОЕ УВЕДОМЛЕНИЕ> сейчас, нажмите «Звонки от» и выберите «Никто».
В. Как включить режим фокусировки?
Вы можете включить режим фокусировки прямо из Центра управления. Кроме того, вы также можете включить его, зайдя в «Настройки» → «Фокус».
В. Почему не включен режим фокусировки, когда он должен быть?
Если вы запланировали Фокус, дважды проверьте время и уважаемые дни, для которых он должен быть включен. Если все в порядке, попробуйте вручную выключить и снова включить нужный режим фокусировки, чтобы проверить, работает ли он, поскольку это может быть сбой.
Аудиофокус — управление доступом к звуковой подсистеме
Это перевод статьи Respecting Audio Focus Kristan Uccello, Google Developer Relations
Считается грубым перебивать во время доклада, это показывает неуважение к докладчику и раздражает аудиторию. Если ваше приложение не учитывает правила работы с аудиофокусом, значит, оно не уважает остальные приложения и раздражает пользователя. Если Вы никогда не слышали об аудиофокусе, стоит обратить внимание на документацию Android developer training material.
Когда несколько приложений могут воспроизводить аудио важно думать о том, как они будут взаимодействовать. Чтобы избежать ситуации когда все плееры играют одновременно Андроид использует понятие аудиофокуса для контроля воспроизведения звуков: ваше приложение должно воспроизводить аудио только тогда, когда оно получило аудиофокус. В этой статье описаны несколько советов о том, как правильно и наилучшим для пользователя образом обрабатывать изменения состояния аудиофокуса.
Запрос аудиофокуса
Не надо быть жадным и запрашивать аудиофокус прямо в момент старта приложения; лучше подождать, пока приложение не начнет что-то делать с аудиопотоком. При получении аудиофокуса через сервис AudioManager, можно воспользоваться константами AUDIOFOCUS_GAIN* для обозначения необходимого режима фокуса.
В примере мы запрашиваем постоянный аудиофокус. Вместо этого, мы могли бы запросить временный (AUDIOFOCUS_GAIN_TRANSIENT) фокус, который подходит для воспроизведения звуков длительностью до 45 секунд.
Еще приложение может использовать режим “крякания” (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) для ситуаций, когда допустимо совместное использование аудиоподсистемы вместе с другими приложениями (например, для фразы “жги еще” в фитнес-приложении, ожидая, что фоновая музыка не будет прерываться). Приложение, запрашивающее фокус в режиме “крякания”, не должно использовать аудиоподсистему дольше 15 секунд подряд.
Обрабатываем изменения состояния аудиофокуса
Для обработки событий изменения состояния аудиофокуса приложение должно создать экземпляр OnAudioFocusChangeListener. В этом обработчике необходимо обработать события AUDIOFOCUS_GAIN* и AUDIOFOCUS_LOSS*. Стоит заметить, что событие AUDIOFOCUS_GAIN имеет несколько особенностей, описанных во втором примере.
Константа AUDIOFOCUS_GAIN используется в коде в двух различных ролях. Во-первых, для получения аудиофокуса как в примере 1. При этом не происходит событие обработчика OnAudioFocusChangeListener, то есть при успешном запросе (и получении) аудиофокуса обработчик НЕ получит соответствующее событие AUDIOFOCUS_GAIN.
AUDIOFOCUS_GAIN также используется в реализации OnAudioFocusChangeListener как вариант события. Как указано ранее, событие AUDIOFOCUS_GAIN не возбуждается при запросе аудиофокуса. Напротив, оно может произойти только после возникновения соответствующего события AUDIOFOCUS_LOSS*. AUDIOFOCUS_GAIN — единственная константа, которая используется в обеих ситуациях.
Существуют четыре ситуации, которые необходимо учитывать в обработчике события изменения состояния аудиофокуса. Когда приложение получает событие AUDIOFOCUS_LOSS, это обычно означает, что обратно аудиофокус оно не получит. В этом случае приложение должно освободить ресурсы, связанные с аудиоподсистемой, и остановить воспроизведение. В качестве примера, представьте, что пользователь слушает музыку через ваше приложение, а затем запускает игру, которая забирает аудиофокус у аудиоплеера. Невозможно предсказать, через сколько времени пользователь закроет игру. Скорее всего, он перейдет на главный экран (оставив игру в фоне) и запустит еще одно приложение. Или он вернется в аудиоплеер, возобновив его работу, что потребует нового запроса аудиофокуса в onResume.
Однако есть другой случай, достойный обсуждения. Существует разница между потерей аудиофокуса навсегда (как в примере выше) или временно. Когда приложение получает событие AUDIOFOCUS_LOSS_TRANSIENT, ожидается, что приложение приостановит использование аудио до тех пор, пока оно не получит событие AUDIOFOCUS_GAIN. Когда возникает событие AUDIOFOCUS_LOSS_TRANSIENT приложение должно запомнить, что потеря фокуса временная, для того, чтобы при возврате фокуса разобраться, какое поведение корректно. (см. пример 2).
Иногда приложение теряет аудиофокус (т.е. получает AUDIOFOCUS_LOSS), а прервавшее приложение завершается, или каким-то другим образом теряет аудиофокус. В этой ситуации последнее приложение, которое имело аудиофокус, может получить событие AUDIOFOCUS_GAIN.
В последующем событии AUDIOFOCUS_GAIN приложение должно понять, получило ли оно аудиофокус после временной потери и должно просто возобновить проигрывание, либо восстановиться и настроить воспроизведение после полной потери фокуса.
Если приложение использует аудио только на короткое время (не более 45 секунд), оно должно запрашивать аудиофокус в режиме AUDIOFOCUS_GAIN_TRANSIENT и отпускать его сразу после завершения воспроизведения или записи звука. Аудиофокус в системе обрабатывается как стек: фокус получает то приложение, которое владело им последним.
Когда аудиофокус получен, самое время создать MediaPlayer или MediaRecorder и зарезервировать ресурсы. Также когда приложение получает AUDIOFOCUS_LOSS, хорошей практикой является освобождение всех зарезервированных ресурсов. Существует три варианта получения аудиофокуса, соответствующие разным вариантам потери фокуса. Неплохо бы явно обрабатывать все варианты потери фокуса в обработчике OnAudioFocusChangeListener.
Таблица 1. Смысл констант получения и потери аудиофокуса
GAIN | LOSS |
AUDIOFOCUS_GAIN | AUDIOFOCUS_LOSS |
AUDIOFOCUS_GAIN_TRANSIENT (*) | AUDIOFOCUS_LOSS_TRANSIENT |
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK (*) | AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK |
Замечание: константа используется в двух местах. Когда запрашивается аудиофокус, она передается как подсказка AudioManager; она же используется как вариант события в OnAudioFocusChangeListener. Константы получения фокуса, обозначенные (*), используются только при запросе аудиофокуса. Константы потери фокуса используются только в обработчике OnAudioFocusChangeListener.
Таблица 2. Типы аудиопотоков.
Тип | Описание |
STREAM_ALARM | Будильник |
STREAM_DTMF | Тоновый набор |
STREAM_MUSIC | Воспроизведение мультимедиа (музыка, подкасты, видео) |
STREAM_NOTIFICATION | Уведомления |
STREAM_RING | Телефонный звонок |
STREAM_SYSTEM | Системные звуки |
Приложение запрашивает аудиофокус у AudioManager (как в примере по ссылке в конце статьи). Параметрами являются необязательный обработчик, подсказка с типом аудиоканала (таблица 2) и тип аудиофокуса из таблицы 1. Любая инициализация аудио должна производиться, только если система разрешила получение аудиофокуса (AudioManager.AUDIOFOCUS_REQUEST_GRANTED).
Замечание: Если происходит телефонный разговор, система не разрешит получение аудиофокуса (AUDIOFOCUS_REQUEST_FAILED) и не отправит приложению событие AUDIOFOCUS_GAIN после завершения звонка.
Краткое описание реакции приложения на события OnAudioFocusChange() описано в таблице 3.
В случае потери аудиофокуса необходимо быть уверенным, что фокус потерян окончательно. Если приложение получает событие AUDIOFOCUS_LOSS_TRANSIENT или AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, оно может придержать зарезервированные ресурсы (не вызывать release()), т.к. скорее всего скоро произойдет новое событие изменения аудиофокуса. Стоит сохранять информацию о временной потере фокуса в каком-нибудь флаге или путем перехода в отдельную вершину графа состояний.
Если приложение запрашивало постоянный аудиофокус в режиме AUDIOFOCUS_GAIN и получило событие AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, подходящей реакцией будет сделать громкость потише (не забыв сохранить старое значение громкости) и затем вернуть громкость при получении события AUDIOFOCUS_GAIN (см. картинку).
Таблица 3. Реакция приложения при изменении состояния аудиофокуса.
Тип смены фокуса | Реакция |
AUDIOFOCUS_GAIN | Событие получения после события потери фокуса: Возобновить воспроизведение медиа, если состояние приложения не противоречат этому. Например, пользователь нажал паузу до события потери фокуса. |
AUDIOFOCUS_LOSS | Остановить воспроизведение, освободить ресурсы |
AUDIOFOCUS_LOSS_TRANSIENT | Приостановить воспроизведение и сохранить флажок о том, что потеря фокуса временная, для того, чтобы при обработке AUDIOFOCUS_GAIN можно было при необходимости возобновить воспроизведение. Не освобождать ресурсы. |
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK | Сделать громкость тише или приостановить воспроизведение, не забывая отслеживать состояние как в случае с AUDIOFOCUS_LOSS_TRANSIENT. Не освобождать ресурсы. |
Заключение и что почитать
Как включить аудио фокус на телефоне
Класс AudioManager предназначен для управления громкостью звука и телефонных мелодий. При разработке приложений, связанных с музыкой или чем-то подобным, вам придётся иметь с ним дело.
У класса достаточно большое количество констант и методов, но сам класс прост в использовании.
Пользователи могут слышать звук через встроенный динамик, разъём для проводной гарнитуры, Bluetooth (A2DP аудио). Вы можете через AudioManager определить, куда в настоящее время направляется аудиопоток и выполнить какое-нибудь действие, например, приглушить звук:
Система оповещает через широковещательное намерение ACTION_AUDIO_BECOMING_NOISY о смене источника звука. Зарегистрируйте BroadcastReceiver и прослушивайте нужное намерение.
В некоторых других примерах на сайте также используется AudioManager.
Управление громкостью и воспроизведением
Вы можете управлять громкостью в своём приложении, используя аппаратные или программные средства контроля звука устройства, блютуз-гарнитуры или наушников.
Также вы можете управлять воспроизведением аудиопотока — пауза, стоп и т.д.
Android поддерживает отдельные звуковые потоки для воспроизведения музыки, сигнала будильника, оповещения, входящего звонка, системных звуков, входящего звонка и DTMF тонов. Пользователь может управлять громкостью каждого потока отдельно.
По умолчанию, при нажатии клавиш регулировки громкости, изменяется уровень громкости активного аудиопотока. Если ваше приложение в данный момент не воспроизводит аудио, то клавиши регулировки громкости регулируют громкость мелодии входящего звонка. Если у вас игра или музыкальное приложение, то когда пользователь нажимает клавиши регулировки громкости, он хочет изменять громкость игры или музыки.
Метод setVolumeControlStream() используется для прямого доступа к клавишам регулировки громкости для звукового потока, который вы укажете. Выяснив, какой аудио поток будет использовать приложение, вы должны установить его в качестве выходного звукового потока. Обычно его вызывают в методе onCreate().
С этого момента нажатия клавиш регулировки громкости на устройстве влияют на указанный звуковой поток, когда ваша активность или фрагмент являются видимым.
Кнопки контроля воспроизведения, такие как воспроизведение, «пауза», «стоп», «вперёд» и «назад» доступны на некоторых телефонах и многих проводных или беспроводных гарнитурах. Когда пользователь нажимает одну из этих аппаратных кнопок, система рассылает намерение с действием ACTION_MEDIA_BUTTON.
Чтобы обработать нажатие медиа-кнопки, вам необходимо зарегистрировать BroadcastReceiver в файле манифеста:
Реализация приёмника сама должна извлекать нажатую клавишу, переданную в оповещении. Объект Intent включает в себя ключ EXTRA_KEY_EVENT, класс KeyEvent включает в себя список статических констант KEYCODE_MEDIA_*, который содержит все возможные медиа-кнопки, такие как KEYCODE_MEDIA_PLAY_PAUSE и KEYCODE_MEDIA_NEXT.
Следующий фрагмент показывает, как получить нажатую медиа-кнопку и изменить воспроизведение медиа.
Так как несколько приложений могут обрабатывать нажатия медиа-кнопок, вы должны программно управлять тем, когда ваше приложение должно получать нажатия кнопок. Следующий код может использоваться в вашем приложении для регистрации и отмены регистрации вашего приемника событий от медиа-кнопок с помощью AudioManager.
Как правило, приложения должны отключать приёмники, когда они становятся неактивными или невидимыми. Однако, это не так просто для приложений, воспроизводящих мультимедиа – на самом деле отвечать на нажатия кнопок воспроизведения наиболее важно, когда приложение не видно и, следовательно, не может управляться с экрана пользовательского интерфейса. Лучший подход заключается в регистрации и отмене регистрации приемника событий медиа-кнопок, когда ваше приложение получает и теряет аудиофокус.
Управление аудиофокусом
Чтобы не получилось так, что сразу несколько приложений одновременно проигрывают аудиопоток, система использует аудиофокус для контроля режима воспроизведения аудио. Воспроизводить звук должно только то приложение, которое имеет аудиофокус. Поэтому вы сами должны позаботиться, чтобы ваше приложение запросило аудиофокус, а также уметь определять момент потери аудиофокуса и среагировать соответствующим образом.
Запрос аудиофокуса делается с помощью метода requestAudioFocus(), который возвращает AUDIOFOCUS_REQUEST_GRANTED, если запрос был успешным.
Вы должны указать какой поток вы будете использовать и какой тип аудиофокуса вам требуется — временный (transient) или постоянный (permanent). Запрашивайте временный фокус, если вы предполагаете воспроизводить аудио в течение короткого времени. При воспроизведении музыки предпочтительнее запрашивать постоянный аудиофокус.
Запросим постоянный аудиофокус в музыкальном потоке, прежде чем начать воспроизведение, например, когда пользователь нажимает играть или начинает проигрываться фоновая музыка для перехода на следующий уровень игры.
Когда приложение закончило воспроизведение, необходимо вызвать метод abandonAudioFocus(). Метод уведомит систему о том, что вам больше не требуется аудиофокус и отменит регистрацию связанную с AudioManager.OnAudioFocusChangeListener. В случае отмены временного аудиофокуса, вызов позволит любому прерванному приложению продолжить воспроизведение.
При запросе временного аудиофокуса у вас есть дополнительная опция: активировать приглушение (ducking). Обычно, когда приложение теряет аудиофокус, оно незамедлительно заглушает воспроизведение. Запрашивая временный аудиофокус, который позволяет приглушение, вы говорите другим приложениям, что они могут продолжить воспроизводить аудио с пониженной громкостью, пока фокус не будет им возвращён.
Приглушение подходит для приложений, которые используют аудиопоток с интервалами, например, для воспроизведения указаний при прокладке маршрута проезда.
Ваше приложение может потерять фокус, когда его запросит другое приложение. Обратный вызов метода onAudioFocusChange() слушателя изменений аудиофокуса, который вы зарегистрировали при запросе аудиофокуса, получает параметр, описывающий событие изменения фокуса. В частности, возможные события потери фокуса отражают типы запросов фокуса из предыдущего раздела, постоянная потеря, временная потеря и временная потеря с приглушением.
Вы должны продолжать следить за изменениями фокуса и быть готовым возобновить воспроизведение с того места где оно было приостановлено, как только вы восстановите фокус.
Если потеря аудиофокуса является постоянной, то предполагается, что в настоящее время другое приложение используется для прослушивания аудио и ваше приложение должно эффективно себя закончить.
В следующем листинге, мы приостановим воспроизведение, если потеря аудиофокуса временная и возобновим его, когда вновь получим аудиофокус. Если потеря является постоянной, то она отменяет регистрацию нашего приёмника событий кнопок и прекращает контролировать изменения аудиофокуса.
В случае временной потери аудиофокуса, где разрешается приглушение, вы можете «сделать потише».
В следующем примере мы снижаем громкость медиапроигрывателя, когда он временно теряет аудиофокус, а затем возвращает громкость на прежний уровень, когда фокус возвращается.
Управление микрофоном
Проверить, выключен ли микрофон, можно с помощью метода isMicrophoneMute():
Включить или выключить микрофон можно с помощью метод setMicrophoneMute():
Использование динамиков
Метод isSpeakerphoneOn() позволяет определить, играет ли музыка через динамики.
Переключиться на динамики или отключить их можно через метод setSpeakerphoneOn():
Дополнительное чтение
Режим «Без звука» — управление режимами Обычный, Без звука, Вибрация.
— используем Audio Focus
Наверняка вы замечали, что при прослушивании музыки, если срабатывает уведомление, то на время звучания уведомления звук музыки или прерывается или становится тише. Это можно реализовать с помощью аудио-фокуса.
Попробую сначала объяснить схему движения фокуса на словах. Если рассматривать пример музыки и уведомления, то пусть музыку играет некое приложение_1, а уведомления выдает некое приложение_2. Приложение_1, когда начинает воспроизведение, запрашивает аудио-фокус, получает его и играет музыку. Далее приходит смс или письмо, и приложение_2 хочет воспроизвести звук уведомления. Оно также запрашивает аудио-фокус и получает его. Но при этом система видит, что фокус сейчас у приложения_1. Система сообщает приложению_1, что фокус оно пока что потеряло. Звук уведомления воспроизводится, приложение_2 отдает фокус, а приложению_1 сообщают, что фокус снова его. Когда приложение_1 заканчивает играть музыку, оно отдает фокус. Т.е. приложение должно не только запрашивать фокус при необходимости, но и явно отдавать его, когда он более не нужен. Для этого есть специальные методы, мы их рассмотрим дальше.
Тут еще важно понимать, что эти сообщения от системы к приложениям о том, что фокус потерян/восстановлен являются просто уведомительными. И разработчик приложения сам решает, как он будет это обрабатывать: проигнорит, убавит звук или приостановит воспроизведение. Например, я протестировал два плеера на своем планшете. На одном включил музыку и свернул его, музыка продолжала играть в фоне. В другом плеере я запустил просмотр фильма. В результате я слышал и фильм и музыку. Аудио-фокус позволяет избежать этого.
Можно провести аналогию с человеком. Допустим, какой-то человек громко говорит. Его просят говорить потише, а еще лучше совсем заткнуться, т.к. он мешает остальным и вообще достал, и все хотят послушать другого человека. Вот это и есть потеря аудио-фокуса первым человеком. Но ведь это вовсе не означает, что этот человек тут же замолчит. Ему просто поступило уведомление, что другой человек хочет говорить. И первый человек поступает так, как считает нужным: либо продолжает громко говорить, либо будет говорить потише, либо замолчит. Это остается на его усмотрение, особенно если он наглый, сильный или быстро бегает )
Напишем приложение, в котором реализуем пример с музыкой и звуком. При нажатии на одну кнопку будем запускать проигрывание музыки, а при нажатии на другую – воспроизводить короткий звук. И привяжем к этой схеме аудио-фокус.
Project name: P1281_AudioFocus
Build Target: Android 2.3.3
Application name: AudioFocus
Package name: ru.startandroid.develop.p1281audiofocus
Create Activity: MainActivity
Добавим строки в strings.xml:
Кнопка Music будет запускать музыку, а три другие кнопки – звук. Их три, потому что есть три разных типа фокуса, которые может запросить приложение. Мы протестируем все три.
В папку mnt/sdcard/Music/ поместите какой-нить файл с именем music.mp3. Например, его можно взять здесь. В папку res/raw поместите файл explosion.mp3, например отсюда.
В onCreate мы просто получаем AudioManager. Именно через него мы будем запрашивать фокус.
onClickMusic срабатывает при нажатии кнопки Music. Здесь мы создаем MediaPlayer и даем ему путь к файлу с музыкой. Методом setOnCompletionListener устанавливаем Activity, как получателя уведомления о окончании воспроизведения. Далее идет работа с фокусом. afListenerMusic – это слушатель (реализующий интерфейс OnAudioFocusChangeListener), который будет получать сообщения о потере/восстановлении фокуса. Он является экземпляром класса AFListener, который мы рассмотрим чуть дальше.
Фокус запрашивается с помощью метода requestAudioFocus. На вход необходимо передать:
— слушателя, который будет получать сообщения о фокусе
— тип потока
— тип фокуса
Тип фокуса говорит о том, насколько долго приложение собирается воспроизводить свой звук и насколько важно, чтобы другое приложение при этом замолчало. Всего есть три типа фокуса:
AUDIOFOCUS_GAIN – приложение дает понять, что оно собирается долго воспроизводить свой звук, и текущее воспроизведение должно приостановиться на это время
AUDIOFOCUS_GAIN_TRANSIENT – воспроизведение будет коротким, и текущее воспроизведение должно приостановиться на это время
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK – воспроизведение будет коротким, но текущее воспроизведение может просто на это время убавить звук и продолжать играть
Итак, мы запрашиваем фокус и говорим, что это надолго — AUDIOFOCUS_GAIN. Метод requestAudioFocus возвращает статус:
AUDIOFOCUS_REQUEST_FAILED = 0 – фокус не получен
AUDIOFOCUS_REQUEST_GRANTED = 1 – фокус получен
После того, как получили фокус, стартуем воспроизведение.
Метод onClickSound срабатывает при нажатии на любую из трех кнопок Sound. Здесь мы определяем, какая из трех кнопок была нажата. Тем самым мы в переменную durationHint пишем тип аудио-фокуса, который будем запрашивать. Далее создаем MediaPlayer, который будет воспроизводить наш звук взрыва из папки raw. Присваиваем ему слушателя окончания воспроизведения. Запрашиваем фокус с типом, который определили выше. Стартуем воспроизведение.
Метод onCompletion, срабатывает по окончании воспроизведения. Мы определяем, какой именно MediaPlayer закончил играть и методом abandonAudioFocus сообщаем системе, что больше не претендуем на аудио-фокус. На вход методу передаем того же слушателя, который давали при запросе фокуса.
В onDestroy освобождаем ресурсы и отпускаем фокус.
Класс AFListener реализует интерфейс OnAudioFocusChangeListener и является получателем сообщений о потере/восстановлении фокуса. При создании мы даем ему соответствующий MediaPlayer (позже станет понятно зачем) и текст, который нам понадобится для логов.
Метод onAudioFocusChange получает на вход статус фокуса этого приложения. Тут 4 варианта:
AUDIOFOCUS_LOSS – фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN. Т.е. нам дают понять, что другое приложение собирается воспроизводить что-то долгое и просит нас пока приостановить наше воспроизведение.
AUDIOFOCUS_LOSS_TRANSIENT — фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN_TRANSIENT. Нам дают понять, что другое приложение собирается воспроизводить что-то небольшое и просит нас пока приостановить наше воспроизведение
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK — фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK. Нам дают понять, что другое приложение собирается воспроизводить что-то небольшое, и мы можем просто убавить звук, не приостанавливая воспроизведение
AUDIOFOCUS_GAIN – другое приложение закончило воспроизведение, звук снова наш
Пока что мы просто будем выводить в лог всю эту информацию, чтобы увидеть схему взаимодействия двух приложений с аудио-фокусом.
Все сохраним и запустим приложение. Жмем Music, воспроизведение музыки началось. В логах видим.
Т.е. музыка запросила фокус и получила его (статус = 1).
Жмем Sound G, чтобы воспроизвести звук взрыва и запросить фокус AUDIOFOCUS_GAIN.
Sound request focus, result: 1
Music onAudioFocusChange: AUDIOFOCUS_LOSS
Фокус запрошен и получен взрывом. А музыка получила уведомление о том, что фокус она потеряла (AUDIOFOCUS_LOSS).
Слышим звук взрыва. После того как звук взрыва закончился:
Sound: abandon focus
Music onAudioFocusChange: AUDIOFOCUS_GAIN
Если дождаться, когда закончится музыка увидим такое сообщение.
Music: abandon focus
Музыка отдала фокус.
Как вы заметили, музыка все это время играла и никуда не делась. То, что она теряла фокус – не означает автоматически, что она остановится. Повторюсь, фокус – это только уведомление. А как приложение отреагирует на это уведомление – решать вам, как разработчику.
Т.е. мы увидели как одно приложение запрашивает определенный тип фокуса, а другое приложение видит этот тип и должно принимать соответствующие меры. Кстати о мерах. Давайте кроме логов реализуем и эти меры.
Перепишем метод onAudioFocusChange класса AFListener:
При потерях фокуса AUDIOFOCUS_LOSS и AUDIOFOCUS_LOSS_TRANSIENT ставим паузу. А при AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK – просто уменьшаем громкость. При получении же фокуса (AUDIOFOCUS_GAIN) возобновляем воспроизведение, если оно было приостановлено, и ставим громкость на максимум.
Я выбрал самые простые меры, чтобы не усложнять урок. Но их можно улучшить. Например, при потере фокуса надолго (AUDIOFOCUS_LOSS) можно освобождать ресурсы, и снова создавать MediaPlayer при получении фокуса. Либо можно вообще полностью отдать фокус (abandon), и тогда пользователю надо будет явно вернуться в ваше приложение, чтобы возобновить воспроизведение.
Когда вы запрашиваете фокус, метод requestFocus возвращает вам ответ, получилось захватить фокус или нет. Хелп рекомендует учитывать этот параметр и стартовать воспроизведение только при положительном результате (AUDIOFOCUS_REQUEST_GRANTED). Я, правда, не знаю как тут можно получить отрицательный результат. Если у кого есть соображения на этот счет – пишите на форуме.
На следующем уроке:
— пишем звук с помощью MediaRecorder
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме