react-native-background-actions icon indicating copy to clipboard operation
react-native-background-actions copied to clipboard

Microphone Not Working in Background on Android Device

Open vishalyad16 opened this issue 1 year ago • 19 comments

Hi

While the app is in the background, the microphone isn't working. However, it functions properly when the app is in the foreground, where both camera and microphone permissions are granted.

how can i solve this ?

I’m facing an issue where the microphone stops working when the app is in the background, even though the camera and microphone permissions are correctly granted when the app is in the background and it functions properly when the app is in foreground.

Can you please assist in resolving this? It would be greatly appreciated if someone could help or provide any guidance on how to fix this behavior.

Thanks in advance!

<service android:name=".RNBackgroundActionsTask" android:foregroundServiceType="dataSync"/>

Image Image

vishalyad16 avatar Jan 27 '25 07:01 vishalyad16

I have similar issue after 2 second the voice permission icon disappear that's the make as microphone off and voice saved as blank i am still finding solution or work around

KartikLakhani009 avatar Jan 27 '25 10:01 KartikLakhani009

@KartikLakhani009, if you find a solution, please share it. I’ve been searching for a solution for the past week.

@Rapsssito, could you please help with the solution?

vishalyad16 avatar Jan 27 '25 11:01 vishalyad16

@KartikLakhani009 @vishalyad16 Did you find any fix for this?

IIvexII avatar Feb 04 '25 23:02 IIvexII

@IIvexII I’m still figuring out the solution.

vishalyad16 avatar Feb 05 '25 04:02 vishalyad16

@vishalyad16 After days of struggle, I have resolved this issue by only running a background service.

npm i react-native-background-actions

After the installation, I converted my expo to bare react native project:

npx expo prebuild

In android>app>src>main>AndroidManifest.xml I added the following permissions and services:

  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

and between application tag I added this

 <application>
       ...............other things
        <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="shortService|microphone|mediaPlayback|mediaProjection"/>
       ...............other things or at the end
</application>

Here is the basic code to start and stop the background service, feel free to change the parameters

import BackgroundService from "react-native-background-actions";

// this start a background service that will keep the microphone access alive
    await BackgroundService.start(taskToMakeMicAlive, {
      taskName: "MicrophoneIndicator",
      taskTitle: "[NOTICE] Mic is being used",
      taskDesc: "",
      taskIcon: {
        name: "ic_launcher_foreground", // you should be very carefull when mentioningthe name of icon its in android>app>src>main>res><inside every folder starting with mipmap> this icon can make or break this functionality of background service so be carefull, I have waste immense amount of time on this :P 
        type: "mipmap",
      },
      color: "#010816",
      linkingURI: "JoinScreen",
      parameters: {
        delay: 2000,
      },
    });

// this will stop the background service
await BackgroundService.stop();

Here is the actual function that will run in the background:

async function taskToMakeMicAlive(taskDataArguments: { delay: number } | undefined) {
    if (!taskDataArguments) return;

    const { delay } = taskDataArguments;
    console.log(BackgroundService.isRunning());
    while (BackgroundService.isRunning()) {
      // wait for the delay time
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }

IIvexII avatar Feb 05 '25 07:02 IIvexII

@IIvexII Please send me the code snippet from node_modules/react-native-background-actions/android/src/main/AndroidManifest.xml.

vishalyad16 avatar Feb 05 '25 07:02 vishalyad16

do you have android folder in your project?

IIvexII avatar Feb 05 '25 07:02 IIvexII

Yes I am using CLI

vishalyad16 avatar Feb 05 '25 07:02 vishalyad16

I didn't edited the node_modules/react-native-background-actions/android/src/main/AndroidManifest.xml, so it will be same as yours. Please change the android>app>src>main>AndroidManifest.xml : Here is mine if it can help:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.CAMERA"/>
  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

  <queries>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"/>
    </intent>
  </queries>
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="default"/>
    <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
    <meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
    <meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
    
    <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="shortService|microphone|mediaPlayback|mediaProjection"/>


    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="com.zafeerhafeez.AudioMeet"/>
        <data android:scheme="exp+audio-meet"/>
      </intent-filter>
    </activity>
  </application>
</manifest>

IIvexII avatar Feb 05 '25 07:02 IIvexII

@IIvexII I'm facing a build issue while adding it.

<service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="shortService|microphone|mediaPlayback|mediaProjection"/>

android\app\src\debug\AndroidManifest.xml:33:85-156 Error: Attribute service#com.asterinet.react.bgactions.RNBackgroundActionsTask@foregroundServiceType value=(shortService|microphone|mediaProjection) from AndroidManifest.xml:33:85-156 is also present at [:react-native-background-actions] AndroidManifest.xml:10:13-53 value=(dataSync). Suggestion: add 'tools:replace="android:foregroundServiceType"' to element at AndroidManifest.xml to override.

FAILURE: Build failed with an exception.

  • What went wrong: Execution failed for task ':app:processDebugMainManifest'.

Manifest merger failed with multiple errors, see logs

vishalyad16 avatar Feb 05 '25 08:02 vishalyad16

It seems like there 2 services defined with the same name but different value. Remove the one that have value of value=(dataSync) and make sure that you have not edited the AndroidManifest of the package. You should only modify the one present in your project's android folder.

If the problem persist then re-install the package react-native-background-actions.

IIvexII avatar Feb 05 '25 09:02 IIvexII

It seems like there 2 services defined with the same name but different value. Remove the one that have value of value=(dataSync) and make sure that you have not edited the AndroidManifest of the package. You should only modify the one present in your project's android folder.

If the problem persist then re-install the package react-native-background-actions.

@IIvexII I tried the solution above, but the app now crashes when it goes into the background.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.asterinet.react.bgactions"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <application> <service android:name=".RNBackgroundActionsTask"/> </application> </manifest>

vishalyad16 avatar Feb 07 '25 12:02 vishalyad16

@vishalyad16 I am facing the same issue in android 14 and above version. This is working fine in 13 and less. The problem is with shortService. I will try to fix mine then I'll share the solution if successful.

IIvexII avatar Feb 07 '25 12:02 IIvexII

Okay @IIvexII

vishalyad16 avatar Feb 07 '25 12:02 vishalyad16

@vishalyad16 Sorry for the late reply, I was busy in some other things. By the way, I have found and fixed the root causes that was making the app crash.

  • shortService - I have removed it and added new foreground service type i.e. dataSync
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
    
    ... under application
    <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="dataSync|microphone|mediaPlayback"/>
    ...
    
  • removed the unused permission and forground type i.e. mediaProjection. Because I don't need the permission to record the screen, but if you want to record then you have to explicitly ask the permission from the user.

IIvexII avatar Feb 12 '25 10:02 IIvexII

@IIvexII , thanks for the reply. Can you please send me the code for android/app/src/main/AndroidManifest.xml?

vishalyad16 avatar Feb 12 '25 12:02 vishalyad16

Sure!! Here is the code:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.CAMERA"/>
  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

  <queries>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"/>
    </intent>
  </queries>
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="default"/>
    <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
    <meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
    <meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
    
    <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="dataSync|microphone|mediaPlayback"/>


    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="dummy scheme"/>
        <data android:scheme="exp+audio-meet"/>
      </intent-filter>
    </activity>
  </application>
</manifest>

IIvexII avatar Feb 12 '25 12:02 IIvexII

@IIvexII it is still crashing on samsung device

vishalyad16 avatar Feb 14 '25 08:02 vishalyad16

Quick note from my testing: React Native seems to throttle background JS, at least setTimeout timers, which broke my background action.

If you’re doing audio work driven by JS timers/callbacks, it might be worth trying native for the critical path. When I moved the setTimeout functionality into a tiny Expo Module, it kept running in the background, while the JS timer path stalled.

Rough sketch:

@AsyncFunction
fun startBackgroundAudio(promise: Promise) { /* native loop */ }
const backgroundTask = async () => {
  await YourAudioModule.startBackgroundAudio();
};

Not saying this is the only cause or a universal fix—just what helped me.

jparksecurity avatar Aug 21 '25 01:08 jparksecurity