"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserTrackContext = void 0;
const react_1 = __importStar(require("react"));
const react_redux_1 = require("react-redux");
const roomSlice_1 = require("../store/roomSlice");
const media_utils_1 = require("../utils/media-utils");
const participantSlice_1 = require("../store/participantSlice");
const ConfigProvider_1 = require("../utils/ConfigProvider");
const RNInCallManager_1 = __importDefault(require("../consolidatedLibraries/RNInCallManager"));
const src_1 = require("../utils/dyte-utils/src");
const react_native_1 = require("react-native");
const logger_1 = __importDefault(require("../utils/logger"));
const masterOut = react_native_1.NativeModules.InCallManager;
const masterOutEmitter = new react_native_1.NativeEventEmitter(masterOut);
exports.UserTrackContext = react_1.createContext(null);
function UserTrackProvider(props) {
    var _a, _b, _c;
    const [audioTrack, setAudioTrack] = react_1.useState();
    const [audioInputDevices, setAudioInputDevices] = react_1.useState([]);
    const [webcamTrack, setWebcamTrack] = react_1.useState();
    const [videoInputDevices, setVideoInputDevices] = react_1.useState([]);
    const [screenShareVideoTrack, setScreenShareVideoTrack] = react_1.useState();
    const [screenShareAudioTrack, setScreenShareAudioTrack] = react_1.useState();
    const webcamTrackSave = react_1.useRef(null);
    const screenShareVideoTrackSave = react_1.useRef(null);
    const screenShareAudioTrackSave = react_1.useRef(null);
    const audioTrackSave = react_1.useRef(null);
    const { meeting, sessionConfig } = react_1.useContext(ConfigProvider_1.ConfigServiceContext);
    const { audio: audioAllowed } = sessionConfig.permissions.produce;
    const videoConfig = sessionConfig.permissions.produce.video;
    const screenshareConfig = sessionConfig.permissions.produce.video;
    const videoAllowed = videoConfig.allow;
    let webcamConstraints = media_utils_1.getWebcamConstraints(videoConfig.quality, videoConfig.frame_rate);
    const screenshareConstraints = media_utils_1.getScreenShareConstraints(screenshareConfig.quality, screenshareConfig.frame_rate);
    const { children } = props;
    const audioMuted = react_redux_1.useSelector((state) => state.participant.audioMuted);
    const videoOff = react_redux_1.useSelector((state) => state.participant.videoOff);
    const producersState = react_redux_1.useSelector((state) => state.room.producersState);
    const switched = react_redux_1.useSelector((state) => state.participant.switched);
    const canPresent = react_redux_1.useSelector((state) => state.participant.canPresent);
    const presentingState = react_redux_1.useSelector((state) => state.participant.presentingState);
    const audioTrackSelection = react_redux_1.useSelector((state) => state.participant.audioTrackSelection);
    const videoTrackSelection = react_redux_1.useSelector((state) => state.participant.videoTrackSelection);
    const videoProduction = react_redux_1.useSelector((state) => state.participant.videoProduction);
    const audioProduction = react_redux_1.useSelector((state) => state.participant.audioProduction);
    const webinarPresentState = react_redux_1.useSelector((state) => state.participant.presentingState);
    const videoButtonsEnabled = (producersState === roomSlice_1.MediaStates.NOT_APPLICABLE
        || videoProduction === roomSlice_1.MediaStates.LOADED
        || videoProduction === roomSlice_1.MediaStates.NOT_STARTED
        || (videoProduction === roomSlice_1.MediaStates.STOPPING
            && webinarPresentState !== participantSlice_1.PresentingState.NOT_PRESENTING)) && videoAllowed;
    const audioButtonsEnabled = (producersState === roomSlice_1.MediaStates.NOT_APPLICABLE
        || audioProduction === roomSlice_1.MediaStates.LOADED
        || audioProduction === roomSlice_1.MediaStates.NOT_STARTED
        || (audioProduction === roomSlice_1.MediaStates.STOPPING
            && webinarPresentState !== participantSlice_1.PresentingState.NOT_PRESENTING)) && audioAllowed;
    const dispatch = react_redux_1.useDispatch();
    const [audioDevices, setAudioDevices] = react_1.default.useState([]);
    const getAllAudioDevices = (devices) => {
        setAudioDevices(devices);
    };
    const roomViewType = react_redux_1.useSelector((state) => state.room.roomViewType);
    const requestToJoinType = react_redux_1.useSelector((state) => state.participant.requestToJoinType);
    const routerState = react_redux_1.useSelector((state) => state.room.routerState);
    if (roomViewType === src_1.DyteViewTypes.webinar && requestToJoinType === participantSlice_1.RequestToJoinType.ask) {
        webcamConstraints = media_utils_1.getWebcamConstraints('QQVGA', (_c = (_b = (_a = sessionConfig.permissions) === null || _a === void 0 ? void 0 : _a.produce) === null || _b === void 0 ? void 0 : _b.video) === null || _c === void 0 ? void 0 : _c.frame_rate);
    }
    react_1.useEffect(() => {
        webcamTrackSave.current = webcamTrack;
        screenShareVideoTrackSave.current = screenShareVideoTrack;
        screenShareAudioTrackSave.current = screenShareAudioTrack;
        audioTrackSave.current = audioTrack;
    }, [webcamTrack, screenShareVideoTrack, screenShareAudioTrack, audioTrack]);
    react_1.useEffect(() => {
        logger_1.default.trace('audioMuted_useEffect', {
            audioMuted,
            presentingState,
        });
        if (audioTrack) {
            audioTrack.enabled = !audioMuted;
        }
        if (roomViewType !== src_1.DyteViewTypes.webinar
            || presentingState === participantSlice_1.PresentingState.PRESENTING) {
            dispatch(participantSlice_1.setAudioProduction(roomSlice_1.MediaStates.CONNECTING));
        }
    }, [audioMuted, presentingState]);
    const initialAudioStreamFetch = () => __awaiter(this, void 0, void 0, function* () {
        try {
            logger_1.default.trace('initialAudioStreamFetch');
            let audTrack = null;
            try {
                audTrack = yield media_utils_1.getAudioTrack();
            }
            catch (e) {
                if (e.name === 'NotAllowedError') {
                    throw new Error('No audio permission');
                }
            }
            if (!audTrack) {
                throw new Error('No audio track');
            }
            // AudioTrack
            if (audioAllowed) {
                setAudioTrack(audTrack);
            }
        }
        catch (err) {
            logger_1.default.error('initialAudioStreamFetch', err);
            dispatch(participantSlice_1.setAudioProduction(roomSlice_1.MediaStates.NOT_APPLICABLE));
            dispatch(participantSlice_1.setAudioMuted(true));
        }
    });
    const setAudioDevice = (newDevice) => {
        logger_1.default.trace('setAudioDevice', {
            audioTrack: !!audioTrack,
        });
        if (audioTrack) {
            audioTrack.stop();
        }
        if (!audioAllowed) {
            dispatch(participantSlice_1.setAudioMuted(true));
            return;
        }
        const deviceId = (newDevice === null || newDevice === void 0 ? void 0 : newDevice.deviceId) || (audioTrackSelection === null || audioTrackSelection === void 0 ? void 0 : audioTrackSelection.selectedDeviceId);
        react_redux_1.batch(() => __awaiter(this, void 0, void 0, function* () {
            yield initialAudioStreamFetch();
            dispatch(participantSlice_1.setAudioProduction(roomSlice_1.MediaStates.CONNECTING));
            if ((audioTrackSelection === null || audioTrackSelection === void 0 ? void 0 : audioTrackSelection.selectedDeviceId) !== deviceId) {
                dispatch(participantSlice_1.setAudioTrackSelection({
                    selectedDeviceId: deviceId,
                }));
            }
        }));
    };
    const initialVideoStreamFetch = () => __awaiter(this, void 0, void 0, function* () {
        try {
            logger_1.default.trace('initialVideoStreamFetch');
            let videoDevices = yield media_utils_1.getAllVideoDevices();
            const frontCamera = videoDevices.filter((el) => el.facing === 'front');
            const currentVideoDevice = frontCamera.length > 0 ? frontCamera[0] : videoDevices[0];
            let videoTrack = null;
            try {
                videoTrack = yield media_utils_1.getVideoTrack(currentVideoDevice.deviceId || '', webcamConstraints);
            }
            catch (e) {
                if (e.name === 'NotAllowedError') {
                    throw new Error('No video permission');
                }
            }
            if (!videoTrack) {
                throw new Error('No video track');
            }
            if (videoAllowed) {
                setWebcamTrack(videoTrack);
            }
            if (currentVideoDevice.label === '') {
                videoDevices = yield media_utils_1.getAllVideoDevices();
            }
            setVideoInputDevices(videoDevices);
            dispatch(participantSlice_1.setVideoTrackSelection({
                selectedDeviceId: currentVideoDevice.deviceId,
            }));
        }
        catch (err) {
            logger_1.default.error('initialVideoStreamFetch', err);
            dispatch(participantSlice_1.setVideoProduction(roomSlice_1.MediaStates.NOT_APPLICABLE));
            dispatch(participantSlice_1.setVideoOff(true));
        }
    });
    const setVideoDevice = (newDevice) => __awaiter(this, void 0, void 0, function* () {
        logger_1.default.trace('setVideoDevice');
        const deviceId = (newDevice === null || newDevice === void 0 ? void 0 : newDevice.deviceId) || (videoTrackSelection === null || videoTrackSelection === void 0 ? void 0 : videoTrackSelection.selectedDeviceId);
        if (!videoAllowed) {
            dispatch(participantSlice_1.setVideoOff(true));
            return;
        }
        react_redux_1.batch(() => {
            dispatch(participantSlice_1.setVideoOff(false));
            dispatch(participantSlice_1.setVideoProduction(roomSlice_1.MediaStates.CONNECTING));
            if ((videoTrackSelection === null || videoTrackSelection === void 0 ? void 0 : videoTrackSelection.selectedDeviceId) !== deviceId) {
                dispatch(participantSlice_1.setVideoTrackSelection({
                    selectedDeviceId: deviceId,
                }));
            }
        });
        setTimeout(() => __awaiter(this, void 0, void 0, function* () {
            if (webcamTrack) {
                webcamTrack.stop();
            }
            const newVideoTrack = yield media_utils_1.getVideoTrack(deviceId, webcamConstraints);
            setWebcamTrack(newVideoTrack);
        }));
    });
    react_1.useEffect(() => {
        if (roomViewType === src_1.DyteViewTypes.webinar
            && routerState === roomSlice_1.MediaStates.LOADED
            && webinarPresentState === participantSlice_1.PresentingState.NOT_PRESENTING) {
            react_redux_1.batch(() => {
                dispatch(participantSlice_1.setVideoProduction(roomSlice_1.MediaStates.STOPPING));
                dispatch(participantSlice_1.setAudioProduction(roomSlice_1.MediaStates.STOPPING));
                dispatch(participantSlice_1.setVideoOff(true));
                dispatch(participantSlice_1.setAudioMuted(true));
                setTimeout(() => {
                    if (webcamTrack) {
                        webcamTrack.stop();
                    }
                    if (audioTrack) {
                        audioTrack.stop();
                    }
                    setAudioTrack(undefined);
                    setWebcamTrack(undefined);
                });
            });
        }
        else if (webinarPresentState === participantSlice_1.PresentingState.INITIATED) {
            initialVideoStreamFetch().then(setVideoDevice);
            setAudioDevice();
        }
    }, [routerState, webinarPresentState]);
    react_1.useEffect(() => {
        RNInCallManager_1.default.start({
            media: 'video',
        });
        const audioDeviceEmitter = new media_utils_1.AudioDevicesEmitter(getAllAudioDevices);
        const x = () => __awaiter(this, void 0, void 0, function* () {
            if (webcamTrackSave.current) {
                webcamTrackSave.current.stop();
            }
            if (audioTrackSave.current) {
                audioTrackSave.current.stop();
            }
            if (screenShareVideoTrackSave.current) {
                screenShareVideoTrackSave.current.stop();
            }
            if (screenShareAudioTrackSave.current) {
                screenShareAudioTrackSave.current.stop();
            }
        });
        x();
        return () => {
            audioDeviceEmitter.removeListener();
        };
    }, []);
    react_1.default.useEffect(() => {
        if (!videoAllowed) {
            dispatch(participantSlice_1.setVideoOff(true));
            setTimeout(() => {
                if (webcamTrack) {
                    webcamTrack.stop();
                    setWebcamTrack(undefined);
                    participantSlice_1.setVideoProduction(roomSlice_1.MediaStates.CONNECTING);
                }
            });
        }
    }, [videoAllowed, webcamTrack]);
    react_1.useEffect(() => {
        if (videoProduction === roomSlice_1.MediaStates.NOT_STARTED) {
            setTimeout(() => {
                if (webcamTrack) {
                    webcamTrack.stop();
                    setWebcamTrack(undefined);
                }
            });
        }
    }, [videoProduction]);
    const toggleAudioState = () => __awaiter(this, void 0, void 0, function* () {
        logger_1.default.trace('toggleAudioState', {
            audioButtonsEnabled,
            audioAllowed,
            audioMuted,
            audioTrack: !!audioTrack,
        });
        if (!audioButtonsEnabled) {
            return;
        }
        if (!audioAllowed) {
            if (!audioMuted) {
                dispatch(participantSlice_1.setAudioMuted(true));
            }
        }
        else if (audioMuted) {
            if (!audioTrack || (audioTrack === null || audioTrack === void 0 ? void 0 : audioTrack.readyState) === 'ended') {
                setAudioDevice(undefined);
            }
            dispatch(participantSlice_1.setAudioMuted(false));
        }
        else {
            dispatch(participantSlice_1.setAudioMuted(true));
        }
    });
    const disableVideoStream = () => {
        react_redux_1.batch(() => {
            dispatch(participantSlice_1.setVideoProduction(roomSlice_1.MediaStates.CONNECTING));
            dispatch(participantSlice_1.setVideoOff(true));
            setTimeout(() => {
                if (webcamTrack) {
                    webcamTrack.stop();
                }
                setWebcamTrack(undefined);
            });
        });
    };
    react_1.useEffect(() => {
        if (!audioAllowed) {
            dispatch(participantSlice_1.setAudioMuted(true));
        }
        if (!videoAllowed) {
            disableVideoStream();
        }
    }, [audioAllowed, videoAllowed]);
    react_1.useEffect(() => {
        if (switched === 'meeting') {
            if (!videoOff)
                disableVideoStream();
        }
        else if (switched === 'webinar') {
            if (!canPresent) {
                if (!audioMuted)
                    dispatch(participantSlice_1.setAudioMuted(true));
                if (!videoOff)
                    disableVideoStream();
            }
        }
    }, [switched]);
    const toggleVideoState = (stop) => __awaiter(this, void 0, void 0, function* () {
        logger_1.default.trace('toggleVideoState', {
            videoButtonsEnabled,
            videoOff,
        });
        if (!videoButtonsEnabled) {
            return;
        }
        if (videoOff) {
            setVideoDevice();
        }
        else {
            disableVideoStream();
        }
    });
    const setupStreams = () => __awaiter(this, void 0, void 0, function* () {
        yield initialVideoStreamFetch();
        yield initialAudioStreamFetch();
    });
    const changeAudioTrack = (selectedDevice = null) => __awaiter(this, void 0, void 0, function* () {
        logger_1.default.trace('changeAudioTrack', {
            selectedDevice,
            audioDevices,
        });
        if (audioDevices.length > 0) {
            const devicesKey = {};
            let audioTrackToChange = {
                deviceId: null,
                InCallManagerId: null,
                device: null,
            };
            if (!selectedDevice) {
                audioDevices.forEach((device) => {
                    const { deviceId } = device;
                    devicesKey[deviceId] = device;
                });
            }
            else {
                const selectedDeviceId = selectedDevice.deviceId;
                devicesKey[selectedDeviceId] = selectedDevice;
            }
            if (devicesKey.wired) {
                audioTrackToChange = {
                    deviceId: 'wired',
                    InCallManagerId: 'WIRED_HEADSET',
                    device: devicesKey.wired,
                };
            }
            else if (devicesKey.bluetooth) {
                audioTrackToChange = {
                    deviceId: 'bluetooth',
                    InCallManagerId: 'BLUETOOTH',
                    device: devicesKey.bluetooth,
                };
            }
            else if (devicesKey.speaker) {
                audioTrackToChange = {
                    deviceId: 'speaker',
                    InCallManagerId: 'SPEAKER_PHONE',
                    device: devicesKey.speaker,
                };
            }
            yield RNInCallManager_1.default.chooseAudioRoute(audioTrackToChange.InCallManagerId);
            setAudioDevice(audioTrackToChange.device);
        }
    });
    const onAudioInputChange = (value) => __awaiter(this, void 0, void 0, function* () {
        logger_1.default.trace('onAudioInputChange', {
            value,
        });
        const newDevice = audioInputDevices
            .find((dev) => dev.deviceId === value);
        changeAudioTrack(newDevice);
    });
    const onVideoInputChange = (value) => {
        logger_1.default.trace('onVideoInputChange', {
            value,
        });
        const newDevice = videoInputDevices
            .find((dev) => dev.deviceId === value);
        dispatch(participantSlice_1.setCameraFacing(newDevice.facing));
        setVideoDevice(newDevice);
    };
    // TOUNDERSTAND: When is on OnDeviceChange called
    media_utils_1.setOnDeviceChange(() => __awaiter(this, void 0, void 0, function* () {
        const videoDevices = yield media_utils_1.getAllVideoDevices();
        // TOUNDERSTAND What does below code do?
        const newAudioDevice = [...audioDevices]
            .find((device) => !audioInputDevices.map((d) => d.deviceId).includes(device.deviceId));
        setAudioInputDevices(audioDevices);
        const newVideoDevice = videoDevices
            .find((device) => !videoInputDevices.map((d) => d.deviceId).includes(device.deviceId));
        setVideoInputDevices(videoDevices);
        if (!audioMuted && newAudioDevice) {
            setAudioDevice(newAudioDevice);
            return;
        }
        if (!videoOff && newVideoDevice) {
            setVideoDevice(newVideoDevice);
            return;
        }
        const isCurrentAudioDeviceUnplugged = !audioDevices
            .map((d) => d.deviceId).includes(audioTrackSelection === null || audioTrackSelection === void 0 ? void 0 : audioTrackSelection.selectedDeviceId);
        const isCurrentVideoDeviceUnplugged = !videoDevices
            .map((d) => d.deviceId).includes(videoTrackSelection === null || videoTrackSelection === void 0 ? void 0 : videoTrackSelection.selectedDeviceId);
        if (!audioMuted && (audioTrack === undefined || isCurrentAudioDeviceUnplugged)) {
            const currentDevice = audioDevices[0];
            setAudioDevice(currentDevice);
        }
        if (!videoOff && (webcamTrack === undefined || isCurrentVideoDeviceUnplugged)) {
            const currentDevice = videoDevices[0];
            setVideoDevice(currentDevice);
        }
    }));
    react_1.useEffect(() => {
        changeAudioTrack(undefined);
        setAudioInputDevices(audioDevices);
    }, [audioDevices]);
    const context = {
        mediaTracks: {
            webcamTrack,
            setWebcamTrack,
            audioTrack,
            setAudioTrack,
            screenShareVideoTrack,
            setScreenShareVideoTrack,
            screenShareAudioTrack,
            setScreenShareAudioTrack,
        },
        inputDevices: {
            audioInputDevices,
            videoInputDevices,
            setAudioInputDevices,
            setVideoInputDevices,
            setAudioDevice,
            setVideoDevice,
            toggleAudioState,
            toggleVideoState,
            onAudioInputChange,
            onVideoInputChange,
        },
        setupStreams,
        videoButtonsEnabled,
        audioButtonsEnabled,
    };
    return (react_1.default.createElement(exports.UserTrackContext.Provider, { value: context }, children));
}
exports.default = UserTrackProvider;
//# sourceMappingURL=UserTrackProvider.js.map