MM-42320: Calls - Fix for: iOS loses calls audio after leaving 1st call and entering next (#6143)

* allow 2nd+ calls to connect to iOS microphone/audio

* peerconnection callback & index.d.ts, webrtc and incallmanager deps
This commit is contained in:
Christopher Poile 2022-04-11 12:03:44 -04:00 committed by GitHub
parent 018aba6ea8
commit 3739d3d2f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 38 deletions

View file

@ -21,7 +21,7 @@ export let client: any = null;
const websocketConnectTimeout = 3000;
export async function newClient(channelID: string, closeCb: () => void, setScreenShareURL: (url: string) => void) {
let peer: any = null;
let peer: Peer | null = null;
let stream: MediaStream;
let voiceTrackAdded = false;
let voiceTrack: MediaStreamTrack | null = null;
@ -50,13 +50,15 @@ export async function newClient(channelID: string, closeCb: () => void, setScree
streams.forEach((s) => {
s.getTracks().forEach((track: MediaStreamTrack) => {
track.stop();
track.release();
});
});
if (peer) {
peer.destroy();
}
InCallManager.stop();
peer?.destroy(undefined, undefined, () => {
// Wait until the peer connection is closed, which avoids the following racy error that can cause problems with accessing the audio system in the future:
// AVAudioSession_iOS.mm:1243 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
InCallManager.stop();
});
if (closeCb) {
closeCb();
@ -67,7 +69,7 @@ export async function newClient(channelID: string, closeCb: () => void, setScree
if (!peer) {
return;
}
if (voiceTrackAdded) {
if (voiceTrackAdded && voiceTrack) {
peer.replaceTrack(voiceTrack, null, stream);
}
if (voiceTrack) {
@ -160,7 +162,7 @@ export async function newClient(channelID: string, closeCb: () => void, setScree
ws.on('message', ({data}) => {
const msg = JSON.parse(data);
if (msg.type === 'answer' || msg.type === 'offer') {
peer.signal(data);
peer?.signal(data);
}
});

View file

@ -421,7 +421,12 @@ export default class Peer extends stream.Duplex {
this.isNegotiating = true;
}
_destroy(err: Error | null, cb: (error: Error | null) => void) {
destroy(err?: Error, cb?: (error: Error | null) => void, cbPCClose?: () => void): this {
this._destroy(err, cb, cbPCClose);
return this;
}
_destroy(err?: Error | null, cb?: (error: Error | null) => void, cbPcClose?: () => void) {
if (this.destroyed || this.destroying) {
return;
}
@ -468,14 +473,14 @@ export default class Peer extends stream.Duplex {
} catch (err) {} // eslint-disable-line
// allow events concurrent with destruction to be handled
this.channel.onmessage = null;
this.channel.onopen = null;
this.channel.onclose = null;
this.channel.onerror = null;
this.channel.onmessage = undefined;
this.channel.onopen = undefined;
this.channel.onclose = undefined;
this.channel.onerror = undefined;
}
if (this.pc) {
try {
this.pc.close();
this.pc.close(cbPcClose);
} catch (err) {} // eslint-disable-line
// allow events concurrent with destruction to be handled
@ -491,7 +496,7 @@ export default class Peer extends stream.Duplex {
this.emit('error', err);
}
this.emit('close');
cb(null);
cb?.(null);
}, 0);
}

View file

@ -348,7 +348,7 @@ PODS:
- ReactNativeExceptionHandler (2.10.10):
- React-Core
- ReactNativeIncallManager (3.3.0):
- React
- React-Core
- ReactNativeKeyboardTrackingView (5.7.0):
- React
- ReactNativeNavigation (7.25.1):
@ -781,7 +781,7 @@ SPEC CHECKSUMS:
React-runtimeexecutor: 2450b43df7ffe8e805a0b3dcb2abd4282f1f1836
ReactCommon: d98c6c96b567f9b3a15f9fd4cc302c1eda8e3cf2
ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60
ReactNativeIncallManager: a840ef75640518065742a893e6c6ff98ee820039
ReactNativeIncallManager: 642c22630caadff0a0619413aff4a9da08d63df9
ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306
ReactNativeNavigation: 6e747bdf88f138088a105285274170b3fc0404ed
rn-fetch-blob: 17961aec08caae68bb8fc0e5b40f93b3acfa6932

19
package-lock.json generated
View file

@ -57,7 +57,7 @@
"react-native-haptic-feedback": "1.13.0",
"react-native-hw-keyboard-event": "0.0.4",
"react-native-image-picker": "4.7.3",
"react-native-incall-manager": "3.3.0",
"react-native-incall-manager": "github:cpoile/react-native-incall-manager",
"react-native-keyboard-aware-scrollview": "2.1.0",
"react-native-keyboard-tracking-view": "5.7.0",
"react-native-keychain": "8.0.0",
@ -81,7 +81,7 @@
"react-native-svg": "12.1.1",
"react-native-vector-icons": "9.0.0",
"react-native-video": "5.2.0",
"react-native-webrtc": "github:streamer45/react-native-webrtc",
"react-native-webrtc": "github:mattermost/react-native-webrtc",
"react-native-webview": "11.17.1",
"react-native-youtube": "2.0.2",
"react-redux": "7.2.6",
@ -19400,8 +19400,8 @@
},
"node_modules/react-native-incall-manager": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/react-native-incall-manager/-/react-native-incall-manager-3.3.0.tgz",
"integrity": "sha512-SvomgHUoKqVso/BGv02b4ndBqenlqYqW3pptZz5qHwteidKFNWI6ny+PPw5X55MdK0lyTbzBoiT3DwS06Qu0lg==",
"resolved": "git+ssh://git@github.com/cpoile/react-native-incall-manager.git#8c55b9dac0a2ab25d651fb54b504d384f9989b36",
"license": "ISC",
"peerDependencies": {
"react-native": ">=0.40.0"
}
@ -19746,7 +19746,7 @@
},
"node_modules/react-native-webrtc": {
"version": "1.75.3",
"resolved": "git+ssh://git@github.com/streamer45/react-native-webrtc.git#7fe7d434892e6b29c5a6086d30b10f482db1e592",
"resolved": "git+ssh://git@github.com/mattermost/react-native-webrtc.git#7f765758f2f67e467ebd224c1c4d00a475e400d3",
"dependencies": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",
@ -38798,9 +38798,8 @@
"requires": {}
},
"react-native-incall-manager": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/react-native-incall-manager/-/react-native-incall-manager-3.3.0.tgz",
"integrity": "sha512-SvomgHUoKqVso/BGv02b4ndBqenlqYqW3pptZz5qHwteidKFNWI6ny+PPw5X55MdK0lyTbzBoiT3DwS06Qu0lg==",
"version": "git+ssh://git@github.com/cpoile/react-native-incall-manager.git#8c55b9dac0a2ab25d651fb54b504d384f9989b36",
"from": "react-native-incall-manager@github:cpoile/react-native-incall-manager",
"requires": {}
},
"react-native-keyboard-aware-scrollview": {
@ -39060,8 +39059,8 @@
}
},
"react-native-webrtc": {
"version": "git+ssh://git@github.com/streamer45/react-native-webrtc.git#7fe7d434892e6b29c5a6086d30b10f482db1e592",
"from": "react-native-webrtc@github:streamer45/react-native-webrtc",
"version": "git+ssh://git@github.com/mattermost/react-native-webrtc.git#7f765758f2f67e467ebd224c1c4d00a475e400d3",
"from": "react-native-webrtc@github:mattermost/react-native-webrtc",
"requires": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",

View file

@ -55,7 +55,7 @@
"react-native-haptic-feedback": "1.13.0",
"react-native-hw-keyboard-event": "0.0.4",
"react-native-image-picker": "4.7.3",
"react-native-incall-manager": "3.3.0",
"react-native-incall-manager": "github:cpoile/react-native-incall-manager",
"react-native-keyboard-aware-scrollview": "2.1.0",
"react-native-keyboard-tracking-view": "5.7.0",
"react-native-keychain": "8.0.0",
@ -79,7 +79,7 @@
"react-native-svg": "12.1.1",
"react-native-vector-icons": "9.0.0",
"react-native-video": "5.2.0",
"react-native-webrtc": "github:streamer45/react-native-webrtc",
"react-native-webrtc": "github:mattermost/react-native-webrtc",
"react-native-webview": "11.17.1",
"react-native-youtube": "2.0.2",
"react-redux": "7.2.6",

View file

@ -50,11 +50,17 @@ declare module 'react-native-webrtc' {
constructor();
stop(): void;
applyConstraints(): void;
clone(): void;
getCapabilities(): void;
getConstraints(): void;
getSettings(): void;
release(): void;
private _switchCamera(): void;
@ -74,13 +80,21 @@ declare module 'react-native-webrtc' {
constructor(arg: any);
addTrack(track: MediaStreamTrack): void;
removeTrack(track: MediaStreamTrack): void;
getTracks(): MediaStreamTrack[];
getTrackById(trackId: string): MediaStreamTrack | undefined;
getAudioTracks(): MediaStreamTrack[];
getVideoTracks(): MediaStreamTrack[];
clone(): void;
toURL(): string;
release(): void;
}
@ -92,23 +106,27 @@ declare module 'react-native-webrtc' {
bufferedAmountLowThreshold: number;
id: number;
label: string;
maxPacketLifeTime: ?number;
maxRetransmits: ?number;
maxPacketLifeTime?: number;
maxRetransmits?: number;
negotiated: boolean;
ordered: boolean;
protocol: string;
readyState: 'connecting' | 'open' | 'closing' | 'closed';
onopen: ?Function;
onmessage: ?Function;
onbufferedamountlow: ?Function;
onerror: ?Function;
onclose: ?Function;
onopen?: Function;
onmessage?: Function;
onbufferedamountlow?: Function;
onerror?: Function;
onclose?: Function;
constructor(peerConnectionId: number, label: string, dataChannelDict: RTCDataChannelInit)
send(data: string | ArrayBuffer | ArrayBufferView): void
close(): void
_unregisterEvents(): void
_registerEvents(): void
}
@ -116,6 +134,7 @@ declare module 'react-native-webrtc' {
type: string;
data: string | ArrayBuffer | Blob;
origin: string;
constructor(type: any, eventInitDict: any)
}
@ -129,6 +148,33 @@ declare module 'react-native-webrtc' {
track?: MediaStreamTrack;
}
export interface EventOnConnectionStateChange {
target: {
iceConnectionState: RTCIceConnectionState;
};
}
export interface ConfigurationParam {
username?: string | undefined;
credential?: string | undefined;
}
export interface ConfigurationParamWithUrls extends ConfigurationParam {
urls: string[];
}
export interface ConfigurationParamWithUrl extends ConfigurationParam {
url: string;
}
export interface RTCPeerConnectionConfiguration {
iceServers: ConfigurationParamWithUrls[] | ConfigurationParamWithUrl[];
iceTransportPolicy?: 'all' | 'relay' | 'nohost' | 'none' | undefined;
bundlePolicy?: 'balanced' | 'max-compat' | 'max-bundle' | undefined;
rtcpMuxPolicy?: 'negotiate' | 'require' | undefined;
iceCandidatePoolSize?: number | undefined;
}
export class RTCPeerConnection {
localDescription: RTCSessionDescriptionType;
remoteDescription: RTCSessionDescriptionType;
@ -164,11 +210,11 @@ declare module 'react-native-webrtc' {
addTrack(track: MediaStreamTrack): void;
addTransceiver(kind: 'audio'|'video'|MediaStreamTrack, init: any): void;
addTransceiver(kind: 'audio' | 'video' | MediaStreamTrack, init: any): void;
removeStream(stream: MediaStream): void;
removeTrack(sender: RtpSender): Promise<boolean>
removeTrack(sender: RTCRtpSender): Promise<boolean>
createOffer(options?: RTCOfferOptions): Promise<RTCSessionDescriptionType>;
@ -188,7 +234,7 @@ declare module 'react-native-webrtc' {
getRemoteStreams(): MediaStream[];
close(): void;
close(cb?: () => void): void;
private _getTrack(streamReactTag: string, trackId: string): MediaStreamTrack;
@ -218,6 +264,7 @@ declare module 'react-native-webrtc' {
export class RTCSessionDescription extends RTCSessionDescriptionType {
constructor(info: RTCSessionDescriptionType);
toJSON(): RTCSessionDescriptionType;
}