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:
parent
f2b4312a57
commit
1fb01dfcdc
6 changed files with 79 additions and 2 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
40
app/products/calls/connection/foreground_service.ts
Normal file
40
app/products/calls/connection/foreground_service.ts
Normal 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();
|
||||
};
|
||||
|
|
@ -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
15
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue