¿Por qué el micrófono Bluetooth deja de grabar en modo de fondo?

Mi objetivo es grabar audio desde un micrófono Bluetooth mientras que en modo de fondo.

Resultado previsto: El A2DP Servicio registra audio mientras que en el modo de fondo.

Resultado real: El A2DPService no puede grabar audio después en el modo de fondo después de 2 minutos. El archivo de audio estará vacío.

Cómo reproducir el tema:

  1. utilizar @ReactMethod connectDevice(address: string).
  2. fue al modo de fondo, esperar hasta 2 minutos.
  3. utilizar @ReactMethod startBluetoothSco() para grabar el audio
  4. utilizar @ReactMethod stopBluetoothSco() Para detener la grabadora.
  5. reproducir el archivo de audio. el archivo de audio no funcionará ya que no hay entrada del micrófono Bluetooth. Conseguir que la aplicación a Foreground Mode arregle el problema, pero la aplicación se pretende utilizar la mayor parte del tiempo en modo de fondo.

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;
        }
    }
}

RNBluetoothNM.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 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);
            }
        }
    }
}

Pregunta hecha hace 3 años, 4 meses, 28 días - Por devdynamo


3 Respuestas:

  • Estás usando un servicio de antecedentes. Hay una cantidad limitada de tiempo que se les permite correr. Utilice un servicio de primer nivel, que no tiene limitaciones de tiempo. Esto no requiere que tu app esté en frente, solo hace que una notificación aparezca diciendo que estás corriendo.

    Lo único que necesitas cambiar es comenzar el servicio con startForegroundService() y llamar a inicio Foregound in the service itself.

    Respondida el Dec 18, 2020 a las 15:53 - por pixelpioneerc4b5

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando con el micrófono Bluetooth que deja de grabar en modo de fondo puede estar relacionado con la gestión de la conexión Bluetooth y el audio en tu aplicación.

    Aquí te dejo algunas sugerencias para solucionar el problema:

    • Gestión de conexiones Bluetooth: Asegúrate de que la conexión Bluetooth con el dispositivo del micrófono se mantenga activa en modo de fondo. Puedes revisar que la conexión a A2DP se mantenga estable durante la grabación de audio en el modo de fondo.
    • Gestión del audio: Verifica que la configuración del audio se mantenga correctamente durante la grabación en modo de fondo. Puedes revisar las configuraciones de audio del dispositivo Android para asegurarte de que no se interrumpa la grabación en modo de fondo.
    • Tiempo de ejecución en segundo plano: Algunas aplicaciones en Android pueden ser detenidas por el sistema operativo cuando entran en modo de fondo. Puedes revisar la gestión de la ejecución en segundo plano de tu aplicación para asegurarte de que se mantenga activa durante la grabación de audio.
    • Permisos: Asegúrate de tener los permisos necesarios correctamente configurados en tu aplicación para acceder al micrófono y gestionar las conexiones Bluetooth.
    • Pruebas en diferentes dispositivos: Prueba tu aplicación en diferentes dispositivos Android para ver si el problema persiste en uno en particular.

    Espero que estas sugerencias te ayuden a resolver el problema con el micrófono Bluetooth en modo de fondo. Si necesitas más ayuda, no dudes en preguntar.

    Respondida el Dec 19, 2020 a las 15:52 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Causa potencial:

    El sistema operativo Android puede suspender Bluetooth en modo de fondo para conservar energía. Esto interrumpe la conexión A2DP y impide que la grabadora Bluetooth funcione.

    Solución:

    Para evitar que el sistema operativo suspenda Bluetooth en modo de fondo, puedes utilizar el Servicio de primer plano de Android. El Servicio de primer plano es un componente que se ejecuta en primer plano y evita que el sistema suspenda el proceso de la aplicación.

    Pasos para implementar el Servicio de primer plano:

    • Crea una clase de servicio que extienda `Service`.
    • Anula el método `onStartCommand()`.
    • Inicia un primer plano dentro del método `onStartCommand()` utilizando `startForeground(int, Notification)`.
    • Detiene el primer plano en el método `onDestroy()`.

    Código de ejemplo:

    java
    public class BluetoothForegroundService extends Service {
    
        private static final int FOREGROUND_ID = 1;
        private Notification notification;
        private BluetoothA2dp mBluetoothA2dp;
        private AudioManager mAudioManager;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(FOREGROUND_ID, notification);
    
            // Código para inicializar la conexión A2DP y iniciar la grabación.
    
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            stopForeground(true);
    
            // Código para detener la conexión A2DP y la grabación.
        }
    }
    

    Uso del Servicio de primer plano:

    • Inicia el `BluetoothForegroundService` en modo de fondo.
    • Establece el primer plano utilizando el método `startForeground()`.

    Esto evitará que el sistema operativo suspenda Bluetooth y permitirá que la grabación continúe en modo de fondo.

    Respondida el Dec 19, 2020 a las 15:54 - por Gemini

    Votos positivos: 0 | Votos negativos: 0