Android и звук: как делать правильно
В статье рассматривается архитектура и API для создания приложений, воспроизводящих музыку. Мы напишем простое приложение, которое будет проигрывать небольшой заранее заданный плейлист, но «по-взрослому» — с использованием официально рекомендуемых практик. Мы применим MediaSession и MediaController для организации единой точки доступа к медиаплееру, и MediaBrowserService для поддержки Android Auto. А также оговорим ряд шагов, которые обязательны, если мы не хотим вызвать ненависти пользователя.
В первом приближении задача выглядит просто: в activity создаем MediaPlayer, при нажатии кнопки Play начинаем воспроизведение, а Stop — останавливаем. Все прекрасно работает ровно до тех пор, пока пользователь не выйдет из activity. Очевидным решением будет перенос MediaPlayer в сервис. Однако теперь у нас встают вопросы организации доступа к плееру из UI. Нам придется реализовать binded-сервис, придумать для него API, который позволил бы управлять плеером и получать от него события. Но это только половина дела: никто, кроме нас, не знает API сервиса, соответственно, наша activity будет единственным средством управления. Пользователю придется зайти в приложение и нажать Pause, если он хочет позвонить. В идеале нам нужен унифицированный способ сообщить Android, что наше приложение является плеером, им можно управлять и что в настоящий момент мы играем такой-то трек из такого-то альбома. Чтобы система со своей стороны подсобила нам с UI. В Lollipop (API 21) был представлен такой механизм в виде классов MediaSession и MediaController. Немногим позже в support library появились их близнецы MediaSessionCompat и MediaControllerCompat.
Следует сразу отметить, что MediaSession не имеет отношения к воспроизведению звука, он только об управлении плеером и его метаданными.
MediaSession
Итак, мы создаем экземпляр MediaSession в сервисе, заполняем его сведениями о нашем плеере, его состоянии и отдаем MediaSession.Callback, в котором определены методы onPlay, onPause, onStop, onSkipToNext и прочие. В эти методы мы помещаем код управления MediaPlayer (в примере воспользуемся ExoPlayer). Наша цель, чтобы события и от аппаратных кнопок, и из окна блокировки, и с часов под Android Wear вызывали эти методы.
Полностью рабочий код доступен на GitHub (ветка master). В статьи приводятся только переработанные выдержки из него.
Для доступа извне к MediaSession требуется токен. Для этого научим сервис его отдавать
и пропишем в манифест
MediaController
Теперь реализуем activity с кнопками управления. Создаем экземпляр MediaController и передаем в конструктор полученный из сервиса токен.
MediaController предоставляет как методы управления плеером play, pause, stop, так и коллбэки onPlaybackStateChanged(PlaybackState state) и onMetadataChanged(MediaMetadata metadata). К одному MediaSession могут подключиться несколько MediaController, таким образом можно легко обеспечить консистентность состояний кнопок во всех окнах.
Наша activity работает, но ведь идея исходно была, чтобы из окна блокировки тоже можно было управлять. И тут мы приходим к важному моменту: в API 21 полностью переделали окно блокировки, теперь там отображаются уведомления и кнопки управления плеером надо делать через уведомления. К этому мы вернемся позже, давайте пока рассмотрим старое окно блокировки.
Как только мы вызываем mediaSession.setActive(true), система магическим образом присоединяется без всяких токенов к MediaSession и показывает кнопки управления на фоне картинки из метаданных.
Однако в силу исторических причин события о нажатии кнопок приходят не напрямую в MediaSession, а в виде бродкастов. Соответственно, нам надо еще подписаться на эти бродкасты и перебросить их в MediaSession.
MediaButtonReceiver
Для этого разработчики Android любезно предлагают нам воспользоваться готовым ресивером MediaButtonReceiver.
Добавим его в манифест
MediaButtonReceiver при получении события ищет в приложении сервис, который также принимает «android.intent.action.MEDIA_BUTTON» и перенаправляет его туда. Поэтому добавим аналогичный интент-фильтр в сервис
Если подходящий сервис не найден или их несколько, будет выброшен IllegalStateException.
Теперь в сервис добавим
Метод handleIntent анализирует коды кнопок из intent и вызывает соответствующие коллбэки в mediaSession. Получилось немного плясок с бубном, но зато почти без написания кода.
На системах с API >= 21 система не использует бродкасты для отправки событий нажатия на кнопки и вместо этого напрямую обращается в MediaSession. Однако, если наш MediaSession неактивен (setActive(false)), его пробудят бродкастом. И для того, чтобы этот механизм работал, надо сообщить MediaSession, в какой ресивер отправлять бродкасты.
Добавим в onCreate сервиса
На системах с API Так это выглядит
Android 4.4
MIUI 8 (базируется на Android 6, то есть теоретически окно блокировки не должно отображать наш трек, но здесь уже сказывается кастомизация MIUI).
Уведомления
Однако, как ранее упоминалось, начиная с API 21 окно блокировки научилось отображать уведомления. И по этому радостному поводу, вышеописанный механизм был выпилен. Так что теперь давайте еще формировать уведомления. Это не только требование современных систем, но и просто удобно, поскольку пользователю не придется выключать и включать экран, чтобы просто нажать паузу. Заодно применим это уведомление для перевода сервиса в foreground-режим.
Нам не придется рисовать кастомное уведомление, поскольку Android предоставляет специальный стиль для плееров — Notification.MediaStyle.
Добавим в сервис два метода
И добавим вызов refreshNotificationAndForegroundStatus(int playbackState) во все коллбэки MediaSession.
Android 4.4
Android 7.1.1
Android Wear
Started service
В принципе у нас уже все работает, но есть засада: наша activity запускает сервис через binding. Соответственно, после того, как activity отцепится от сервиса, он будет уничтожен и музыка остановится. Поэтому нам надо в onPlay добавить
Никакой обработки в onStartCommand не надо, наша цель не дать системе убить сервис после onUnbind.
А в onStop добавить
В случае, если к сервису привязаны клиенты, stopSelf ничего не делает, только взводит флаг, что после onUnbind сервис можно уничтожить. Так что это вполне безопасно.
ACTION_AUDIO_BECOMING_NOISY
Продолжаем полировать сервис. Допустим пользователь слушает музыку в наушниках и выдергивает их. Если эту ситуацию специально не обработать, звук переключится на динамик телефона и его услышат все окружающие. Было бы хорошо в этом случае встать на паузу.
Для этого в Android есть специальный бродкаст AudioManager.ACTION_AUDIO_BECOMING_NOISY.
Добавим в onPlay
В onPause и onStop
И по факту события встаем на паузу
Android Auto
Начиная с API 21 появилась возможность интегрировать телефон с экраном в автомобиле. Для этого необходимо поставить приложение Android Auto и подключить телефон к совместимому автомобилю. На экран автомобиля будет выведены крупные контролы для управления навигацией, сообщениями и музыкой. Давайте предложим Android Auto наше приложение в качестве поставщика музыки.
Если у вас под рукой нет совместимого автомобиля, что, согласитесь, иногда бывает, можно просто запустить приложение и экран самого телефона будет работать в качестве автомобильного.
Исходный код выложен на GitHub (ветка MediaBrowserService).
Прежде всего надо указать в манифесте, что наше приложение совместимо с Android Auto.
Добавим в манифест
Здесь automotive_app_desc — это ссылка на файл automotive_app_desc.xml, который надо создать в папке xml
Преобразуем наш сервис в MediaBrowserService. Его задача, помимо всего ранее сделанного, отдавать токен в Android Auto и предоставлять плейлисты.
Поправим декларацию сервиса в манифесте
Во-первых, теперь наш сервис экспортируется, поскольку к нему будут подсоединяться снаружи.
И, во-вторых, добавлен интент-фильтр android.media.browse.MediaBrowserService.
Меняем родительский класс на MediaBrowserServiceCompat.
Поскольку теперь сервис должен отдавать разные IBinder в зависимости от интента, поправим onBind
Имплементируем два абстрактных метода, возвращающие плейлисты
И, наконец, имплементируем новый коллбэк MediaSession
Здесь mediaId — это тот, который мы отдали в setMediaId в onLoadChildren.
Плейлист
Трек
UPDATE от 27.10.2017: Пример на GitHub переведен на targetSdkVersion=26. Из релевантных теме статьи изменений необходимо отметить следующее:
- android.support.v7.app.NotificationCompat.MediaStyle теперь deprecated. Вместо него следует использовать android.support.v4.media.app.NotificationCompat.MediaStyle. Соответственно, больше нет необходимости использовать android.support.v7.app.NotificationCompat, теперь можно использовать android.support.v4.app.NotificationCompat
- Метод AudioManager.requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) теперь тоже deprecated. Вместо него надо использовать AudioManager.requestAudioFocus(AudioFocusRequest focusRequest). AudioFocusRequest — новый класс, добавленный с API 26, поэтому не забывайте проверять на API level.
Создание AudioFocusRequest выглядит следующим образом
Теперь запрашиваем фокус
Разумеется, все вышеописанные изменения вносить необязательно, старые методы работать не перестали.
Вот мы и добрались до конца. В целом тема эта довольно запутанная. Плюс отличия реализаций на разных API level и у разных производителей. Очень надеюсь, что я ничего не упустил. Но если у вас есть, что исправить и добавить, с удовольствием внесу изменения в статью.
Еще очень рекомендую к просмотру доклад Ian Lake. Доклад от 2015 года, но вполне актуален.
Источник
How To : Play Sound from 2 Apps at Once on Your Samsung Galaxy Phone
On a PC, you can play sound from multiple apps at once. It’s great, but it can also be confusing — there’s a volume slider in each app, then the system-wide one, and probably another knob on your speakers. To avoid this dysfunction, Android only has one sound stream for media. But that has its own problems.
Let’s say you’re keeping an ear on your newborn with a baby monitor app, but you also want to listen to music. Nope, it’s one or the other. Or maybe you’re watching something visually oriented on Netflix or YouTube and you want to give it your own soundtrack with Spotify. Sorry, you’re SOL.
But hey, your Galaxy phone doesn’t just run Android, it runs an OEM skin called One UI that Samsung built on top of Android. Bottom line, what this means is you get extra features like the ability to change Android’s default audio behavior.
Step 1: Install SoundAssistant
Samsung created a wonderful app that works as an extension of your phone’s audio-related settings menus. It’s called SoundAssistant, and among other things, it makes multi-stream audio possible.
So tap the following link from your Galaxy device, then press «Install» to get the app. Alternatively, open the Galaxy Store app from your app drawer, then search for «SoundAssistant» to find and install it.
For those familiar, SoundAssistant is part of the Good Lock family of apps. But unlike some of its siblings, you don’t need the main Good Lock app to use it.
Step 2: Enable Multi-Stream Audio
Now, open SoundAssistant. Scroll down a bit on the main menu and select «MultiSound.» Make sure to tap the text itself rather than the the toggle next to it.
From here, you’ve got a couple of options. First, you could select a single app that will be allowed to continue playing audio in the background even if another app starts playing audio in the foreground. Alternatively, you can enable the toggle next to «All apps» at the top of the screen to turn on true multi-stream audio system-wide.
The first option is better if, for instance, you just want to be able to play songs from your music app while you’re doing other stuff, up to and including watching videos or playing music in other apps.
The second option is a lot more flexible since the feature will work with any combination of apps. Just remember where to find this option, because you may realize that you actually want most apps to stop playing sound automatically when you start playing sound elsewhere.
Keep Your Connection Secure Without a Monthly Bill. Get a lifetime subscription to VPN Unlimited for all your devices with a one-time purchase from the new Gadget Hacks Shop, and watch Hulu or Netflix without regional restrictions, increase security when browsing on public networks, and more.
Источник
Sound devices app android
Краткое описание:
SoundWire позволяет отправлять любую музыку или аудио («что вы слышите сейчас») с Вашего компьютера на Android устройство.
SoundWire lets you send any music or audio («what you hear now») from your Windows or Linux PC to your Android mobile devices, or other PCs. Use it as:
— A wireless extension of your PC-based music system for parties
— A remote headphone amp (wireless headphones)
— A way to listen to music and movies from your computer anywhere in your house or out on your deck.
The full version of SoundWire enables unlimited Opus audio compression, can handle up to 10 connections at the same time, and has no ads or interruptions. It also has a special Pro Mode to set and display buffer latency precisely in milliseconds. You can use any music player on your PC or laptop like Grooveshark, Spotify, YouTube, or iTunes and feed the live sound directly to your Android device. SoundWire lets you listen to the free versions of Grooveshark and Spotify on your phone.
SoundWire has low latency (audio delay), which means it can even be used to listen to the soundtrack of a movie or YouTube video while you watch (**Note you must adjust the buffer size in app settings for low latency). There are other uses too. SoundWire can work as a baby monitor or listening device with a computer such as a netbook that has a built-in microphone. Hook up turntables to your computer’s line input and stream a live DJ set to another part of the house over WiFi, or anywhere else over 3G/4G.
Features
— Live audio capture and streaming to multiple clients
— Not locked to one music player
— Excellent sound quality (44.1 / 48 kHz stereo 16-bit, PCM or Opus compression)
— True low latency (unlike AirPlay, Airfoil)
— Easy to use
— Compression option greatly reduces network usage
— x86 and MIPS support, stream music from PC to PC running virtualized app (Linux/Windows)
— Record SoundWire audio to a file (MP3 or WAV)
Before using SoundWire on your Android device you must install and run the SoundWire Server application on the Windows/Linux PC or laptop which is your source of music, web audio streaming, or other sounds. Download the server at http://georgielabs.net/
These links are also available in the app. If you have any problems please see the troubleshooting tips at the above link. For example if you get choppy audio try restarting your wireless router, then try the other troubleshooting suggestions in the guide. If you get a message saying the app is not licensed and this message is incorrect then please check your internet connection and try again.
Please rate the app and submit comments on Google Play to let us know what you think of SoundWire. If you have a question or bug report send email to [email protected] If reporting a problem please give your phone’s Android version (e.g. 2.3) and make/model. Check the server download page georgielabs.99k.org occasionally for updates.
Permissions
— Network communication: Communicates with the server program on your PC.
— Phone calls: Mutes audio when you receive or make a call. Without this permission music would continue to play, interfering with your call.
— Prevent phone from sleeping: Keeps app running while connected (playing music) or attempting to connect. May be disabled in settings.
Источник