@lls/lls-audio 0.0.58 → 0.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +26 -24
- package/player/Play.js +13 -7
- package/recorder/AudioWorker.js +133 -0
- package/recorder/DesktopRecorder.js +159 -88
- package/recorder/index.js +5 -5
- package/stories/recorder.js +23 -6
- package/utils/audio.js +26 -141
- package/utils/mediaDevices.js +33 -0
- package/recorder/AsyncLoader.js +0 -84
- package/recorder/DesktopAudioRecorder.js +0 -191
package/package.json
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lls/lls-audio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.60",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"devDependencies": {
|
|
6
|
-
"@kadira/storybook": "
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"babel-
|
|
12
|
-
"babel-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"conventional-changelog
|
|
16
|
-
"
|
|
17
|
-
"
|
|
6
|
+
"@kadira/storybook": "2.21.0",
|
|
7
|
+
"@kadira/storybook-deployer": "1.0.0",
|
|
8
|
+
"@lls/lls-icons": "*",
|
|
9
|
+
"@lls/lls-ui": "*",
|
|
10
|
+
"aphrodite": "0.5.0",
|
|
11
|
+
"babel-cli": "6.9.0",
|
|
12
|
+
"babel-preset-es2015": "6.3.13",
|
|
13
|
+
"babel-preset-react": "6.3.13",
|
|
14
|
+
"babel-preset-stage-0": "6.3.13",
|
|
15
|
+
"conventional-changelog": "1.1.0",
|
|
16
|
+
"conventional-changelog-cli": "1.2.0",
|
|
17
|
+
"css-loader": "0.26.1",
|
|
18
18
|
"react": "15.3.1",
|
|
19
19
|
"react-dom": "15.3.1",
|
|
20
|
-
"
|
|
20
|
+
"release-it": "2.4.0",
|
|
21
|
+
"style-loader": "0.13.1",
|
|
22
|
+
"superheroes": "1.0.0"
|
|
21
23
|
},
|
|
22
24
|
"dependencies": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"is_js": "
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"react-input-range": "^0.9.3",
|
|
29
|
-
"waveform-data": "^2.0.0"
|
|
25
|
+
"hark": "1.1.5",
|
|
26
|
+
"inline-worker": "1.1.0",
|
|
27
|
+
"is_js": "0.9.0",
|
|
28
|
+
"react-input-range": "0.9.3",
|
|
29
|
+
"waveform-data": "2.0.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
32
|
+
"@lls/lls-icons": "*",
|
|
33
|
+
"@lls/lls-ui": "*",
|
|
34
|
+
"aphrodite": "0.5.0",
|
|
35
|
+
"react": "*",
|
|
36
|
+
"react-dom": "*"
|
|
35
37
|
},
|
|
36
38
|
"engines": {
|
|
37
39
|
"node": ">=0.12.0"
|
package/player/Play.js
CHANGED
|
@@ -18,19 +18,25 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
18
18
|
|
|
19
19
|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
|
20
20
|
|
|
21
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
22
|
-
|
|
23
21
|
var generateStyles = function generateStyles(_ref) {
|
|
24
|
-
var _play_button_wrapper;
|
|
25
|
-
|
|
26
22
|
var size = _ref.size,
|
|
27
23
|
invert = _ref.invert,
|
|
28
24
|
transitionDuration = _ref.transitionDuration;
|
|
29
25
|
return _noImportant.StyleSheet.create({
|
|
30
|
-
play_button_wrapper:
|
|
26
|
+
play_button_wrapper: {
|
|
31
27
|
height: '100%',
|
|
32
|
-
width: size * 2.5
|
|
33
|
-
|
|
28
|
+
width: size * 2.5,
|
|
29
|
+
height: size * 2.5,
|
|
30
|
+
color: '#6d6d6d',
|
|
31
|
+
textAlign: 'center',
|
|
32
|
+
boxSizing: 'border-box',
|
|
33
|
+
backgroundColor: invert ? 'white' : _colors.BLUE,
|
|
34
|
+
borderRadius: '50%',
|
|
35
|
+
display: 'flex',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
cursor: 'pointer'
|
|
39
|
+
},
|
|
34
40
|
play_button: {
|
|
35
41
|
'height': size,
|
|
36
42
|
'width': size,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var AudioWorker = function AudioWorker(self) {
|
|
7
|
+
var recLength = 0;
|
|
8
|
+
var recBuffers = [];
|
|
9
|
+
var audioBlob = null;
|
|
10
|
+
|
|
11
|
+
self.onmessage = function (e) {
|
|
12
|
+
var mergeBuffers = function mergeBuffers(recBuffers, recLength) {
|
|
13
|
+
var result = new Float32Array(recLength);
|
|
14
|
+
var offset = 0;
|
|
15
|
+
for (var i = 0; i < recBuffers.length; i++) {
|
|
16
|
+
result.set(recBuffers[i], offset);
|
|
17
|
+
offset += recBuffers[i].length;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
var appendBuffer = function appendBuffer(timestamp, inputBuffer) {
|
|
23
|
+
for (var channel = 0; channel < inputBuffer.length; channel++) {
|
|
24
|
+
if (!recBuffers[channel]) recBuffers[channel] = [];
|
|
25
|
+
recBuffers[channel].push({ timestamp: timestamp, data: inputBuffer[channel], length: inputBuffer[channel].length });
|
|
26
|
+
}
|
|
27
|
+
recLength += inputBuffer[0].length;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function interleave(inputL, inputR) {
|
|
31
|
+
var length = inputL.length + inputR.length;
|
|
32
|
+
var result = new Float32Array(length);
|
|
33
|
+
|
|
34
|
+
var index = 0;
|
|
35
|
+
var inputIndex = 0;
|
|
36
|
+
|
|
37
|
+
while (index < length) {
|
|
38
|
+
result[index++] = inputL[inputIndex];
|
|
39
|
+
result[index++] = inputR[inputIndex];
|
|
40
|
+
inputIndex++;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var writeString = function writeString(view, offset, string) {
|
|
46
|
+
for (var i = 0; i < string.length; i++) {
|
|
47
|
+
view.setUint8(offset + i, string.charCodeAt(i));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
var floatTo16BitPCM = function floatTo16BitPCM(output, offset, input) {
|
|
52
|
+
for (var i = 0; i < input.length; i++, offset += 2) {
|
|
53
|
+
var s = Math.max(-1, Math.min(1, input[i]));
|
|
54
|
+
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
var encodeWAV = function encodeWAV(samples) {
|
|
59
|
+
var buffer = new ArrayBuffer(44 + samples.length * 2);
|
|
60
|
+
var view = new DataView(buffer);
|
|
61
|
+
|
|
62
|
+
/* RIFF identifier */
|
|
63
|
+
writeString(view, 0, 'RIFF');
|
|
64
|
+
/* RIFF chunk length */
|
|
65
|
+
view.setUint32(4, 36 + samples.length * 2, true);
|
|
66
|
+
/* RIFF type */
|
|
67
|
+
writeString(view, 8, 'WAVE');
|
|
68
|
+
/* format chunk identifier */
|
|
69
|
+
writeString(view, 12, 'fmt ');
|
|
70
|
+
/* format chunk length */
|
|
71
|
+
view.setUint32(16, 16, true);
|
|
72
|
+
/* sample format (raw) */
|
|
73
|
+
view.setUint16(20, 1, true);
|
|
74
|
+
/* channel count */
|
|
75
|
+
view.setUint16(22, recBuffers.length, true);
|
|
76
|
+
/* sample rate */
|
|
77
|
+
view.setUint32(24, 44100, true);
|
|
78
|
+
/* byte rate (sample rate * block align) */
|
|
79
|
+
view.setUint32(28, 44100 * 4, true);
|
|
80
|
+
/* block align (channel count * bytes per sample) */
|
|
81
|
+
view.setUint16(32, recBuffers.length * 2, true);
|
|
82
|
+
/* bits per sample */
|
|
83
|
+
view.setUint16(34, 16, true);
|
|
84
|
+
/* data chunk identifier */
|
|
85
|
+
writeString(view, 36, 'data');
|
|
86
|
+
/* data chunk length */
|
|
87
|
+
view.setUint32(40, samples.length * 2, true);
|
|
88
|
+
|
|
89
|
+
floatTo16BitPCM(view, 44, samples);
|
|
90
|
+
|
|
91
|
+
return view;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
var exportWAV = function exportWAV(beginning, end) {
|
|
95
|
+
var buffers = [];
|
|
96
|
+
for (var channel = 0; channel < recBuffers.length; channel++) {
|
|
97
|
+
var length = 0;
|
|
98
|
+
var filtredRecBuffers = recBuffers[channel].filter(function (buffer) {
|
|
99
|
+
return buffer.timestamp >= beginning - 1000 && buffer.timestamp <= end;
|
|
100
|
+
}).map(function (buffer) {
|
|
101
|
+
length += buffer.length;
|
|
102
|
+
return buffer.data;
|
|
103
|
+
});
|
|
104
|
+
buffers.push(mergeBuffers(filtredRecBuffers, length));
|
|
105
|
+
}
|
|
106
|
+
var interleaved = recBuffers.length === 2 ? interleave(buffers[0], buffers[1]) : buffers[0];
|
|
107
|
+
var dataview = encodeWAV(interleaved);
|
|
108
|
+
audioBlob = new Blob([dataview], { type: 'audio/wav' });
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
switch (e.data.command) {
|
|
112
|
+
case 'append':
|
|
113
|
+
appendBuffer(e.data.timestamp, e.data.inputBuffer);
|
|
114
|
+
var buffers = [];
|
|
115
|
+
for (var channel = 0; channel < recBuffers.length; channel++) {
|
|
116
|
+
buffers.push(mergeBuffers(recBuffers[channel], recLength));
|
|
117
|
+
}
|
|
118
|
+
postMessage({ command: 'send_buffers', buffers: recBuffers });
|
|
119
|
+
break;
|
|
120
|
+
case 'exportWAV':
|
|
121
|
+
exportWAV(e.data.beginning, e.data.end);
|
|
122
|
+
postMessage({ command: 'send_WAV', audioBlob: audioBlob });
|
|
123
|
+
break;
|
|
124
|
+
case 'clean':
|
|
125
|
+
recLength = 0;
|
|
126
|
+
recBuffers = [];
|
|
127
|
+
audioBlob = null;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
exports.default = AudioWorker;
|
|
@@ -10,19 +10,27 @@ var _react = require('react');
|
|
|
10
10
|
|
|
11
11
|
var _react2 = _interopRequireDefault(_react);
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _CustomWave = require('../player/CustomWave');
|
|
14
14
|
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
var _Wave = require('../player/Wave');
|
|
18
|
-
|
|
19
|
-
var _Wave2 = _interopRequireDefault(_Wave);
|
|
15
|
+
var _CustomWave2 = _interopRequireDefault(_CustomWave);
|
|
20
16
|
|
|
21
17
|
var _audioContext = require('../utils/audioContext');
|
|
22
18
|
|
|
23
19
|
var _audioContext2 = _interopRequireDefault(_audioContext);
|
|
24
20
|
|
|
25
|
-
var
|
|
21
|
+
var _mediaDevices = require('../utils/mediaDevices');
|
|
22
|
+
|
|
23
|
+
var _hark = require('hark');
|
|
24
|
+
|
|
25
|
+
var _hark2 = _interopRequireDefault(_hark);
|
|
26
|
+
|
|
27
|
+
var _inlineWorker = require('inline-worker');
|
|
28
|
+
|
|
29
|
+
var _inlineWorker2 = _interopRequireDefault(_inlineWorker);
|
|
30
|
+
|
|
31
|
+
var _AudioWorker = require('./AudioWorker');
|
|
32
|
+
|
|
33
|
+
var _AudioWorker2 = _interopRequireDefault(_AudioWorker);
|
|
26
34
|
|
|
27
35
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
36
|
|
|
@@ -32,112 +40,175 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
|
|
|
32
40
|
|
|
33
41
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
34
42
|
|
|
43
|
+
var INTERVAL = 100;
|
|
44
|
+
|
|
35
45
|
var audioContext = new _audioContext2.default();
|
|
36
46
|
|
|
37
|
-
var
|
|
38
|
-
|
|
47
|
+
var initRecorder = function initRecorder(_ref) {
|
|
48
|
+
var stream = _ref.stream,
|
|
49
|
+
audioContext = _ref.audioContext,
|
|
50
|
+
_ref$onAudioProcess = _ref.onAudioProcess,
|
|
51
|
+
onAudioProcess = _ref$onAudioProcess === undefined ? function () {} : _ref$onAudioProcess;
|
|
52
|
+
|
|
53
|
+
var bufferSize = 4096;
|
|
54
|
+
var numberOfInputChannels = 1; // for google cloud Speech to text, we must have one (and only one) channel
|
|
55
|
+
var numberOfOutputChannels = 1;
|
|
56
|
+
|
|
57
|
+
// creates an audio node from the microphone incoming stream
|
|
58
|
+
var mediaStream = audioContext.createMediaStreamSource(stream);
|
|
59
|
+
var recorder = audioContext.createScriptProcessor ? audioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels) : audioContext.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);
|
|
60
|
+
|
|
61
|
+
recorder.onaudioprocess = onAudioProcess;
|
|
62
|
+
|
|
63
|
+
// we connect the recorder with the input stream
|
|
64
|
+
mediaStream.connect(recorder);
|
|
65
|
+
recorder.connect(audioContext.destination);
|
|
66
|
+
|
|
67
|
+
return recorder;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
var initSpeechEvents = function initSpeechEvents(_ref2) {
|
|
71
|
+
var stream = _ref2.stream,
|
|
72
|
+
_ref2$onSpeaking = _ref2.onSpeaking,
|
|
73
|
+
onSpeaking = _ref2$onSpeaking === undefined ? function () {} : _ref2$onSpeaking,
|
|
74
|
+
_ref2$onStoppedSpeaki = _ref2.onStoppedSpeaking,
|
|
75
|
+
onStoppedSpeaking = _ref2$onStoppedSpeaki === undefined ? function () {} : _ref2$onStoppedSpeaki,
|
|
76
|
+
_ref2$onVolumeChange = _ref2.onVolumeChange,
|
|
77
|
+
onVolumeChange = _ref2$onVolumeChange === undefined ? function () {} : _ref2$onVolumeChange;
|
|
78
|
+
|
|
79
|
+
// Try hark
|
|
80
|
+
var options = {
|
|
81
|
+
interval: INTERVAL
|
|
82
|
+
};
|
|
83
|
+
var speechEvents = (0, _hark2.default)(stream, options);
|
|
84
|
+
|
|
85
|
+
speechEvents.on('speaking', onSpeaking);
|
|
86
|
+
speechEvents.on('stopped_speaking', onStoppedSpeaking);
|
|
87
|
+
speechEvents.on('volume_change', onVolumeChange);
|
|
88
|
+
|
|
89
|
+
return speechEvents;
|
|
90
|
+
};
|
|
39
91
|
|
|
40
|
-
|
|
41
|
-
|
|
92
|
+
var DesktopAudioRecorder = function (_Component) {
|
|
93
|
+
_inherits(DesktopAudioRecorder, _Component);
|
|
42
94
|
|
|
43
|
-
|
|
95
|
+
function DesktopAudioRecorder(props) {
|
|
96
|
+
_classCallCheck(this, DesktopAudioRecorder);
|
|
44
97
|
|
|
45
|
-
_this
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
_this.
|
|
50
|
-
_this.
|
|
98
|
+
var _this = _possibleConstructorReturn(this, (DesktopAudioRecorder.__proto__ || Object.getPrototypeOf(DesktopAudioRecorder)).call(this, props));
|
|
99
|
+
|
|
100
|
+
_this.recordStart = null;
|
|
101
|
+
_this.audioBuffer = [];
|
|
102
|
+
_this.init = _this.init.bind(_this);
|
|
103
|
+
_this.initStream = _this.initStream.bind(_this);
|
|
51
104
|
return _this;
|
|
52
105
|
}
|
|
53
106
|
|
|
54
|
-
_createClass(
|
|
55
|
-
key: '
|
|
56
|
-
value: function
|
|
107
|
+
_createClass(DesktopAudioRecorder, [{
|
|
108
|
+
key: 'componentDidMount',
|
|
109
|
+
value: function componentDidMount() {
|
|
110
|
+
this.init(this.props);
|
|
111
|
+
}
|
|
112
|
+
}, {
|
|
113
|
+
key: 'init',
|
|
114
|
+
value: function init(props) {
|
|
57
115
|
var _this2 = this;
|
|
58
116
|
|
|
59
|
-
var
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
recordedData ? _react2.default.createElement(_Wave2.default, {
|
|
81
|
-
width: 500,
|
|
82
|
-
currentTime: 0,
|
|
83
|
-
height: 40,
|
|
84
|
-
isLoading: false,
|
|
85
|
-
buffer: recordedData }) : null
|
|
86
|
-
);
|
|
117
|
+
var _props$onError = props.onError,
|
|
118
|
+
onError = _props$onError === undefined ? function () {} : _props$onError,
|
|
119
|
+
_props$onVolumeChange = props.onVolumeChange,
|
|
120
|
+
onVolumeChange = _props$onVolumeChange === undefined ? function () {} : _props$onVolumeChange,
|
|
121
|
+
_props$onRecordComple = props.onRecordComplete,
|
|
122
|
+
onRecordComplete = _props$onRecordComple === undefined ? function () {} : _props$onRecordComple;
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
(0, _mediaDevices.shimMediaDevices)();
|
|
126
|
+
window.navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) {
|
|
127
|
+
_this2.initStream({
|
|
128
|
+
stream: stream,
|
|
129
|
+
onError: onError,
|
|
130
|
+
onVolumeChange: onVolumeChange,
|
|
131
|
+
onRecordComplete: onRecordComplete
|
|
132
|
+
});
|
|
133
|
+
}).catch(function (err) {
|
|
134
|
+
onError(err);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
this.initWorker();
|
|
87
138
|
}
|
|
88
139
|
}, {
|
|
89
|
-
key: '
|
|
90
|
-
value: function
|
|
140
|
+
key: 'initStream',
|
|
141
|
+
value: function initStream(_ref3) {
|
|
91
142
|
var _this3 = this;
|
|
92
143
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
144
|
+
var stream = _ref3.stream,
|
|
145
|
+
onError = _ref3.onError,
|
|
146
|
+
_onVolumeChange = _ref3.onVolumeChange,
|
|
147
|
+
onRecordComplete = _ref3.onRecordComplete;
|
|
148
|
+
|
|
149
|
+
// Init recorder
|
|
150
|
+
var recorder = initRecorder({
|
|
151
|
+
stream: stream,
|
|
152
|
+
audioContext: audioContext,
|
|
153
|
+
onAudioProcess: function onAudioProcess(e) {
|
|
154
|
+
var inputBuffer = [];
|
|
155
|
+
for (var channel = 0; channel < e.inputBuffer.numberOfChannels; channel++) {
|
|
156
|
+
inputBuffer.push(e.inputBuffer.getChannelData(channel));
|
|
157
|
+
}
|
|
158
|
+
_this3.worker.postMessage({ command: 'append', timestamp: Date.now(), inputBuffer: inputBuffer });
|
|
159
|
+
}
|
|
97
160
|
});
|
|
98
|
-
|
|
99
|
-
|
|
161
|
+
|
|
162
|
+
// Initialize hark for silence recognition
|
|
163
|
+
var speechEvents = initSpeechEvents({
|
|
164
|
+
stream: stream,
|
|
165
|
+
onStoppedSpeaking: function onStoppedSpeaking() {
|
|
166
|
+
console.log('stop');
|
|
167
|
+
try {
|
|
168
|
+
_this3.worker.postMessage({ command: 'exportWAV', buffers: _this3.audioBuffer, beginning: _this3.recordStart, end: Date.now() });
|
|
169
|
+
_this3.worker.postMessage({ command: 'clean' });
|
|
170
|
+
_this3.audioBuffer = [];
|
|
171
|
+
} catch (e) {
|
|
172
|
+
onError(e);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onSpeaking: function onSpeaking() {
|
|
176
|
+
console.log('start');
|
|
177
|
+
_this3.recordStart = Date.now() - INTERVAL * 3; // give it a bit of extra time
|
|
178
|
+
},
|
|
179
|
+
onVolumeChange: function onVolumeChange(volume) {
|
|
180
|
+
_onVolumeChange(volume);
|
|
181
|
+
}
|
|
100
182
|
});
|
|
101
183
|
}
|
|
102
184
|
}, {
|
|
103
|
-
key: '
|
|
104
|
-
value: function
|
|
185
|
+
key: 'initWorker',
|
|
186
|
+
value: function initWorker() {
|
|
105
187
|
var _this4 = this;
|
|
106
188
|
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
|
|
111
|
-
|
|
189
|
+
this.worker = new _inlineWorker2.default(_AudioWorker2.default, {});
|
|
190
|
+
|
|
191
|
+
this.worker.onmessage = function (e) {
|
|
192
|
+
switch (e.data.command) {
|
|
193
|
+
case 'send_buffers':
|
|
194
|
+
_this4.audioBuffer = e.data.buffers;
|
|
195
|
+
break;
|
|
196
|
+
case 'send_WAV':
|
|
197
|
+
console.log('send_WAV');
|
|
198
|
+
//const url = (window.URL || window.webkitURL).createObjectURL(e.data.audioBlob)
|
|
199
|
+
_this4.props.onRecordComplete(e.data.audioBlob);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
112
202
|
};
|
|
113
|
-
this.mediaRecorder.start();
|
|
114
203
|
}
|
|
115
204
|
}, {
|
|
116
|
-
key: '
|
|
117
|
-
value: function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
var mergedBuffer = (0, _audio.appendBuffer)(recordedData, audioBuffer);
|
|
121
|
-
this.setState({
|
|
122
|
-
recordedData: mergedBuffer
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}, {
|
|
126
|
-
key: 'onMediaError',
|
|
127
|
-
value: function onMediaError(e) {
|
|
128
|
-
console.error('media error', e);
|
|
129
|
-
}
|
|
130
|
-
}, {
|
|
131
|
-
key: 'stopRecording',
|
|
132
|
-
value: function stopRecording() {
|
|
133
|
-
this.mediaRecorder.stop();
|
|
134
|
-
this.setState({
|
|
135
|
-
isRecording: false
|
|
136
|
-
});
|
|
205
|
+
key: 'render',
|
|
206
|
+
value: function render() {
|
|
207
|
+
return null;
|
|
137
208
|
}
|
|
138
209
|
}]);
|
|
139
210
|
|
|
140
|
-
return
|
|
211
|
+
return DesktopAudioRecorder;
|
|
141
212
|
}(_react.Component);
|
|
142
213
|
|
|
143
|
-
exports.default =
|
|
214
|
+
exports.default = DesktopAudioRecorder;
|
package/recorder/index.js
CHANGED
|
@@ -10,9 +10,9 @@ var _react2 = _interopRequireDefault(_react);
|
|
|
10
10
|
|
|
11
11
|
var _is_js = require('is_js');
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _DesktopRecorder = require('./DesktopRecorder');
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _DesktopRecorder2 = _interopRequireDefault(_DesktopRecorder);
|
|
16
16
|
|
|
17
17
|
var _MobileRecorder = require('./MobileRecorder');
|
|
18
18
|
|
|
@@ -24,12 +24,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
24
24
|
var isUserMediaSupported = !!(window.navigator.getUserMedia || window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia || window.navigator.msGetUserMedia);
|
|
25
25
|
var desktop = !((0, _is_js.tablet)() && (0, _is_js.mobile)());
|
|
26
26
|
|
|
27
|
-
var Recorder = function Recorder() {
|
|
28
|
-
return desktop ? isUserMediaSupported ? _react2.default.createElement(
|
|
27
|
+
var Recorder = function Recorder(props) {
|
|
28
|
+
return desktop ? isUserMediaSupported ? _react2.default.createElement(_DesktopRecorder2.default, props) : _react2.default.createElement(
|
|
29
29
|
'div',
|
|
30
30
|
null,
|
|
31
31
|
' not supported '
|
|
32
|
-
) : _react2.default.createElement(_MobileRecorder2.default,
|
|
32
|
+
) : _react2.default.createElement(_MobileRecorder2.default, props);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
exports.default = Recorder;
|
package/stories/recorder.js
CHANGED
|
@@ -18,13 +18,30 @@ var _recorder2 = _interopRequireDefault(_recorder);
|
|
|
18
18
|
|
|
19
19
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
20
20
|
|
|
21
|
+
var API_URL = 'http://localhost:3004/speechtotext';
|
|
22
|
+
|
|
23
|
+
var sendFile = function sendFile(wav) {
|
|
24
|
+
var xhr = new XMLHttpRequest();
|
|
25
|
+
xhr.onreadystatechange = function () {
|
|
26
|
+
if (xhr.readyState == 4 && xhr.status == 200) {
|
|
27
|
+
console.log('Speech to text: ', xhr.responseText);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
xhr.open('POST', API_URL, false);
|
|
31
|
+
xhr.setRequestHeader('Content-Type', 'audio/wav');
|
|
32
|
+
xhr.send(wav);
|
|
33
|
+
};
|
|
34
|
+
|
|
21
35
|
var RecorderExample = function RecorderExample() {
|
|
22
|
-
return _react2.default.createElement(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
return _react2.default.createElement(_recorder2.default, {
|
|
37
|
+
onVolumeChange: function onVolumeChange(vol) {},
|
|
38
|
+
onError: function onError(err) {
|
|
39
|
+
return console.log('error', err);
|
|
40
|
+
},
|
|
41
|
+
onRecordComplete: function onRecordComplete(wax) {
|
|
42
|
+
return sendFile(wax);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
28
45
|
};
|
|
29
46
|
|
|
30
47
|
exports.default = RecorderExample;
|
package/utils/audio.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.getWaveform = undefined;
|
|
7
7
|
|
|
8
8
|
var _audioContext = require('./audioContext');
|
|
9
9
|
|
|
@@ -47,166 +47,51 @@ var getWaveform = exports.getWaveform = function getWaveform(url) {
|
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
/*
|
|
51
|
+
export const convertAudioBufferToWaveform = (audioBuffer) => {
|
|
51
52
|
// All this code (except the last line) is stolen/inspired from https://github.com/bbc/waveform-data.js/blob/master/lib/builders/audiodecoder.js
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
dataObject.setInt32(
|
|
65
|
-
dataObject.
|
|
66
|
-
dataObject.setInt32(8, audioBuffer.sampleRate, true); //sample rate
|
|
67
|
-
dataObject.setInt32(12, scale, true); //scale
|
|
68
|
-
dataObject.setInt32(16, dataLength, true); //length
|
|
53
|
+
const scale = 512
|
|
54
|
+
const scaleAdjuster = 127
|
|
55
|
+
const dataLength = Math.floor(audioBuffer.length / scale)
|
|
56
|
+
let offset = 20
|
|
57
|
+
const dataObject = new DataView(new ArrayBuffer(offset + dataLength * 2))
|
|
58
|
+
let leftChannel, rightChannel
|
|
59
|
+
let minValue = Infinity, max_value = -Infinity, scale_counter = scale;
|
|
60
|
+
const bufferLength = audioBuffer.length
|
|
61
|
+
|
|
62
|
+
dataObject.setInt32(0, 1, true); //version
|
|
63
|
+
dataObject.setUint32(4, 1, true); //is 8 bit
|
|
64
|
+
dataObject.setInt32(8, audioBuffer.sampleRate, true); //sample rate
|
|
65
|
+
dataObject.setInt32(12, scale, true); //scale
|
|
66
|
+
dataObject.setInt32(16, dataLength, true); //length
|
|
69
67
|
|
|
70
68
|
leftChannel = audioBuffer.getChannelData(0);
|
|
71
69
|
rightChannel = audioBuffer.getChannelData(1);
|
|
72
70
|
|
|
73
|
-
for (
|
|
74
|
-
|
|
71
|
+
for (let i = 0; i < bufferLength; i++){
|
|
72
|
+
const sample = (leftChannel[i] + rightChannel[i]) / 2 * scaleAdjuster;
|
|
75
73
|
|
|
76
|
-
if (sample < minValue)
|
|
74
|
+
if (sample < minValue){
|
|
77
75
|
minValue = sample;
|
|
78
76
|
if (minValue < -128) {
|
|
79
77
|
minValue = -128;
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
|
|
83
|
-
if (sample > max_value)
|
|
81
|
+
if (sample > max_value){
|
|
84
82
|
max_value = sample;
|
|
85
83
|
if (max_value > 127) {
|
|
86
84
|
max_value = 127;
|
|
87
85
|
}
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
if (--scale_counter === 0)
|
|
88
|
+
if (--scale_counter === 0){
|
|
91
89
|
dataObject.setInt8(offset++, Math.floor(minValue));
|
|
92
90
|
dataObject.setInt8(offset++, Math.floor(max_value));
|
|
93
|
-
minValue = Infinity;max_value = -Infinity;scale_counter = scale;
|
|
91
|
+
minValue = Infinity; max_value = -Infinity; scale_counter = scale;
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
94
|
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
var appendBuffer = exports.appendBuffer = function appendBuffer(buffer1, buffer2) {
|
|
101
|
-
if (!buffer1) return buffer2;
|
|
102
|
-
if (!buffer2) return buffer1;
|
|
103
|
-
var numberOfChannels = Math.min(buffer1.numberOfChannels, buffer2.numberOfChannels);
|
|
104
|
-
var tmp = audioContext.createBuffer(numberOfChannels, buffer1.length + buffer2.length, buffer1.sampleRate);
|
|
105
|
-
for (var i = 0; i < numberOfChannels; i++) {
|
|
106
|
-
var channel = tmp.getChannelData(i);
|
|
107
|
-
channel.set(buffer1.getChannelData(i), 0);
|
|
108
|
-
channel.set(buffer2.getChannelData(i), buffer1.length);
|
|
109
|
-
}
|
|
110
|
-
return tmp;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
var convertBlobToaudioBuffer = exports.convertBlobToaudioBuffer = function convertBlobToaudioBuffer(blob, cb) {
|
|
114
|
-
var fileReader = new FileReader();
|
|
115
|
-
fileReader.onload = function (_ref) {
|
|
116
|
-
var result = _ref.target.result;
|
|
117
|
-
|
|
118
|
-
audioContext.decodeAudioData(result, function (buf) {
|
|
119
|
-
cb(buf);
|
|
120
|
-
});
|
|
121
|
-
};
|
|
122
|
-
fileReader.readAsArrayBuffer(blob);
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
var audioBufferToWav = exports.audioBufferToWav = function audioBufferToWav(buffer, opt) {
|
|
126
|
-
opt = opt || {};
|
|
127
|
-
|
|
128
|
-
var numChannels = buffer.numberOfChannels;
|
|
129
|
-
var sampleRate = buffer.sampleRate;
|
|
130
|
-
var format = opt.float32 ? 3 : 1;
|
|
131
|
-
var bitDepth = format === 3 ? 32 : 16;
|
|
132
|
-
|
|
133
|
-
var result = numChannels === 2 ? interleave(buffer.getChannelData(0), buffer.getChannelData(1)) : buffer.getChannelData(0);
|
|
134
|
-
|
|
135
|
-
return encodeWAV(result, format, sampleRate, numChannels, bitDepth);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
var encodeWAV = function encodeWAV(samples, format, sampleRate, numChannels, bitDepth) {
|
|
139
|
-
var bytesPerSample = bitDepth / 8;
|
|
140
|
-
var blockAlign = numChannels * bytesPerSample;
|
|
141
|
-
|
|
142
|
-
var buffer = new ArrayBuffer(44 + samples.length * bytesPerSample);
|
|
143
|
-
var view = new DataView(buffer);
|
|
144
|
-
|
|
145
|
-
/* RIFF identifier */
|
|
146
|
-
writeString(view, 0, 'RIFF');
|
|
147
|
-
/* RIFF chunk length */
|
|
148
|
-
view.setUint32(4, 36 + samples.length * bytesPerSample, true);
|
|
149
|
-
/* RIFF type */
|
|
150
|
-
writeString(view, 8, 'WAVE');
|
|
151
|
-
/* format chunk identifier */
|
|
152
|
-
writeString(view, 12, 'fmt ');
|
|
153
|
-
/* format chunk length */
|
|
154
|
-
view.setUint32(16, 16, true);
|
|
155
|
-
/* sample format (raw) */
|
|
156
|
-
view.setUint16(20, format, true);
|
|
157
|
-
/* channel count */
|
|
158
|
-
view.setUint16(22, numChannels, true);
|
|
159
|
-
/* sample rate */
|
|
160
|
-
view.setUint32(24, sampleRate, true);
|
|
161
|
-
/* byte rate (sample rate * block align) */
|
|
162
|
-
view.setUint32(28, sampleRate * blockAlign, true);
|
|
163
|
-
/* block align (channel count * bytes per sample) */
|
|
164
|
-
view.setUint16(32, blockAlign, true);
|
|
165
|
-
/* bits per sample */
|
|
166
|
-
view.setUint16(34, bitDepth, true);
|
|
167
|
-
/* data chunk identifier */
|
|
168
|
-
writeString(view, 36, 'data');
|
|
169
|
-
/* data chunk length */
|
|
170
|
-
view.setUint32(40, samples.length * bytesPerSample, true);
|
|
171
|
-
if (format === 1) {
|
|
172
|
-
// Raw PCM
|
|
173
|
-
floatTo16BitPCM(view, 44, samples);
|
|
174
|
-
} else {
|
|
175
|
-
writeFloat32(view, 44, samples);
|
|
176
|
-
}
|
|
177
|
-
return buffer;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
var interleave = function interleave(inputL, inputR) {
|
|
181
|
-
var length = inputL.length + inputR.length;
|
|
182
|
-
var result = new Float32Array(length);
|
|
183
|
-
|
|
184
|
-
var index = 0;
|
|
185
|
-
var inputIndex = 0;
|
|
186
|
-
|
|
187
|
-
while (index < length) {
|
|
188
|
-
result[index++] = inputL[inputIndex];
|
|
189
|
-
result[index++] = inputR[inputIndex];
|
|
190
|
-
inputIndex++;
|
|
191
|
-
}
|
|
192
|
-
return result;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
var writeFloat32 = function writeFloat32(output, offset, input) {
|
|
196
|
-
for (var i = 0; i < input.length; i++, offset += 4) {
|
|
197
|
-
output.setFloat32(offset, input[i], true);
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
var floatTo16BitPCM = function floatTo16BitPCM(output, offset, input) {
|
|
202
|
-
for (var i = 0; i < input.length; i++, offset += 2) {
|
|
203
|
-
var s = Math.max(-1, Math.min(1, input[i]));
|
|
204
|
-
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
var writeString = function writeString(view, offset, string) {
|
|
209
|
-
for (var i = 0; i < string.length; i++) {
|
|
210
|
-
view.setUint8(offset + i, string.charCodeAt(i));
|
|
211
|
-
}
|
|
212
|
-
};
|
|
95
|
+
return WaveformData.create(dataObject.buffer)
|
|
96
|
+
}
|
|
97
|
+
*/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var shimMediaDevices = exports.shimMediaDevices = function shimMediaDevices() {
|
|
7
|
+
// Older browsers might not implement mediaDevices at all, so we set an empty object first
|
|
8
|
+
if (window.navigator.mediaDevices === undefined) {
|
|
9
|
+
window.navigator.mediaDevices = {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Some browsers partially implement mediaDevices. We can't just assign an object
|
|
13
|
+
// with getUserMedia as it would overwrite existing properties.
|
|
14
|
+
// Here, we will just add the getUserMedia property if it's missing.
|
|
15
|
+
if (window.navigator.mediaDevices.getUserMedia === undefined) {
|
|
16
|
+
window.navigator.mediaDevices.getUserMedia = function (constraints) {
|
|
17
|
+
|
|
18
|
+
// First get ahold of the legacy getUserMedia, if present
|
|
19
|
+
var getUserMedia = window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia;
|
|
20
|
+
|
|
21
|
+
// Some browsers just don't implement it - return a rejected promise with an error
|
|
22
|
+
// to keep a consistent interface
|
|
23
|
+
if (!getUserMedia) {
|
|
24
|
+
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
|
|
28
|
+
return new Promise(function (resolve, reject) {
|
|
29
|
+
getUserMedia.call(navigator, constraints, resolve, reject);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
};
|
package/recorder/AsyncLoader.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
-
|
|
9
|
-
var _react = require('react');
|
|
10
|
-
|
|
11
|
-
var _react2 = _interopRequireDefault(_react);
|
|
12
|
-
|
|
13
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
-
|
|
15
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
16
|
-
|
|
17
|
-
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
18
|
-
|
|
19
|
-
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
20
|
-
|
|
21
|
-
var loadedScripts = [];
|
|
22
|
-
|
|
23
|
-
var getCssEl = function getCssEl(_ref) {
|
|
24
|
-
var href = _ref.href;
|
|
25
|
-
|
|
26
|
-
var link = document.createElement('link');
|
|
27
|
-
link.rel = 'stylesheet';
|
|
28
|
-
link.type = 'text/css';
|
|
29
|
-
link.href = href;
|
|
30
|
-
link.media = 'all';
|
|
31
|
-
return link;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
var getScriptEl = function getScriptEl(_ref2) {
|
|
35
|
-
var src = _ref2.src,
|
|
36
|
-
onload = _ref2.onload,
|
|
37
|
-
onError = _ref2.onError;
|
|
38
|
-
|
|
39
|
-
var script = document.createElement('script');
|
|
40
|
-
script.type = 'text/javascript';
|
|
41
|
-
script.src = src;
|
|
42
|
-
script.async = false;
|
|
43
|
-
script.onload = onload;
|
|
44
|
-
script.onerror = onError;
|
|
45
|
-
return script;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
var AsyncLoader = function (_Component) {
|
|
49
|
-
_inherits(AsyncLoader, _Component);
|
|
50
|
-
|
|
51
|
-
function AsyncLoader() {
|
|
52
|
-
_classCallCheck(this, AsyncLoader);
|
|
53
|
-
|
|
54
|
-
return _possibleConstructorReturn(this, (AsyncLoader.__proto__ || Object.getPrototypeOf(AsyncLoader)).apply(this, arguments));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
_createClass(AsyncLoader, [{
|
|
58
|
-
key: 'componentDidMount',
|
|
59
|
-
value: function componentDidMount() {
|
|
60
|
-
var _props = this.props,
|
|
61
|
-
src = _props.src,
|
|
62
|
-
href = _props.href,
|
|
63
|
-
_props$onLoad = _props.onLoad,
|
|
64
|
-
onLoad = _props$onLoad === undefined ? function () {} : _props$onLoad,
|
|
65
|
-
_props$onError = _props.onError,
|
|
66
|
-
onError = _props$onError === undefined ? function () {} : _props$onError;
|
|
67
|
-
|
|
68
|
-
if (src && !loadedScripts.includes(href || src)) {
|
|
69
|
-
var el = href ? getCssEl({ href: href }) : getScriptEl({ src: src, onLoad: onLoad, onError: onError });
|
|
70
|
-
document.body.appendChild(el);
|
|
71
|
-
loadedScripts.push(href || src);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}, {
|
|
75
|
-
key: 'render',
|
|
76
|
-
value: function render() {
|
|
77
|
-
return _react2.default.createElement('noscript', null);
|
|
78
|
-
}
|
|
79
|
-
}]);
|
|
80
|
-
|
|
81
|
-
return AsyncLoader;
|
|
82
|
-
}(_react.Component);
|
|
83
|
-
|
|
84
|
-
exports.default = AsyncLoader;
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
-
|
|
9
|
-
var _react = require('react');
|
|
10
|
-
|
|
11
|
-
var _react2 = _interopRequireDefault(_react);
|
|
12
|
-
|
|
13
|
-
var _CustomWave = require('../player/CustomWave');
|
|
14
|
-
|
|
15
|
-
var _CustomWave2 = _interopRequireDefault(_CustomWave);
|
|
16
|
-
|
|
17
|
-
var _audioContext = require('../utils/audioContext');
|
|
18
|
-
|
|
19
|
-
var _audioContext2 = _interopRequireDefault(_audioContext);
|
|
20
|
-
|
|
21
|
-
var _audio = require('../utils/audio');
|
|
22
|
-
|
|
23
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
24
|
-
|
|
25
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
26
|
-
|
|
27
|
-
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
28
|
-
|
|
29
|
-
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
30
|
-
|
|
31
|
-
var audioContext = new _audioContext2.default();
|
|
32
|
-
|
|
33
|
-
var DesktopAudioRecorder = function (_Component) {
|
|
34
|
-
_inherits(DesktopAudioRecorder, _Component);
|
|
35
|
-
|
|
36
|
-
function DesktopAudioRecorder(props) {
|
|
37
|
-
_classCallCheck(this, DesktopAudioRecorder);
|
|
38
|
-
|
|
39
|
-
var _this = _possibleConstructorReturn(this, (DesktopAudioRecorder.__proto__ || Object.getPrototypeOf(DesktopAudioRecorder)).call(this, props));
|
|
40
|
-
|
|
41
|
-
_this.state = {
|
|
42
|
-
isRecording: false,
|
|
43
|
-
recordedData: null,
|
|
44
|
-
waveform: null
|
|
45
|
-
};
|
|
46
|
-
//this.audioRecorder = null
|
|
47
|
-
_this.buffers = [];
|
|
48
|
-
return _this;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
_createClass(DesktopAudioRecorder, [{
|
|
52
|
-
key: 'componentDidMount',
|
|
53
|
-
value: function componentDidMount() {
|
|
54
|
-
var _this2 = this;
|
|
55
|
-
|
|
56
|
-
window.navigator.getUserMedia({
|
|
57
|
-
"audio": {
|
|
58
|
-
"mandatory": {
|
|
59
|
-
"googEchoCancellation": "false",
|
|
60
|
-
"googAutoGainControl": "false",
|
|
61
|
-
"googNoiseSuppression": "false",
|
|
62
|
-
"googHighpassFilter": "false"
|
|
63
|
-
},
|
|
64
|
-
"optional": []
|
|
65
|
-
}
|
|
66
|
-
}, function (stream) {
|
|
67
|
-
return _this2.onMediaSuccess(stream);
|
|
68
|
-
}, function (stream) {
|
|
69
|
-
return _this2.onMediaError(stream);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}, {
|
|
73
|
-
key: 'render',
|
|
74
|
-
value: function render() {
|
|
75
|
-
var _this3 = this;
|
|
76
|
-
|
|
77
|
-
var _state = this.state,
|
|
78
|
-
isRecording = _state.isRecording,
|
|
79
|
-
waveform = _state.waveform;
|
|
80
|
-
|
|
81
|
-
return _react2.default.createElement(
|
|
82
|
-
'div',
|
|
83
|
-
null,
|
|
84
|
-
'Desktop audio recorder',
|
|
85
|
-
isRecording ? _react2.default.createElement(
|
|
86
|
-
'button',
|
|
87
|
-
{ onClick: function onClick() {
|
|
88
|
-
return _this3.stopRecording();
|
|
89
|
-
} },
|
|
90
|
-
' stop recording '
|
|
91
|
-
) : _react2.default.createElement(
|
|
92
|
-
'button',
|
|
93
|
-
{ onClick: function onClick() {
|
|
94
|
-
return _this3.record();
|
|
95
|
-
} },
|
|
96
|
-
' record '
|
|
97
|
-
),
|
|
98
|
-
waveform ? _react2.default.createElement(_CustomWave2.default, {
|
|
99
|
-
width: 500,
|
|
100
|
-
currentTime: 0,
|
|
101
|
-
totalTime: 200,
|
|
102
|
-
height: 40,
|
|
103
|
-
isLoading: false,
|
|
104
|
-
waveform: waveform
|
|
105
|
-
}) : null
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}, {
|
|
109
|
-
key: 'record',
|
|
110
|
-
value: function record() {
|
|
111
|
-
this.setState({
|
|
112
|
-
recordedData: null,
|
|
113
|
-
isRecording: true
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}, {
|
|
117
|
-
key: 'onMediaSuccess',
|
|
118
|
-
value: function onMediaSuccess(stream) {
|
|
119
|
-
var _this4 = this;
|
|
120
|
-
|
|
121
|
-
var bufferSize = 4096;
|
|
122
|
-
var numberOfInputChannels = 2;
|
|
123
|
-
var numberOfOutputChannels = 2;
|
|
124
|
-
|
|
125
|
-
// creates an audio node from the microphone incoming stream
|
|
126
|
-
var mediaStream = audioContext.createMediaStreamSource(stream);
|
|
127
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/AudioaudioContext/createScriptProcessor
|
|
128
|
-
var recorder = audioContext.createScriptProcessor ? audioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels) : audioContext.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);
|
|
129
|
-
|
|
130
|
-
recorder.onaudioprocess = function (e) {
|
|
131
|
-
var _state2 = _this4.state,
|
|
132
|
-
recordedData = _state2.recordedData,
|
|
133
|
-
isRecording = _state2.isRecording;
|
|
134
|
-
|
|
135
|
-
if (!isRecording) return;
|
|
136
|
-
var audioBuffer = (0, _audio.appendBuffer)(recordedData, e.inputBuffer);
|
|
137
|
-
var waveform = (0, _audio.convertAudioBufferToWaveform)(audioBuffer);
|
|
138
|
-
|
|
139
|
-
_this4.setState({
|
|
140
|
-
recordedData: audioBuffer,
|
|
141
|
-
waveform: waveform
|
|
142
|
-
});
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// we connect the recorder with the input stream
|
|
146
|
-
mediaStream.connect(recorder);
|
|
147
|
-
recorder.connect(audioContext.destination);
|
|
148
|
-
}
|
|
149
|
-
}, {
|
|
150
|
-
key: 'onMediaError',
|
|
151
|
-
value: function onMediaError(e) {
|
|
152
|
-
console.error('media error', e);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// This is just for demo purposes: in real life we'll upload the file somewhere
|
|
156
|
-
|
|
157
|
-
}, {
|
|
158
|
-
key: 'updateAudioDom',
|
|
159
|
-
value: function updateAudioDom() {
|
|
160
|
-
var recordedData = this.state.recordedData;
|
|
161
|
-
|
|
162
|
-
var audioEl = document.querySelector('audio');
|
|
163
|
-
|
|
164
|
-
if (audioEl) {
|
|
165
|
-
var wav = (0, _audio.audioBufferToWav)(recordedData);
|
|
166
|
-
var audioBlob = new Blob([wav], { type: 'audio/wav' });
|
|
167
|
-
var reader = new FileReader();
|
|
168
|
-
reader.onload = function (e) {
|
|
169
|
-
// e.target.result will hold the base64 data.
|
|
170
|
-
// Note: It includes the pre-text "data:audio/<format>;base64,<base64 data>"
|
|
171
|
-
audioEl.src = e.target.result;
|
|
172
|
-
};
|
|
173
|
-
reader.readAsDataURL(audioBlob);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}, {
|
|
177
|
-
key: 'stopRecording',
|
|
178
|
-
value: function stopRecording() {
|
|
179
|
-
this.setState({
|
|
180
|
-
isRecording: false
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// Update audio element with new file
|
|
184
|
-
this.updateAudioDom();
|
|
185
|
-
}
|
|
186
|
-
}]);
|
|
187
|
-
|
|
188
|
-
return DesktopAudioRecorder;
|
|
189
|
-
}(_react.Component);
|
|
190
|
-
|
|
191
|
-
exports.default = DesktopAudioRecorder;
|