MM-54553 - Calls: Enable microphone input in background (Android) (#7585)

* Add foreground service for Android; add voip UIBackgroundMode for iOS

* remove iOS change for this PR

* create foreground notification channel once at startup
This commit is contained in:
Christopher Poile 2023-10-13 14:45:14 -04:00 committed by GitHub
parent f2b4312a57
commit 1fb01dfcdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 2 deletions

View file

@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission android:name="android.permission.BLUETOOTH"
@ -102,5 +103,8 @@
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
<!-- For Calls microphone to work in the background -->
<service android:name="com.voximplant.foregroundservice.VIForegroundService"/>
</application>
</manifest>

View file

@ -8,6 +8,11 @@ import InCallManager from 'react-native-incall-manager';
import {mediaDevices, MediaStream, MediaStreamTrack, RTCPeerConnection} from 'react-native-webrtc';
import {setPreferredAudioRoute, setSpeakerphoneOn} from '@calls/actions/calls';
import {
foregroundServiceStart,
foregroundServiceStop,
foregroundServiceSetup,
} from '@calls/connection/foreground_service';
import {processMeanOpinionScore, setAudioDeviceInfo} from '@calls/state';
import {AudioDevice, type AudioDeviceInfo, type AudioDeviceInfoRaw, type CallsConnection} from '@calls/types/calls';
import {getICEServersConfigs} from '@calls/utils';
@ -26,6 +31,11 @@ const rtcMonitorInterval = 4000;
const InCallManagerEmitter = new NativeEventEmitter(NativeModules.InCallManager);
// Setup the foreground service channel
if (Platform.OS === 'android') {
foregroundServiceSetup();
}
export async function newConnection(
serverUrl: string,
channelID: string,
@ -111,6 +121,10 @@ export async function newConnection(
audioDeviceChanged?.remove();
wiredHeadsetEvent?.remove();
if (Platform.OS === 'android') {
foregroundServiceStop();
}
if (closeCb) {
closeCb();
}
@ -249,6 +263,9 @@ export async function newConnection(
}
}
});
// To allow us to use microphone in the background
await foregroundServiceStart();
}
// We default to speakerphone, but not if the WiredHeadset is plugged in.

View file

@ -0,0 +1,40 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import VIForegroundService from '@voximplant/react-native-foreground-service';
import {logError} from '@utils/log';
const channelConfig = {
id: 'calls_channel',
name: 'Mattermost',
description: 'Mattermost Calls microphone while app is in the background',
enableVibration: false,
};
// Note: multiple calls with same arguments are a noop.
export const foregroundServiceSetup = () => {
VIForegroundService.getInstance().createNotificationChannel(channelConfig);
};
export const foregroundServiceStart = async () => {
const notificationConfig = {
channelId: 'calls_channel',
id: 345678,
title: 'Mattermost',
text: 'Mattermost Calls Microphone',
icon: '',
button: 'Stop',
};
try {
await VIForegroundService.getInstance().startService(notificationConfig);
} catch (e) {
logError('Calls: Cannot start ForegroundService, error:', e);
}
};
export const foregroundServiceStop = async () => {
await VIForegroundService.getInstance().stopService();
};

View file

@ -19,7 +19,7 @@ module.exports = {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/test/file_transformer.js',
},
transformIgnorePatterns: [
'node_modules/(?!(@react-native|react-native)|jail-monkey|@sentry/react-native|react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|validator|react-syntax-highlighter/.*|hast-util-from-selector|hastscript|property-information|hast-util-parse-selector|space-separated-tokens|comma-separated-tokens|zwitch|@mattermost/calls)',
'node_modules/(?!(@react-native|react-native)|jail-monkey|@sentry/react-native|react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|validator|react-syntax-highlighter/.*|hast-util-from-selector|hastscript|property-information|hast-util-parse-selector|space-separated-tokens|comma-separated-tokens|zwitch|@mattermost/calls|@voximplant/react-native-foreground-service)',
],
moduleNameMapper: {

15
package-lock.json generated
View file

@ -39,6 +39,7 @@
"@sentry/react-native": "5.9.0",
"@stream-io/flat-list-mvcp": "0.10.3",
"@tsconfig/react-native": "3.0.2",
"@voximplant/react-native-foreground-service": "3.0.2",
"base-64": "1.0.0",
"commonmark": "npm:@mattermost/commonmark@0.30.1-1",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#235bc817bcade503fb81fa51bbbe3c84f958ed12",
@ -7645,6 +7646,14 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@voximplant/react-native-foreground-service": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@voximplant/react-native-foreground-service/-/react-native-foreground-service-3.0.2.tgz",
"integrity": "sha512-ZIyccOAXPqznA1PAVAYlKZ+GI7kXYCuYgH+gmAkhPouyJbkgrSXaCJJzQ+uBkPr4FBa/PuC/yjzK8vf6tJREQA==",
"peerDependencies": {
"react-native": ">= 0.41.2"
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@ -28508,6 +28517,12 @@
}
}
},
"@voximplant/react-native-foreground-service": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@voximplant/react-native-foreground-service/-/react-native-foreground-service-3.0.2.tgz",
"integrity": "sha512-ZIyccOAXPqznA1PAVAYlKZ+GI7kXYCuYgH+gmAkhPouyJbkgrSXaCJJzQ+uBkPr4FBa/PuC/yjzK8vf6tJREQA==",
"requires": {}
},
"@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",

View file

@ -40,6 +40,7 @@
"@sentry/react-native": "5.9.0",
"@stream-io/flat-list-mvcp": "0.10.3",
"@tsconfig/react-native": "3.0.2",
"@voximplant/react-native-foreground-service": "3.0.2",
"base-64": "1.0.0",
"commonmark": "npm:@mattermost/commonmark@0.30.1-1",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#235bc817bcade503fb81fa51bbbe3c84f958ed12",