react-native-twilio-video-webrtc
react-native-twilio-video-webrtc copied to clipboard
setLocalVideoEnabled disables the sound
When ever I run setLocalVideoEnabled the audio also disables and on enabling the video the audio remains disabled where as setLocalAudioEnabled works perfectly.
_onMuteVideoButtonPress = () => { this.twilioRef .setLocalVideoEnabled(!this.state.isVideoEnabled) .then((isEnabled) => { this.setState({ isVideoEnabled: isEnabled }, () => { console.log("video mute", this.state.isVideoEnabled); console.log("audio mute", this.state.isAudioEnabled); }); }); };
Which platform(s) have you observed this behavior?
I'm experiencing this on Android. I literally tried everything but no luck.
I wonder if this is due one of the android bugs mentioned here: https://www.twilio.com/docs/video/changelog-twilio-video-android. If so it seems like the solution will be to upgrade to the latest version of the android library. Could you try upgrading the android version in the gradle file: https://github.com/blackuy/react-native-twilio-video-webrtc/blob/ad03d0106cfa5bcc75157f8ddb31a85ba02e0640/android/build.gradle#L52
I wonder if this is due one of the android bugs mentioned here: https://www.twilio.com/docs/video/changelog-twilio-video-android. If so it seems like the solution will be to upgrade to the latest version of the android library. Could you try upgrading the android version in the gradle file:
https://github.com/blackuy/react-native-twilio-video-webrtc/blob/ad03d0106cfa5bcc75157f8ddb31a85ba02e0640/android/build.gradle#L52
did you update this package because I did not get any success after changing the library version.
On master it is now set to 5.10.0.
Hello @slycoder i have started facing this issue on IOs now the setLocalVideoEnabled disables the video as well as the audio and does not return back to normal state after enabling the video again.
Interesting. We haven't had any other reports of this issue. Is there any code you could share to reproduce the issue? Does it occur on the Example app?
There's a definition of isVideoEnabled in the Example app but you did not use it, have a look at my code
import React, { Component } from "react";
import {
StyleSheet,
Text,
TextInput,
View,
Button,
Alert,
TouchableOpacity,
Platform,
PermissionsAndroid,
Image,
} from "react-native";
import styles from "./styles";
import {
TwilioVideoLocalView,
TwilioVideoParticipantView,
TwilioVideo,
} from "react-native-twilio-video-webrtc";
import { connect } from "react-redux";
import _ from "lodash";
import { request } from "../../../actions/GetRoomAndToken";
import SessionHelper from "../../../helpers/SessionHelper";
import { Images, Colors } from "../../../theme";
import { ButtonView, Loading } from "../../../components";
const requestCameraPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: "App Camera Permission",
message: "App needs access to your camera",
buttonNegative: "Cancel",
buttonPositive: "OK",
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can use the camera");
} else {
console.log("Camera permission denied");
}
} catch (err) {
console.warn(err);
}
};
class CallModule extends Component {
state = {
participantJoined: false,
isAudioEnabled: true,
isVideoEnabled: true,
showVideoBox: true,
status: "disconnected",
participants: new Map(),
videoTracks: new Map(),
roomName: "",
token: "",
isBtnDisabled: true,
};
componentDidMount() {
requestCameraPermission();
const payload = {
user_id: this.props.user.data.user_id,
token: SessionHelper.getAccessToken(),
booking_id: this.props.bookingId,
};
this.props.request(payload);
}
componentDidUpdate(prevProps) {
if (
!_.isEqual(
prevProps.getroomandtoken.data,
this.props.getroomandtoken.data
)
) {
this.setState({
roomName: this.props.getroomandtoken.data.room,
token: this.props.getroomandtoken.data.token,
});
}
}
_onConnectButtonPress = () => {
const { roomName, token } = this.state;
if (roomName === "" || token === "") {
Alert.alert("Enter both Room name and token.");
} else {
try {
this.twilioRef.connect({
roomName: this.state.roomName,
accessToken: this.state.token,
});
} catch (error) {
console.log(error);
}
this.setState({ status: "connecting" });
}
};
_onEndButtonPress = () => {
this.twilioRef.disconnect();
this.setState({ status: "disconnected" });
};
_onMuteButtonPress = () => {
this.twilioRef
.setLocalAudioEnabled(!this.state.isAudioEnabled)
.then((isEnabled) =>
this.setState({ isAudioEnabled: isEnabled }, () => {
console.log("video mute", this.state.isVideoEnabled);
console.log("audio mute", this.state.isAudioEnabled);
})
);
};
_onMuteVideoButtonPress = () => {
this.twilioRef
.setLocalVideoEnabled(!this.state.isVideoEnabled)
.then((isEnabled) => {
this.setState({ isVideoEnabled: isEnabled }, () => {
console.log("video mute", this.state.isVideoEnabled);
console.log("audio mute", this.state.isAudioEnabled);
});
});
};
onMute = () => {
const { videoTracks } = this.state;
videoTracks.forEach(function (track) {
track.disable();
});
this.setState({ isVideoEnabled: false });
};
onUnMute = () => {
const { videoTracks } = this.state;
videoTracks.forEach(function (track) {
track.enable();
});
this.setState({ isVideoEnabled: true });
};
_onFlipButtonPress = () => {
this.twilioRef.flipCamera();
};
_onRoomDidConnect = () => {
this.setState({ status: "connected", isBtnDisabled: false });
};
_onVideoChanged = () => {
this.setState({ showVideoBox: !this.state.showVideoBox });
};
_onAudioChanged = () => {
console.log("audio toggled");
};
_onRoomDidConnect = () => {
this.setState({ status: "connected", isBtnDisabled: false });
};
_onRoomDidDisconnect = ({ roomName, error }) => {
console.log("ERROR: ", error);
this.setState({ status: "disconnected" });
};
_onRoomDidFailToConnect = (error) => {
console.log("ERROR: ", error);
this.setState({ status: "disconnected" });
};
_onParticipantAddedVideoTrack = ({ participant, track }) => {
console.log("onParticipantAddedVideoTrack: ", participant, track);
this.setState({
participantJoined: true,
videoTracks: new Map([
...this.state.videoTracks,
[
track.trackSid,
{ participantSid: participant.sid, videoTrackSid: track.trackSid },
],
]),
});
};
_onParticipantRemovedVideoTrack = ({ participant, track }) => {
console.log("onParticipantRemovedVideoTrack: ", participant, track);
const videoTracks = this.state.videoTracks;
videoTracks.delete(track.trackSid);
this.setState({
participantJoined: false,
videoTracks: new Map([...videoTracks]),
});
};
setTwilioRef = (ref) => {
this.twilioRef = ref;
};
render() {
let loading = this.props.getroomandtoken.isFetching;
const { status } = this.state;
if (loading) {
return (
<View
style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
>
<Loading loading={loading} />
<Text>Preparing Room</Text>
</View>
);
}
return (
<View
style={[
styles.container,
{
backgroundColor: status === "disconnected" ? "#FFFFFF" : "#000000",
},
]}
>
{this.state.status === "disconnected" && (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<ButtonView
onPress={this._onConnectButtonPress}
style={{
backgroundColor: "#FFFFFF",
width: 150,
height: 150,
justifyContent: "center",
alignItems: "center",
borderRadius: 150 / 2,
backgroundColor: "#FFF",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.22,
shadowRadius: 2.22,
elevation: 6,
}}
>
<Image
source={Images.video_chat_icon}
style={{ width: 100, height: 100 }}
resizeMode="contain"
/>
</ButtonView>
<Text style={styles.welcome}>Push button to initiate the call</Text>
</View>
)}
{this.state.status === "connected" ||
this.state.status === "connecting" ? (
<View style={styles.callContainer}>
{this.state.status === "connected" && (
<View style={styles.remoteGrid}>
{this.state.participantJoined ? (
Array.from(
this.state.videoTracks,
([trackSid, trackIdentifier]) => {
return (
<TwilioVideoParticipantView
style={styles.remoteVideo}
key={trackSid}
trackIdentifier={trackIdentifier}
/>
);
}
)
) : (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text style={{ color: "#FFFFFF", fontSize: 20 }}>
Participant has not joined the call yet
</Text>
</View>
)}
</View>
)}
<View style={styles.optionsContainer}>
<TouchableOpacity
disabled={this.state.isBtnDisabled}
style={[styles.optionButton]}
onPress={this._onEndButtonPress}
>
<Image
source={Images.disconnect_call}
style={{ width: 60, height: 60 }}
resizeMode="contain"
/>
</TouchableOpacity>
<TouchableOpacity
disabled={this.state.isBtnDisabled}
style={[styles.optionButton, { backgroundColor: "#a0c6ed" }]}
onPress={this._onMuteButtonPress}
>
<Image
source={
this.state.isAudioEnabled
? Images.mute_mic
: Images.unmute_mic
}
style={{ width: 30, height: 30, tintColor: "#FFFFFF" }}
resizeMode="contain"
/>
</TouchableOpacity>
<TouchableOpacity
disabled={this.state.isBtnDisabled}
style={[styles.optionButton, { backgroundColor: "#a0c6ed" }]}
onPress={() => this._onMuteVideoButtonPress()}
>
<Image
source={
this.state.isVideoEnabled
? Images.mute_video
: Images.unmute_video
}
style={{ width: 30, height: 30, tintColor: "#FFFFFF" }}
resizeMode="contain"
/>
</TouchableOpacity>
<TouchableOpacity
disabled={this.state.isBtnDisabled}
style={[styles.optionButton, { backgroundColor: "#a0c6ed" }]}
onPress={this._onFlipButtonPress}
>
<Image
source={Images.flip_camera}
style={{ width: 30, height: 30, tintColor: "#FFFFFF" }}
resizeMode="contain"
/>
</TouchableOpacity>
<View />
</View>
{this.state.showVideoBox ? (
<TwilioVideoLocalView
enabled={this.state.showVideoBox}
style={styles.localVideo}
/>
) : (
<View style={styles.localVideo}></View>
)}
</View>
) : null}
<TwilioVideo
ref={this.setTwilioRef}
onParticipantDisabledVideoTrack={(res, ind) => console.log(res, ind)}
onVideoChanged={this._onVideoChanged}
onAudioChanged={this._onAudioChanged}
onRoomDidConnect={this._onRoomDidConnect}
onRoomDidDisconnect={this._onRoomDidDisconnect}
onRoomDidFailToConnect={this._onRoomDidFailToConnect}
onParticipantAddedVideoTrack={this._onParticipantAddedVideoTrack}
onParticipantRemovedVideoTrack={this._onParticipantRemovedVideoTrack}
/>
</View>
);
}
}
const mapStateToProps = ({ user, getroomandtoken }) => ({
user,
getroomandtoken,
});
const actions = { request };
export default connect(mapStateToProps, actions)(CallModule);
plus the onVideoChanged and onAudioChanged does not trigger on IOS
Looks like there's an inconsistency here. On iOS the result of the muting is returned via the promise whereas on android it's returned via the onVideoChanged callback. If you use only the latter for Android, do you get the correct events returned to you?
Yes on android it triggers the events but lets not forget what issue we are facing here, the video disabling the sound one. :|
Hi, this issue still persists on ios on latest library verion. Any solutions on how to fix it?
I am having this issue on ios, weird. Any help?