<commit_before>var websocket    = require('websocket-stream'),
    Frame        = require('canvas-to-buffer'),
    util         = require('util'),
    h            = require('hyperscript'),
    hidden       = require('hidden'),

    UserMedia = require('./userMedia'),

    Events          = require('./../../events'),
    Constants       = require('./../../constants'),
    EventEmitter    = require('./../../util/eventEmitter'),
    Browser         = require('./../../util/browser'),
    Humanize        = require('./../../util/humanize'),
    VideomailError  = require('./../../util/videomailError')

var Recorder = function(visuals, replay, options) {

    EventEmitter.call(this, options, 'Recorder')

    // validate some options this class needs
    if (!options || !options.video || !options.video.fps)
        throw VideomailError.create('FPS must be defined', options)

    var self            = this,
        browser         = new Browser(options),

        wantedInterval  = 1e3 / options.video.fps,
        debug           = options.debug,

        samplesCount = 0,
        framesCount  = 0,

        confirmedFrameNumber = 0,
        confirmedSampleNumber = 0,

        recorderElement,
        userMedia,

        lastAnimationTimestamp,
        userMediaTimeout,
        retryTimeout,

        intervalSum,
        bytesSum,

        frameProgress,
        sampleProgress,

        canvas,
        ctx,
        rafId,

        userMediaLoaded,
        userMediaLoading,
        avgFps,
        submitting,
        unloaded,
        stopTime,
        stream,
        connecting,
        connected,
        blocking,
        built,
        key,

        pingInterval

    function sendPings() {
        pingInterval = window.setInterval(function() {
            writeStream(new Buffer(''))
        }, options.timeouts.pingInterval)
    }

    function stopPings() {
        clearInterval(pingInterval)
    }

    function onAudioSample(audioSample) {
        samplesCount++

        var audioBuffer = audioSample.toBuffer()

        // if (options.verbose) {
        //     debug(
        //         'Sample #' + samplesCount + ' (' + audioBuffer.length + ' bytes):'
        //     )
        // }

        writeStream(audioBuffer)
    }

    function onUserMediaReady() {
        try {
            debug('Recorder: onUserMediaReady()')

            userMediaLoading = blocking = unloaded = submitting = false
            userMediaLoaded = true

            show()
            self.emit(Events.USER_MEDIA_READY, {paused: self.isPaused()})
        } catch (exc) {
            self.emit(Events.ERROR, exc)
        }
    }

    function clearRetryTimeout() {
        debug('Recorder: clearRetryTimeout()')

        retryTimeout && clearTimeout(retryTimeout)
        retryTimeout = null
    }

    function clearUserMediaTimeout() {
        if (userMediaTimeout) {
            debug('Recorder: clearUserMediaTimeout()')

            userMediaTimeout && clearTimeout(userMediaTimeout)
            userMediaTimeout = null
        }
    }

    function userMediaErrorCallback(err) {
        userMediaLoading = false

        clearUserMediaTimeout()

        var errorListeners = self.listeners(Events.ERROR)

        if (errorListeners.length) {
            self.emit(Events.ERROR, err)

            // retry after a while
            retryTimeout = setTimeout(initSocket, options.timeouts.userMedia)
        } else {
            debug('Recorder: no error listeners attached but throwing error', err)

            // weird situation, throw it since there are no error listeners
            throw err
        }
    }

    function showUserMedia() {
        return isNotifying() || !isHidden() || blocking
    }

    function getUserMediaCallback(localStream) {
        debug('Recorder: getUserMediaCallback()')

        if (showUserMedia()) {
            try {
                clearUserMediaTimeout()

                userMedia.init(
                    localStream,
                    onUserMediaReady.bind(self),
                    onAudioSample.bind(self),
                    function(err) {
                        self.emit(Events.ERROR, err)
                    }
                )
            } catch (exc) {
                self.emit(Events.ERROR, exc)
            }
        }
    }

    function loadGenuineUserMedia() {
        if (!navigator)
            throw new Error('Navigator is missing!')

        // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
        if (navigator.mediaDevices.getUserMedia) {
            // prefer the front camera (if one is available) over the rear one
            navigator.mediaDevices.getUserMedia({
                video: {facingMode: "user"},
                audio: options.isAudioEnabled()
            })
            .then(getUserMediaCallback)
            .catch(userMediaErrorCallback)
        } else {
            navigator.getUserMedia_({
                video: true,
                audio: options.isAudioEnabled()
            }, getUserMediaCallback, userMediaErrorCallback)
        }
    }

    function loadUserMedia() {

        if (userMediaLoaded) {
            debug('Recorder: skipping loadUserMedia() because it is already loaded')
            onUserMediaReady()
            return false
        } else if (userMediaLoading) {
            debug('Recorder: skipping loadUserMedia() because it is already asking for permission')
            return false
        }

        debug('Recorder: loadUserMedia()')<commit_msg>check media devices first<commit_after>var websocket    = require('websocket-stream'),
    Frame        = require('canvas-to-buffer'),
    util         = require('util'),
    h            = require('hyperscript'),
    hidden       = require('hidden'),

    UserMedia = require('./userMedia'),

    Events          = require('./../../events'),
    Constants       = require('./../../constants'),
    EventEmitter    = require('./../../util/eventEmitter'),
    Browser         = require('./../../util/browser'),
    Humanize        = require('./../../util/humanize'),
    VideomailError  = require('./../../util/videomailError')

var Recorder = function(visuals, replay, options) {

    EventEmitter.call(this, options, 'Recorder')

    // validate some options this class needs
    if (!options || !options.video || !options.video.fps)
        throw VideomailError.create('FPS must be defined', options)

    var self            = this,
        browser         = new Browser(options),

        wantedInterval  = 1e3 / options.video.fps,
        debug           = options.debug,

        samplesCount = 0,
        framesCount  = 0,

        confirmedFrameNumber = 0,
        confirmedSampleNumber = 0,

        recorderElement,
        userMedia,

        lastAnimationTimestamp,
        userMediaTimeout,
        retryTimeout,

        intervalSum,
        bytesSum,

        frameProgress,
        sampleProgress,

        canvas,
        ctx,
        rafId,

        userMediaLoaded,
        userMediaLoading,
        avgFps,
        submitting,
        unloaded,
        stopTime,
        stream,
        connecting,
        connected,
        blocking,
        built,
        key,

        pingInterval

    function sendPings() {
        pingInterval = window.setInterval(function() {
            writeStream(new Buffer(''))
        }, options.timeouts.pingInterval)
    }

    function stopPings() {
        clearInterval(pingInterval)
    }

    function onAudioSample(audioSample) {
        samplesCount++

        var audioBuffer = audioSample.toBuffer()

        // if (options.verbose) {
        //     debug(
        //         'Sample #' + samplesCount + ' (' + audioBuffer.length + ' bytes):'
        //     )
        // }

        writeStream(audioBuffer)
    }

    function onUserMediaReady() {
        try {
            debug('Recorder: onUserMediaReady()')

            userMediaLoading = blocking = unloaded = submitting = false
            userMediaLoaded = true

            show()
            self.emit(Events.USER_MEDIA_READY, {paused: self.isPaused()})
        } catch (exc) {
            self.emit(Events.ERROR, exc)
        }
    }

    function clearRetryTimeout() {
        debug('Recorder: clearRetryTimeout()')

        retryTimeout && clearTimeout(retryTimeout)
        retryTimeout = null
    }

    function clearUserMediaTimeout() {
        if (userMediaTimeout) {
            debug('Recorder: clearUserMediaTimeout()')

            userMediaTimeout && clearTimeout(userMediaTimeout)
            userMediaTimeout = null
        }
    }

    function userMediaErrorCallback(err) {
        userMediaLoading = false

        clearUserMediaTimeout()

        var errorListeners = self.listeners(Events.ERROR)

        if (errorListeners.length) {
            self.emit(Events.ERROR, err)

            // retry after a while
            retryTimeout = setTimeout(initSocket, options.timeouts.userMedia)
        } else {
            debug('Recorder: no error listeners attached but throwing error', err)

            // weird situation, throw it since there are no error listeners
            throw err
        }
    }

    function showUserMedia() {
        return isNotifying() || !isHidden() || blocking
    }

    function getUserMediaCallback(localStream) {
        debug('Recorder: getUserMediaCallback()')

        if (showUserMedia()) {
            try {
                clearUserMediaTimeout()

                userMedia.init(
                    localStream,
                    onUserMediaReady.bind(self),
                    onAudioSample.bind(self),
                    function(err) {
                        self.emit(Events.ERROR, err)
                    }
                )
            } catch (exc) {
                self.emit(Events.ERROR, exc)
            }
        }
    }

    function loadGenuineUserMedia() {
        if (!navigator)
            throw new Error('Navigator is missing!')

        // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
        if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
            // prefer the front camera (if one is available) over the rear one
            navigator.mediaDevices.getUserMedia({
                video: {facingMode: "user"},
                audio: options.isAudioEnabled()
            })
            .then(getUserMediaCallback)
            .catch(userMediaErrorCallback)
        } else {
            navigator.getUserMedia_({
                video: true,
                audio: options.isAudioEnabled()
            }, getUserMediaCallback, userMediaErrorCallback)
        }
    }

    function loadUserMedia() {

        if (userMediaLoaded) {
            debug('Recorder: skipping loadUserMedia() because it is already loaded')
            onUserMediaReady()
            return false
        } else if (userMediaLoading) {
            debug('Recorder: skipping loadUserMedia() because it is already asking for permission')
            return false
        }

        debug('Recorder: loadUserMedia()')
{'fraction_non_alphanumeric': 0.10323338150289017, 'fraction_numerical': 0.001083815028901734, 'mean_word_length': 1.7027092994874298, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6938377', 'n_tokens_mistral': 2897, 'n_tokens_neox': 2766, 'n_words': 589}