当前位置: 首页 > 知识库问答 >
问题:

当应用程序被关闭时,Android服务停止录制音频

施华奥
2023-03-14

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

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

我想创建一个应用程序,除了启动服务什么也不做:在请求权限(RECORD_AUDIOINTERNET)后,应用程序只从Mainactive调用start Service()

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

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

@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()中创建的线程中的循环终止。然后我释放记录器,这样它就可以初始化并再次使用。

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

这个程序的工作原理只有部分:

  • 当我启动计算机上的监听服务器和模拟器中的应用程序时,我可以正常听到音频。
  • 当我最小化应用程序(点击主页按钮)时,音频流仍然正常。
  • 我的问题是,当我杀死应用程序(在运行的应用程序屏幕中滑动它),音频停止。在Logcat中,我可以看到服务已经重新启动,并像往常一样运行(初始化Audio记录和一切,没有抛出异常),只有我什么也听不到。当我再次运行应用程序(因此再次调用start Service())时,我在Logcat中看到一个异常,告诉我AudioBookstart失败,错误代码为-38(这意味着麦克风正在被服务的上一个实例)。

我做错了什么?为什么在我关闭应用程序时,服务正在运行,但音频没有流媒体?

非常感谢你的回答。

编辑:

我知道这种方法在较新的Android版本上不起作用。这个应用程序只是出于私人目的,将在我的旧手机上运行,无论是Android5.1.1还是6.0。

在我阅读了这篇回答中的文章后,我将之前在onDestroy中的内容移动到了onTaskRemoved。然而,一切都没有改变。

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

编辑2:

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

所以问题可能出在服务器端。服务器可能有什么问题?我是否正确使用源数据线?服务器代码如下所示(取自此处):

...
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个答案

邬承悦
2023-03-14

阅读本文:当你从最近的应用列表中滑动一个Android应用时,运行服务会发生什么?

在你的情况下,服务停止工作,在娱乐中,因为启动粘性,似乎你有一个问题,录音失败,我不知道这是什么。在改善服务的意义上,使用IntentService或前台服务来解决问题。

顺便说一句,如果你想在android 8或更高版本中使用你的应用程序,你可能只需要使用ForeGrounService,因为如果应用程序在后台,IntentService将在几分钟后被系统终止。阅读以下内容:后台执行限制

所以在测试了所有的解决方案之后,你可能会同意我使用前台服务:Android前台服务示例

 类似资料:
  • 问题内容: 我正在使用背景音乐创建游戏应用程序。我使用Android Service播放背景音乐是​​因为我想在更改活动时运行BGM。我的问题是,我在每个活动的onPause方法中都声明了finish()(我不想让用户返回并想杀死该活动)。 因此,当我打算进行其他活动时,它将调用onDestroy并停止该服务。我想停止该服务以完全退出应用程序(按下主页按钮),并想要通过onPause()中的BGM

  • 当用户使用后退按钮退出应用程序时,Android中的后台服务将停止运行。如果应用程序在前台或后台(点击HOME按钮),同样的服务工作得很好。 有3个案例: null MainActivity.java SimpleService

  • 我试图重新创建Connect四,我成功了。但我想通过频繁地切换颜色,给玩家一个获胜的四张光盘在哪里的指示。我对线程和编程中的时间概念是新的。 我也成功地给了用户这个指示,但是在关闭应用程序之后,控制台仍然会给出输出,也是在使用SetonCloserEquest时。 代码如下:

  • 问题内容: 我有一个媒体播放器服务,可在整个应用程序的后台播放音乐,例如: 问题在于,当用户更改应用程序或进入手机主屏幕(应用程序在后台运行)时,音乐仍在播放。 我试图停止它和方法,但是当我更改活动时这会停止音乐,这是我不希望的(我希望音乐在用户浏览活动时继续播放)。 更新资料 我尝试了广播: 我加了 在音乐服务的onCreate和接收事件的方法中: 在应用程序类中,我这样做: 但是音乐不会恢复