You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PARTIAL_WAKE_LOCK后设备休眠时AudioRecord无录音内容求助

解决Android休眠时AudioRecord录制静音的问题

我帮你捋捋这个问题——你遇到的情况其实是Android系统休眠时的硬件资源限制导致的,PARTIAL_WAKE_LOCK只能保证CPU持续运行,但很多厂商为了省电,会在设备屏幕关闭(休眠)时自动禁用麦克风这类输入硬件,这就导致AudioRecord虽然还在循环读取,但拿到的都是静音数据。下面是具体的排查方向和解决方案:

核心原因

PARTIAL_WAKE_LOCK的作用仅为保持CPU唤醒,它不会强制音频输入硬件(麦克风)处于活跃状态。当设备进入休眠模式后,系统的省电策略会优先切断非必要硬件的供电,麦克风首当其冲,这时候AudioRecord的read()方法虽然能返回正常的读取计数,但数据都是0(静音)。

解决方案

1. 将录音逻辑移到前台服务中

Android 8.0及以后,后台线程的优先级极低,设备休眠时很容易被系统限制资源。前台服务拥有更高的优先级,系统会保证其稳定运行,同时明确告知系统该服务需要持续使用麦克风资源。

  • 首先在Manifest中注册前台服务,并声明必要的权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 12+ 必需 -->
    
    <service
        android:name=".RecordForegroundService"
        android:foregroundServiceType="microphone" /> <!-- 明确服务类型为麦克风 -->
    
  • 在服务中实现录音逻辑,启动时创建前台通知:

    public class RecordForegroundService extends Service {
        private static final String CHANNEL_ID = "RecordServiceChannel";
        private AudioRecord audioRecord;
        private PowerManager.WakeLock wakeLock;
        private boolean isReading = false;
        private int bufferSize;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            createNotificationChannel();
            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("正在录音")
                    .setContentText("后台持续录制音频")
                    .setSmallIcon(R.drawable.ic_mic)
                    .build();
            startForeground(1, notification);
    
            // 初始化AudioRecord参数
            bufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
    
            // 初始化并获取WakeLock
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp:RecordWakeLock");
            wakeLock.acquire();
    
            startRecordingThread();
            return START_STICKY;
        }
    
        private void startRecordingThread() {
            isReading = true;
            new Thread(() -> {
                short[] buffer = new short[bufferSize];
                int readCount;
                while (isReading && audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                    readCount = audioRecord.read(buffer, 0, buffer.length);
                    // 只写入有效数据,避免读取到0时写入静音
                    if (readCount > 0) {
                        writeWavFile(buffer, readCount);
                    }
                }
                // 释放资源
                audioRecord.stop();
                audioRecord.release();
                if (wakeLock.isHeld()) {
                    wakeLock.release();
                }
            }).start();
            audioRecord.startRecording();
        }
    
        private void createNotificationChannel() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "录音服务", NotificationManager.IMPORTANCE_LOW);
                NotificationManager manager = getSystemService(NotificationManager.class);
                manager.createNotificationChannel(channel);
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

2. 优化AudioRecord数据写入逻辑

你原来的代码中直接将整个buffer写入文件,但如果readCount小于bufferSize,多余的部分会是默认的0值,导致文件出现静音片段。修改writeWavFile方法,传入实际读取的字节数:

private void writeWavFile(short[] buffer, int readCount) {
    try {
        DataOutputStream dos = ...; // 你的文件输出流实例
        // 将short数组转换为字节数组(16bit采样,每个short占2字节)
        byte[] byteBuffer = new byte[readCount * 2];
        ByteBuffer.wrap(byteBuffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer, 0, readCount);
        dos.write(byteBuffer);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3. 调整设备省电策略

部分定制ROM可能有更严格的省电规则,你可以在设备的「电池优化」设置中,将你的应用设置为「不优化」,避免系统强制停止后台录音逻辑。

额外注意事项

  • 务必在录音结束后及时释放WakeLock和AudioRecord资源,避免不必要的电量消耗。
  • Android 10及以后,确保已经获得RECORD_AUDIO的用户授权,后台录音才会被允许。

内容的提问来源于stack exchange,提问作者Igor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:22:49