Android-сервис останавливает запись звука, когда приложение убито - PullRequest
1 голос
/ 16 октября 2019

Моя проблема немного изменилась, пожалуйста, посмотрите на EDIT 2 ниже

Я учусь работать со Службами и записывать аудио на Android.

Я хочу создать приложение, которое ничего не будет делать, кроме запуска службы: после запроса разрешений (RECORD_AUDIO, INTERNET) приложение вызывает только startService() из MainActivity.

Затем служба будет записывать аудио и передавать его на указанный IP-адрес. Я черпал вдохновение для сервера и клиента потокового аудио из ответов на этот вопрос . Пока я тестирую приложение на Android 6.0 в эмуляторе Android Studio.

Это метод onStartCommand() моего служения. Я создаю новый поток, в котором я жду, пока пользователь не нажмет «Разрешить» в диалоговом окне запроса разрешений. Когда я получаю разрешения, я инициализирую AudioRecord, а затем читаю из него в while -цикле и отправляю данные.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Thread streamThread = new Thread(new Runnable() {

        @Override
        public void run() {
            waitForPermissions();
            try {
                DatagramSocket socket = new DatagramSocket();
                byte[] buffer = new byte[minBufSize];
                DatagramPacket packet;
                final InetAddress destination = InetAddress.getByName(address);
                recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, minBufSize * 10);
                recorder.startRecording();
                while (status == true) {
                    minBufSize = recorder.read(buffer, 0, buffer.length);
                    packet = new DatagramPacket(buffer, buffer.length, destination, port);
                    socket.send(packet);
                }
            } catch (...) {...}
        }
    });
    streamThread.start();
    return START_STICKY;
}

В onDestroy() Я устанавливаю флаг statusдо false, чтобы цикл в потоке, созданном в onStartCommand(), завершился. Затем я отпускаю recorder, чтобы его можно было инициализировать и использовать снова.

@Override      
public void onDestroy(){
    status = false;
    recorder.stop();
    recorder.release();
    super.onDestroy();
}

Это приложение работает только частично:

  • Когда я запускаю сервер прослушивания накомпьютер и приложение в эмуляторе, я слышу звук нормально.
  • Когда я сворачиваю приложение (нажмите кнопку «Домой»), аудиопоток все еще в порядке.
  • Моя проблема в том, , что когда я убиваю приложение (проведите пальцем по экрану прямо на экране запущенных приложений), звук останавливается. В Logcat я вижу, что служба была перезапущена и работает как обычно (инициализирует AudioRecord и все, без исключений), только я ничего не слышу. Когда я снова запускаю приложение (и, следовательно, снова вызываю startService()), в Logcat я вижу исключение, сообщающее, что запуск AudioRecord завершился неудачно с кодом ошибки -38 (что означает, что предыдущий микрофон использовался предыдущим). экземпляр службы).

Что я тут не так делаю? Почему служба работает, но звук не воспроизводится, когда я убиваю приложение?

Большое спасибо за ваши ответы.

РЕДАКТИРОВАТЬ:

Я знаюэтот подход не будет работать на более новых версиях Android. Это приложение предназначено только для личных целей и будет работать на одном из моих старых телефонов с Android 5.1.1 или 6.0.

После прочтения статьи в этот ответ Я переместил чторанее был в onDestroy до onTaskRemoved. Однако ничего не изменилось.

Служба, по-видимому, все еще отправляет некоторые пакеты после перезапуска. Я посмотрел на них в Wireshark, и пакеты все еще покидают устройство, а Сервер все еще принимает их. Полезная нагрузка пакетов отлична от нуля, уникальна для каждого пакета.

РЕДАКТИРОВАТЬ 2:

Я изменил размер буфера на AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 10 в приложении для Android и AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 20 в приложении на сервере. Теперь, когда я смахиваю приложение, Service перезагружается, и затем я слышу звук. Но после перезапуска звук очень громоздкий, и я не знаю почему. Кроме того, он становится громоздким, когда я удаляю приложение, поддерживаю работу сервера, а затем снова устанавливаю и запускаю приложение.

Так что проблема, вероятно, на стороне сервера. В чем может быть проблема с сервером? Я правильно работаю с SourceDataLine? Код сервера выглядит следующим образом (взято из здесь ):

...
static int sampleRate = 8000;
static int bufferLen = minBufSize * 20;

public static void main(String args[]) throws Exception {

    DatagramSocket serverSocket = new DatagramSocket(port);
    byte[] receiveData = new byte[bufferLen];
    format = new AudioFormat(sampleRate, 16, 1, true, false);
    dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
    sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
    sourceDataLine.open(format);
    sourceDataLine.start();

    FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
    volumeControl.setValue(volumeControl.getMaximum());

    while (status == true) {
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        serverSocket.receive(receivePacket);
        toSpeaker(receivePacket.getData(), receivePacket.getLength());
    }
    sourceDataLine.drain();
    sourceDataLine.close();
}
public static void toSpeaker(byte soundbytes[], int length) {
    try {
        sourceDataLine.write(soundbytes, 0, length);
    } catch (...) {...}
}
...

Частота дискретизации сервера идентична приложению для Android. Формат AudioFormat.ENCODING_PCM_16BIT.

1 Ответ

0 голосов
/ 19 октября 2019

Прочитайте эту статью: Что именно происходит с запущенными службами, когда вы удаляете приложение для Android из списка недавних приложений?

В вашем случае служба перестает работать в процессе восстановления из-за запускакажется, у вас проблема с записью, но я не знаю, что это такое. В смысле улучшения вашего сервиса используйте IntentService или приоритетный сервис для решения проблемы.

Кстати, если вы хотите использовать свое приложение на Android 8 или выше, вы, вероятно, должны использовать ForeGrounService только потому, что IntentService будет убит системой через несколько минут, если приложение находится в фоновом режиме. Прочитайте это: Пределы выполнения фона

Итак, после тестирования всех решений вы можете согласиться со мной по использованию службы переднего плана: Пример службы Android переднего плана

...