"use strict";
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.getQualityAfterLegacyModeShift = exports.setOnDeviceChange = exports.getScreenShare = exports.getSpeakerTrack = exports.getAudioTrack = exports.getVideoTrack = exports.getScreenShareConstraints = exports.getWebcamConstraints = exports.getAllVideoDevices = exports.AudioDevicesEmitter = exports.getAllMediaDevices = void 0;
const WebRTC_1 = require("../consolidatedLibraries/WebRTC");
const BluetoothHeadsetDetect_1 = require("../consolidatedLibraries/BluetoothHeadsetDetect");
const react_native_1 = require("react-native");
const RoomConfig_1 = require("../RoomConfig");
const RNInCallManager_1 = __importDefault(require("../consolidatedLibraries/RNInCallManager"));
const masterOut = react_native_1.NativeModules.InCallManager;
const masterOutEmitter = new react_native_1.NativeEventEmitter(masterOut);
const getAllMediaDevices = () => __awaiter(void 0, void 0, void 0, function* () {
    const devices = yield WebRTC_1.mediaDevices.enumerateDevices();
    return devices;
});
exports.getAllMediaDevices = getAllMediaDevices;
// Get All audio device should emit all audio device and whenever device changes
// Initially we will have default audio as phone microphone
// then we will have listener for bluetooth and wiredheadset which will emit code upwards
// Event listener code
class AudioDevicesEmitter {
    constructor(callback) {
        if (!callback) {
            throw new Error('Callback not initalized');
        }
        this.callback = callback;
        // Not doing anything with haveMic for now
        this.notConnected = {
            connected: false,
            haveMic: false,
        };
        this.connectedWithMic = {
            connected: true,
            haveMic: true,
        };
        this.connectedWithoutMic = {
            connected: true,
            haveMic: false,
        };
        const bluetoothDeviceConnected = BluetoothHeadsetDetect_1.getHeadset();
        this.audioDevices = {
            speaker: this.connectedWithMic,
            bluetooth: bluetoothDeviceConnected
                ? this.connectedWithMic
                : this.notConnected,
            wired: this.notConnected,
        };
        this.checkIfWiredHeadphonesConnected();
        this.onBluetoothEvent();
        this.onWiredHeadsetEvent();
        this.emit();
        this.wiredHeadListener = null;
    }
    checkIfWiredHeadphonesConnected() {
        return __awaiter(this, void 0, void 0, function* () {
            const isWiredHeadphonesConnected = yield RNInCallManager_1.default.getIsWiredHeadsetPluggedIn();
            this.audioDevices = Object.assign(Object.assign({}, this.audioDevices), { wired: isWiredHeadphonesConnected
                    ? this.connectedWithMic
                    : this.notConnected });
            this.emit();
        });
    }
    onBluetoothEvent() {
        BluetoothHeadsetDetect_1.addListener((bluetoothDevice) => {
            const { connected } = this.audioDevices.bluetooth;
            // TODO: Setting haveMic default to true because
            // bluetooth package does not detect if wireless device have mic or not
            if (bluetoothDevice && !connected) {
                this.audioDevices = Object.assign(Object.assign({}, this.audioDevices), { bluetooth: Object.assign({}, this.connectedWithMic) });
                this.emit();
            }
            else if (!bluetoothDevice && connected) {
                this.audioDevices = Object.assign(Object.assign({}, this.audioDevices), { bluetooth: Object.assign({}, this.notConnected) });
                this.emit();
            }
        });
    }
    onWiredHeadsetEvent() {
        this.wiredHeadListener = masterOutEmitter.addListener('WiredHeadset', (data) => {
            if (data) {
                const { isPlugged, hasMic } = data;
                const { connected } = this.audioDevices.wired;
                if (isPlugged && !connected) {
                    const wired = hasMic
                        ? Object.assign({}, this.connectedWithMic) : Object.assign({}, this.connectedWithoutMic);
                    this.audioDevices = Object.assign(Object.assign({}, this.audioDevices), { wired });
                    this.emit();
                }
                else if (!isPlugged && connected) {
                    this.audioDevices = Object.assign(Object.assign({}, this.audioDevices), { wired: Object.assign({}, this.notConnected) });
                    this.emit();
                }
            }
        });
    }
    getAudioDevices() {
        return this.formatAudioDevices();
    }
    formatAudioDevices() {
        return Object.keys(this.audioDevices)
            .map((audioDevice) => {
            const audioDeviceProps = this.audioDevices[audioDevice];
            return Object.assign(Object.assign({}, audioDeviceProps), { deviceId: audioDevice, label: audioDevice, kind: 'audioinput' });
        })
            .filter((audioDevice) => audioDevice.connected);
    }
    emit() {
        this.callback(this.formatAudioDevices());
    }
    removeListener() {
        var _a;
        (_a = this.wiredHeadListener) === null || _a === void 0 ? void 0 : _a.remove();
    }
}
exports.AudioDevicesEmitter = AudioDevicesEmitter;
// Samsung devices gives multiple front and back video camera
// Log 1: https://sentry.io/organizations/dyte-in/issues/2654518025/events/9035bfb550fa4de7b3aa698534edd7da/?environment=production&project=5766483
// Log 2: https://sentry.io/organizations/dyte-in/issues/2654518025/events/748b9a99288d4845bde888a7ea925622/?environment=production&project=5766483
const getAllVideoDevices = () => __awaiter(void 0, void 0, void 0, function* () {
    const deviceMem = {};
    const devices = yield exports.getAllMediaDevices();
    if (Array.isArray(devices)) {
        return devices.filter((d) => {
            if (d.kind === 'videoinput' && !deviceMem[d.facing]) {
                deviceMem[d.facing] = true;
                return d;
            }
            return false;
        });
    }
    return [];
});
exports.getAllVideoDevices = getAllVideoDevices;
const getWebcamConstraints = (quality, frameRate) => {
    const constraints = RoomConfig_1.VIDEO_CONSTRAINS[quality.toLowerCase()];
    if (!constraints) {
        throw new Error('Invalid quality');
    }
    if (frameRate) {
        if (frameRate < 5 || frameRate > 30) {
            throw new Error('Invalid framerate');
        }
        constraints.frameRate = { ideal: frameRate };
    }
    return constraints;
};
exports.getWebcamConstraints = getWebcamConstraints;
const getScreenShareConstraints = (quality, frameRate) => {
    const constraints = RoomConfig_1.VIDEO_CONSTRAINS_SCREENSHARE[quality.toLowerCase() || 'vga'];
    if (!constraints) {
        throw new Error('Invalid quality');
    }
    if (frameRate) {
        if (frameRate < 5 || frameRate > 30) {
            throw new Error('Invalid framerate');
        }
        constraints.frameRate = { max: frameRate };
    }
    return constraints;
};
exports.getScreenShareConstraints = getScreenShareConstraints;
const getVideoTrack = (deviceId, quality) => __awaiter(void 0, void 0, void 0, function* () {
    const qual = quality || RoomConfig_1.VIDEO_CONSTRAINS.vga;
    const stream = yield WebRTC_1.mediaDevices.getUserMedia({
        video: Object.assign({ deviceId: deviceId || '', frameRate: 24 }, qual),
        audio: false,
    });
    return stream.getVideoTracks()[0];
});
exports.getVideoTrack = getVideoTrack;
const getAudioTrack = () => __awaiter(void 0, void 0, void 0, function* () {
    const stream = yield WebRTC_1.mediaDevices.getUserMedia({
        audio: true,
        video: false,
    });
    return stream.getAudioTracks()[0];
});
exports.getAudioTrack = getAudioTrack;
const getSpeakerTrack = (deviceId) => __awaiter(void 0, void 0, void 0, function* () {
    const advanced = {};
    // const stream = await mediaDevices.getUserMedia(
    // 	{
    // 		audio:
    // 		{
    // 			deviceId: { ideal: deviceId || '' },
    // 			...advanced,
    // 		},
    // 		video: false,
    // 	},
    // );
    return null;
});
exports.getSpeakerTrack = getSpeakerTrack;
const getScreenShare = () => __awaiter(void 0, void 0, void 0, function* () {
    // @ts-ignore
    const stream = yield WebRTC_1.mediaDevices.getDisplayMedia({
        audio: true,
        video: {
            displaySurface: 'monitor',
            logicalSurface: true,
            cursor: true,
            width: { max: 1920 },
            height: { max: 1080 },
            frameRate: { max: 5 },
        },
    });
    return { video: stream.getTracks()[0], audio: null };
});
exports.getScreenShare = getScreenShare;
const setOnDeviceChange = (callback) => {
    /* mediaDevices.ondevicechange = () => {
        callback();
    }; */
};
exports.setOnDeviceChange = setOnDeviceChange;
const getQualityAfterLegacyModeShift = (isLegacy, joinedPeersLength, previousVideoQuality) => {
    if (joinedPeersLength === RoomConfig_1.HD_QUALITY_PEERS_LIMIT && isLegacy) {
        return RoomConfig_1.VIDEO_CONSTRAINS.vga;
    }
    if (joinedPeersLength === RoomConfig_1.HD_QUALITY_PEERS_LIMIT + 1 && !isLegacy) {
        return RoomConfig_1.VIDEO_CONSTRAINS.hd;
    }
    return previousVideoQuality;
};
exports.getQualityAfterLegacyModeShift = getQualityAfterLegacyModeShift;
//# sourceMappingURL=media-utils.js.map