簡體   English   中英

為什么藍牙麥克風在后台模式下停止錄音?

[英]Why Bluetooth Microphone stops recording in Background Mode?

我的目標是在后台模式下從藍牙麥克風錄制音頻。

預期結果:A2DPService 在后台模式下錄制音頻。

實際結果:A2DPService 在后台模式下 2 分鍾后無法錄制音頻。 音頻文件將為空。

如何重現該問題:

  1. 使用 @ReactMethod connectDevice(address: string)
  2. 進入后台模式,等到2分鍾。
  3. 使用@ReactMethod startBluetoothSco()錄制音頻
  4. 使用 @ReactMethod stopBluetoothSco()來停止錄音機。
  5. 播放音頻文件。 由於沒有來自藍牙麥克風的輸入,音頻文件將不會運行。 將應用程序設置為前台模式解決了該問題,但該應用程序旨在大部分時間在后台模式下使用。

A2DPService.java

package com.satpam.RNBluetoothNM.A2DP;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class A2DPService {
    private BluetoothDevice mBluetoothDevice;
    private BluetoothA2dp mBluetoothA2dp;
    private AudioManager mAudioManager;

    public A2DPService(ReactApplicationContext reactContext) {
        mAudioManager = (AudioManager) reactContext.getSystemService(Context.AUDIO_SERVICE);

        BluetoothAdapter
                .getDefaultAdapter()
                .getProfileProxy(reactContext, new BluetoothProfile.ServiceListener() {
                    @Override
                    public void onServiceConnected(int i, BluetoothProfile bluetoothProfile) {
                        if (i == BluetoothProfile.A2DP) {
                            mBluetoothA2dp = (BluetoothA2dp) bluetoothProfile;
                        }
                    }

                    @Override
                    public void onServiceDisconnected(int i) {
                        if (i == BluetoothProfile.A2DP) {
                            mBluetoothA2dp = null;
                        }
                    }
                }, BluetoothProfile.A2DP);
    }

    public boolean createBond(BluetoothDevice bluetoothDevice) {
        mBluetoothDevice = bluetoothDevice;
        return mBluetoothDevice.createBond();
    }

    public boolean connectA2DP(BluetoothDevice bluetoothDevice) {
        if (mBluetoothDevice == null) {
            return false;
        } else {
            try {
                Method method = BluetoothA2dp.class.getMethod("connect", BluetoothDevice.class);
                method.invoke(mBluetoothA2dp, bluetoothDevice);
                return true;
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                return false;
            }
        }
    }

    public int getConnectedState() {
        return mBluetoothA2dp.getConnectionState(mBluetoothDevice);
    }

    public boolean startBluetoothSco() {
        if (getConnectedState() != BluetoothProfile.STATE_CONNECTED) {
            return false;
        } else {
            mAudioManager.setBluetoothScoOn(true);
            mAudioManager.startBluetoothSco();
            return true;
        }
    }

    public boolean stopBluetoothSco() {
        if (getConnectedState() != BluetoothProfile.STATE_CONNECTED) {
            return false;
        } else {
            mAudioManager.setBluetoothScoOn(false);
            mAudioManager.stopBluetoothSco();
            return true;
        }
    }
}

RN藍牙NM.java

package com.satpam.RNBluetoothNM;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.util.Log;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.satpam.RNBluetoothNM.A2DP.A2DPService;
import com.satpam.RNBluetoothNM.SPP.SPPService;

import java.util.Set;

public class RNBluetoothNMPackage extends ReactContextBaseJavaModule {

    @NonNull
    @Override
    public String getName() {
        return "RNBluetoothNM";
    }

    private static final int getBondedDeviceRequestCode = 0;
    private Promise mPromise;

    private final ActivityEventListener activityListener = new BaseActivityEventListener() {

        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
            super.onActivityResult(activity, requestCode, resultCode, data);
            if (requestCode == getBondedDeviceRequestCode && resultCode == activity.RESULT_OK) {
                getBondedDevices(mPromise);
                mPromise = null;
            }
        }
    };

    public RNBluetoothNMPackage(ReactApplicationContext reactContext) {
        super(reactContext);

        // Add a listener for `onActivityResult`
        reactContext.addActivityEventListener(activityListener);
    }

    private void _requestEnableBluetooth(Promise promise) {
        Intent enableAdapter = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        Activity activity = getCurrentActivity();

        // Store the promise to resolve/reject when onActivityResult returns value;
        mPromise = promise;
        activity.startActivityForResult(enableAdapter, getBondedDeviceRequestCode);
    }

    @ReactMethod
    public void getBondedDevices(final Promise promise) {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if (bluetoothAdapter == null) {
            promise.reject("getBondedDevices", "BluetoothAdapter is not supported");
        } else {
            if (!bluetoothAdapter.isEnabled()) {
                _requestEnableBluetooth(promise);
            }

            Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
            if (devices.size() > 0) {
                WritableArray array = Arguments.createArray();
                for (BluetoothDevice device : devices) {
                    WritableMap writableMap = Arguments.createMap();
                    writableMap.putString("name", device.getName());
                    writableMap.putString("address", device.getAddress());
                    writableMap.putInt("bondState", device.getBondState());

                    array.pushMap(writableMap);
                }

                promise.resolve(array);
            }
        }
    }

    private A2DPService a2DPService;
    private SPPService sppService;

    @ReactMethod
    public void connectDevice(String address, final Promise promise) {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            promise.reject("connectDevice", "BluetoothAdapter is not supported");
        } else {
            if (!bluetoothAdapter.isEnabled()) {
                _requestEnableBluetooth(promise);
            }

            BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
            a2DPService = new A2DPService(getReactApplicationContext());
            boolean a2dpIsBonded = a2DPService.createBond(bluetoothDevice);

            if (a2dpIsBonded == false) {
                promise.reject("A2DPService", "A2DP failed to bond");
            } else {
                boolean a2dpIsConnected = a2DPService.connectA2DP(bluetoothDevice);
                if (a2dpIsConnected == false) {
                    promise.reject("A2DP", "A2DP failed to connect");
                } else {

                    sppService = new SPPService(getReactApplicationContext());
                    boolean sppIsConnected = sppService.connectSPP(bluetoothDevice);
                    if (sppIsConnected == false) {
                        promise.reject("SPPService", "A2DP failed to bond");
                    } else {
                        promise.resolve(true);
                        Thread listener = new Thread(sppService);
                        listener.start();
                    }
                }
            }
        }
    }


    @ReactMethod
    public void startBluetoothSco(final Promise promise) {
        if (a2DPService == null) {
            promise.reject("startBluetoothSco", "A2DPService is null");
        } else {
            boolean isBluetoothScoStarted = a2DPService.startBluetoothSco();
            if (isBluetoothScoStarted == false) {
                promise.reject("startBluetoothSco", "A2DPService is not connected");
            } else {
                promise.resolve(true);
            }
        }
    }

    @ReactMethod
    public void stopBluetoothSco(final Promise promise) {
        if (a2DPService == null) {
            promise.reject("stopBluetoothSco", "A2DPService is null");
        } else {
            boolean isBluetoothScoStopped = a2DPService.stopBluetoothSco();
            if (isBluetoothScoStopped == false) {
                promise.reject("stopBluetoothSco", "A2DPService is not connected");
            } else {
                promise.resolve(true);
            }
        }
    }
}

您正在使用后台服務。 那些被允許運行的時間是有限的。 使用沒有時間限制的前台服務。 這不需要您的應用程序在前面,它只會導致出現一個通知,說明您正在運行。

您唯一需要更改的是使用 startForegroundService() 啟動服務並在服務本身中調用 startForegound。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM