【问题标题】:Android Service stops recording audio when app is killed当应用程序被杀死时,Android 服务停止录制音频
【发布时间】:2019-10-16 16:08:18
【问题描述】:

我的问题有点变了,请看下面的EDIT 2

我正在学习如何在 Android 上使用服务和录音。

我想创建一个应用程序,除了启动服务之外什么都不做:在请求权限(RECORD_AUDIOINTERNET)后,应用程序只从MainActivity 调用startService()

然后该服务将录制音频并将其流式传输到给定的 IP 地址。我从this question 的答案中获得了音频流服务器和客户端的灵感。到目前为止,我正在 Android Studio Emulator 中的 Android 6.0 上测试该应用程序。

这是我服务的onStartCommand() 方法。我创建了一个新线程,等待用户在权限请求对话框中单击“允许”。当我收到权限时,我初始化了AudioRecord,然后我在while-loop 中读取它并将数据发送出去。

@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。

阅读this answer 中的文章后,我将之前在onDestroy 中的内容移至onTaskRemoved。然而,一切都没有改变。

服务在重新启动后显然仍在发送一些数据包。我在 Wireshark 中查看了它们,数据包仍在离开设备,服务器仍在接收它们。数据包的有效载荷是非零的,对于每个数据包都是唯一的。

编辑 2:

我在 Android 应用程序中将缓冲区大小更改为 AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 10,在服务器应用程序中将缓冲区大小更改为 AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 20。现在,当我滑动应用程序时,Service 重新启动,然后我可以听到一些声音。但是重启后声音很粗,我不知道为什么。当我卸载应用程序,保持服务器运行,然后再次安装并运行应用程序时,它也会变得很粗。

所以问题可能出在服务器端。服务器可能有什么问题?我使用SourceDataLine 是否正常工作?服务器代码如下所示(取自here):

...
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

【问题讨论】:

  • 请记住,这种方法不适用于 Android 9 或更高版本。在这些 Android 版本上,您只能在应用处于前台时录制音频,或者从在活动时显示通知的前台服务录制音频。
  • @Michael 我知道这件事。我正在尝试编写的这个应用程序仅用于个人学习目的,并且针对的是我的 Android 6 旧手机。

标签: java android audio android-service audio-recording


【解决方案1】:

阅读这篇文章:What exactly happens to running services when you swipe an android app from recent app list ?

在您的情况下,服务停止工作,在娱乐中由于开始粘滞,您似乎遇到了录制失败的问题,我不知道它是什么。在改进服务的意义上,使用 IntentService 或前台服务来解决问题。

顺便说一句,如果您想在 android 8 或更高版本中使用您的应用程序,您可能只需要使用 ForeGrounService,因为如果应用程序处于后台,IntentService 将在几分钟后被系统杀死。阅读:Background Execution Limits

所以在测试了所有解决方案后,您可能会同意我使用前台服务:Android Foreground Service Example

【讨论】:

    猜你喜欢
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多