Получать аудио через Bluetooth в Android

Я хочу создать приложение для Android, которое может принимать аудиопоток. Я думал об использовании профиля A2DP, но кажется, что Android не поддерживает A2DP-приемник. Похоже, что есть много людей, которые ищут решение этой проблемы. Но как насчет приема обычного битового потока, а затем преобразовать данные в аудио в приложении? Я подумывал получить поток данных PCM или Mp3 через RFCOMM (профиль Bluetooth SPP), а затем воспроизвести его с помощью AudioTrack.

Во-первых, как мне получить бит-поток на моем телефоне Android через RFCOMM? И можно ли получить бит-поток через RFCOMM в качестве потока PCM или Mp3?

Во-вторых, если невозможно получить бит-поток через RFCOMM в качестве PCM или Mp3-потока, как мне преобразовать полученный бит-поток в аудио?

В-третьих, как преобразовать полученные данные в аудио и воспроизводить аудио одновременно, в режиме реального времени? Можно ли использовать onDataReceived?

Чтобы быть ясным, мне не интересно использовать профиль A2DP! Я хочу передавать данные через RFCOMM (профиль Bluetooth SPP). Полученный поток данных будет в PCM или Mp3. Я думал написать собственное приложение, но если кто-нибудь знает о приложении, чтобы решить это, я был бы рад услышать об этом! Я использую Android 2.3 Gingerbread.

/Джонни

Ответ 1

Нет. Попытка написать приложение для Android, которое обрабатывает это, не будет решением. По крайней мере, если вы хотите использовать роль A2DP Sink.

Дело в том, что Android, как вы уже упоминали, не выполняет вызовы API BlueZ (стек bluetooth Android использует до Желе Bean 4.1) относительно возможностей A2DP Sink. Вы должны реализовать их самостоятельно. Я попытаюсь направить вас, поскольку мне также было интересно это сделать в ближайшем прошлом.

Ваш Android-устройство с поддержкой bluetooth рекламирует себя как устройство A2DP source по умолчанию. Сначала вы должны изменить это, поэтому поблизости устройства могут распознать ваше устройство как приемник. Для этого вы должны изменить файл audio.conf (обычно расположенный в /etc/bluetooth/) и убедиться, что существует клавиша Enable и значение Source прикрепляется к этому ключу, поэтому вы получите что-то вроде:

Enable=Source

Перезагрузите, находящиеся поблизости устройства должны теперь распознать ваше устройство как A2DP Sink.

Теперь вам нужно будет взаимодействовать с BlueZ, чтобы реагировать соответствующим образом, когда исходное устройство A2DP начнет передавать аудио на ваш телефон.

Android и BlueZ разговаривают друг с другом через D-BUS. Фактически, Android подключается к каналу DBUS_SYSTEM и слушает каждую рекламу BlueZ, такую ​​как события, файловые дескрипторы...

Я помню, как успешно связал себя, используя собственное приложение к этому каналу d-bus и получил доступ к различным событиям, которые BlueZ публиковал. Это относительно легко достичь с помощью ссылки, BlueZ API доступен здесь. Если вы пойдете так, вам придется создать собственное приложение (C/С++) и скомпилировать его для вашей платформы. Вы должны сделать это, используя Android NDK.

Если вам трудно использовать D-BUS, вы можете попробовать эту библиотеку Java, которую я только что нашел, которая обрабатывает связь с D-BUS для вас: http://jbluez.sourceforge.net/. Я никогда не использовал его, но, на мой взгляд, стоит попробовать.

Что вам действительно нужно сделать, так это узнать, когда исходное устройство A2DP сопряжено с вашим телефоном и когда он начинает передавать музыку. Вы можете получить эти события через D-BUS. Когда кто-то попытается передать музыку, вам нужно сказать BlueZ, что ваше родное приложение будет обрабатывать его. Существует довольно хороший документ, который объясняет поток событий, которые вы должны использовать для этого. Этот документ доступен здесь. Часть, которую вас интересует, приведена на странице 7. Приложение-приемник в данном примере - PulseAudio, но оно также может быть вашим приложением.

BlueZ отправит вам сокет UNIX, когда вы вызовете метод org.bluez.MediaTransport.Acquire. Чтение этого сокета даст вам данные, которые в настоящее время передаются удаленным устройством. Но я помню, что парень, работающий над стеклом BlueZ, сказал, что данные, прочитанные в этом сокете, не являются чистым звуком PCM, а закодированным аудиоконтентом. Данные обычно кодируются в формате под названием SBC (низкополосное кодирование подсетей).

Декодирование SBC не очень сложно, вы можете найти декодер здесь.

Конечным шагом будет пересылка звука PCM в ваши динамики.

Чтобы вы не застряли и чтобы легче протестировать ваше приложение, вы можете использовать двоичный файл D-BUS, который должен быть доступен в вашей системе Android. Он находится в /system/bin.

Быстрые тесты, которые вы можете сделать, прежде чем делать что-либо из вышеизложенного, могут быть:

Получить список устройств:

dbus-send --system --dest = org.bluez --print-reply/ org.bluez.Manager.GetProperties

Возвращает массив адаптеров со своими путями. После того, как у вас есть эти пути, вы можете получить список всех Bluetooth-устройств в паре с вашим адаптером.

Получить сопряженные устройства:

dbus-send --system --print-reply --dest = org.bluez /org/bluez/ {pid}/hci0 org.bluez.Adapter.GetProperties

Это дает вам список спаренных устройств в поле "Устройства".

Как только у вас есть список устройств, соединенных с вашим адаптером Bluetooth, вы можете узнать, подключен ли он к интерфейсу AudioSource.

Получить устройства, подключенные к интерфейсу AudioSource:

dbus-send --system --print-reply --dest = org.bluez /Орг/BlueZ/{PID}/hci0/dev_XX_XX_XX_XX_XX_XX org.bluez.AudioSource.GetProperties org.bluez.Manager.GetProperties

Надеюсь, что это поможет.

Ответ 2

Другая работа вокруг - использование HandsFreeProfile.

в Android, BluetoothHeadset работает над этим. Подождите, пока статус не изменится на BluetoothHeadset.STATE_AUDIO_CONNECTED.

тогда вы можете записывать звук с Bluetooth-гарнитуры.

    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mMediaRecorder.setOutputFile(mFilename);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    mMediaRecorder.start();

Ответ 3

[Irrelevant but works] Этот хак служит только для потоковой передачи mp3 через точку доступа WIFI (я использую его в своем автомобиле, который имеет только вход AUX):

  • Установите приложение AirSong,
  • Включите горячую точку Wi-Fi,
  • Подключите другое устройство к этой точке доступа,
  • Доступ к 192.168.43.1:8088 из браузера устройства и включен.

(интересно, почему "192.168.43.1" только? потому что это шлюз по умолчанию любого устройства, подключенного к Hotspot Android)

Ответ 4

audio.conf, кажется, отсутствует в Android 4.2.2?

Ответ 5

Чтобы получить аудио-поток pcm через rfcomm, вы можете использовать поток кода в качестве пояснения (Чтение аудиофайла на C и пересылка через Bluetooth для воспроизведения на треке Android Audio), с изменением. частота изменения используется при инициализации от 44100 до 22050

AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,22050,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_8BIT,10000, AudioTrack.MODE_STREAM);

Примечание: эта потоковая передача по-прежнему содержит некоторый шум, но ваш

", который получает поток данных PCM через RFCOMM (профиль SPP Bluetooth), а затем воспроизводит его с помощью AudioTrack."

будет работать.