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:
parent
018aba6ea8
commit
3739d3d2f8
6 changed files with 91 additions and 38 deletions
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
19
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
67
types/modules/react-native-webrtc.d.ts
vendored
67
types/modules/react-native-webrtc.d.ts
vendored
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue