Completed
Push — master ( 93164a...2ac899 )
by Jacob
01:57
created

tinymce/js/audiomodule.js   A

Complexity

Total Complexity 35
Complexity/F 2.33

Size

Lines of Code 201
Function Count 15

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 0
c 4
b 1
f 0
nc 6
dl 0
loc 201
rs 9
wmc 35
mnd 5
bc 27
fnc 15
bpm 1.8
cpm 2.3333
noi 0

2 Functions

Rating   Name   Duplication   Size   Complexity  
A M.tinymce_recordrtc.capture_audio 0 21 1
A M.tinymce_recordrtc.stop_recording_audio 0 52 1
1
// TinyMCE recordrtc library functions.
2
// @package    tinymce_recordrtc.
3
// @author     Jesus Federico  (jesus [at] blindsidenetworks [dt] com).
4
// @copyright  2016 to present, Blindside Networks Inc.
5
// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
6
7
// Scrutinizer CI directives.
8
/** global: M */
9
/** global: Y */
10
/** global: tinyMCEPopup */
11
/** global: recordrtc */
12
/** global: alertWarning */
13
/** global: alertDanger */
14
/** global: blobSize */
15
/** global: chunks */
16
/** global: countdownSeconds */
17
/** global: countdownTicker */
18
/** global: maxUploadSize */
19
/** global: mediaRecorder */
20
/** global: player */
21
/** global: playerDOM */
22
/** global: recType */
23
/** global: startStopBtn */
24
/** global: uploadBtn */
25
26
// This function is initialized from PHP.
27
M.tinymce_recordrtc.view_init = function() {
28
    // Assignment of global variables.
29
    alertWarning = Y.one('div#alert-warning');
30
    alertDanger = Y.one('div#alert-danger');
31
    player = Y.one('audio#player');
32
    playerDOM = document.querySelector('audio#player');
33
    startStopBtn = Y.one('button#start-stop');
34
    uploadBtn = Y.one('button#upload');
35
    recType = 'audio';
36
    // Extract the numbers from the string, and convert to bytes.
37
    maxUploadSize = window.parseInt(recordrtc.maxfilesize.match(/\d+/)[0], 10) * Math.pow(1024, 2);
38
39
    // Show alert and redirect user if connection is not secure.
40
    M.tinymce_recordrtc.check_secure();
41
    // Show alert if using non-ideal browser.
42
    M.tinymce_recordrtc.check_browser();
43
44
    // Run when user clicks on "record" button.
45
    startStopBtn.on('click', function() {
46
        startStopBtn.set('disabled', true);
47
48
        // If button is displaying "Start Recording" or "Record Again".
49
        if ((startStopBtn.get('textContent') === M.util.get_string('startrecording', 'tinymce_recordrtc')) ||
50
            (startStopBtn.get('textContent') === M.util.get_string('recordagain', 'tinymce_recordrtc')) ||
51
            (startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'tinymce_recordrtc'))) {
52
            // Make sure the audio player and upload button are not shown.
53
            player.ancestor().ancestor().addClass('hide');
54
            uploadBtn.ancestor().ancestor().addClass('hide');
55
56
            // Change look of recording button.
57
            if (!recordrtc.oldermoodle) {
58
                startStopBtn.replaceClass('btn-outline-danger', 'btn-danger');
59
            }
60
61
            // Empty the array containing the previously recorded chunks.
62
            chunks = [];
63
            blobSize = 0;
64
65
            // Initialize common configurations.
66
            var commonConfig = {
67
                // When the stream is captured from the microphone/webcam.
68
                onMediaCaptured: function(stream) {
69
                    // Make audio stream available at a higher level by making it a property of startStopBtn.
70
                    startStopBtn.stream = stream;
71
72
                    M.tinymce_recordrtc.start_recording(recType, startStopBtn.stream);
73
                },
74
75
                // Revert button to "Record Again" when recording is stopped.
76
                onMediaStopped: function(btnLabel) {
77
                    startStopBtn.set('textContent', btnLabel);
78
                    startStopBtn.set('disabled', false);
79
                    if (!recordrtc.oldermoodle) {
80
                        startStopBtn.replaceClass('btn-danger', 'btn-outline-danger');
81
                    }
82
                },
83
84
                // Handle recording errors.
85
                onMediaCapturingFailed: function(error) {
86
                    var btnLabel = M.util.get_string('recordingfailed', 'tinymce_recordrtc');
87
                    var treatAsStopped = function() {
88
                        commonConfig.onMediaStopped(btnLabel);
89
                    };
90
91
                    // Handle getUserMedia-thrown errors.
92
                    // After alert, proceed to treat as stopped recording, or close dialogue.
93
                    switch (error.name) {
94
                        case 'AbortError':
95
                            M.tinymce_recordrtc.show_alert('gumabort', treatAsStopped);
96
97
                            break;
98
                        case 'NotAllowedError':
99
                            M.tinymce_recordrtc.show_alert('gumnotallowed', treatAsStopped);
100
101
                            break;
102
                        case 'NotFoundError':
103
                            M.tinymce_recordrtc.show_alert('gumnotfound', treatAsStopped);
104
105
                            break;
106
                        case 'NotReadableError':
107
                            M.tinymce_recordrtc.show_alert('gumnotreadable', treatAsStopped);
108
109
                            break;
110
                        case 'OverConstrainedError':
111
                            M.tinymce_recordrtc.show_alert('gumoverconstrained', treatAsStopped);
112
113
                            break;
114
                        case 'SecurityError':
115
                            M.tinymce_recordrtc.show_alert('gumsecurity', function() {
116
                                tinyMCEPopup.close();
117
                            });
118
119
                            break;
120
                        case 'TypeError':
121
                            M.tinymce_recordrtc.show_alert('gumtype', treatAsStopped);
122
123
                            break;
124
                        default:
125
                            break;
126
                    }
127
                }
128
            };
129
130
            // Capture audio stream from microphone.
131
            M.tinymce_recordrtc.capture_audio(commonConfig);
132
        } else { // If button is displaying "Stop Recording".
133
            // First of all clears the countdownTicker.
134
            window.clearInterval(countdownTicker);
135
136
            // Disable "Record Again" button for 1s to allow background processing (closing streams).
137
            window.setTimeout(function() {
138
                startStopBtn.set('disabled', false);
139
            }, 1000);
140
141
            // Stop recording.
142
            M.tinymce_recordrtc.stop_recording_audio(startStopBtn.stream);
143
144
            // Change button to offer to record again.
145
            startStopBtn.set('textContent', M.util.get_string('recordagain', 'tinymce_recordrtc'));
146
            if (!recordrtc.oldermoodle) {
147
                startStopBtn.replaceClass('btn-danger', 'btn-outline-danger');
148
            }
149
        }
150
    });
151
};
152
153
// Setup to get audio stream from microphone.
154
M.tinymce_recordrtc.capture_audio = function(config) {
155
    M.tinymce_recordrtc.capture_user_media(
156
        // Media constraints.
157
        {
158
            audio: true
159
        },
160
161
        // Success callback.
162
        function(audioStream) {
163
            // Set audio player source to microphone stream.
164
            playerDOM.srcObject = audioStream;
165
166
            config.onMediaCaptured(audioStream);
167
        },
168
169
        // Error callback.
170
        function(error) {
171
            config.onMediaCapturingFailed(error);
172
        }
173
    );
174
};
175
176
M.tinymce_recordrtc.stop_recording_audio = function(stream) {
177
    // Stop recording microphone stream.
178
    mediaRecorder.stop();
179
180
    // Stop each individual MediaTrack.
181
    stream.getTracks().forEach(function(track) {
182
        track.stop();
183
    });
184
185
    // Set source of audio player.
186
    var blob = new window.Blob(chunks, {type: mediaRecorder.mimeType});
187
    player.set('src', window.URL.createObjectURL(blob));
188
189
    // Show audio player with controls enabled, and unmute.
190
    player.set('muted', false);
191
    player.set('controls', true);
192
    player.ancestor().ancestor().removeClass('hide');
193
194
    // Show upload button.
195
    uploadBtn.ancestor().ancestor().removeClass('hide');
196
    uploadBtn.set('textContent', M.util.get_string('attachrecording', 'tinymce_recordrtc'));
197
    uploadBtn.set('disabled', false);
198
199
    // Handle when upload button is clicked.
200
    uploadBtn.on('click', function() {
201
        // Trigger error if no recording has been made.
202
        if (!player.get('src') || chunks === []) {
203
            M.tinymce_recordrtc.show_alert('norecordingfound');
204
        } else {
205
            uploadBtn.set('disabled', true);
206
207
            // Upload recording to server.
208
            M.tinymce_recordrtc.upload_to_server(recType, function(progress, fileURLOrError) {
209
                if (progress === 'ended') { // Insert annotation in text.
210
                    uploadBtn.set('disabled', false);
211
                    M.tinymce_recordrtc.insert_annotation(recType, fileURLOrError);
212
                } else if (progress === 'upload-failed') { // Show error message in upload button.
213
                    uploadBtn.set('disabled', false);
214
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed', 'tinymce_recordrtc') + ' ' + fileURLOrError);
215
                } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle.
216
                    uploadBtn.set('disabled', false);
217
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'tinymce_recordrtc'));
218
                } else if (progress === 'upload-aborted') {
219
                    uploadBtn.set('disabled', false);
220
                    uploadBtn.set('textContent', M.util.get_string('uploadaborted', 'tinymce_recordrtc') + ' ' + fileURLOrError);
221
                } else {
222
                    uploadBtn.set('textContent', progress);
223
                }
224
            });
225
        }
226
    });
227
};
228