Моя проблема немного изменилась, пожалуйста, посмотрите на 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
.