Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encode after record #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.DS_Store
node_modules

/.idea
157 changes: 118 additions & 39 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15816,20 +15816,25 @@ var MicRecorder = function () {
// 128 or 160 kbit/s – mid-range bitrate quality
bitRate: 128,

deviceId: null,
// Encode to mp3 after finish recording
// Encoding during recording may result in distorted audio
// This could be crucial on mobile devices
encodeAfterRecord: true,
// There is a known issue with some macOS machines, where the recording
// will sometimes have a loud 'pop' or 'pop-click' sound. This flag
// prevents getting audio from the microphone a few milliseconds after
// the begining of the recording. It also helps to remove the mouse
// the beginning of the recording. It also helps to remove the mouse
// "click" sound from the output mp3 file.
startRecordingAt: 300,
deviceId: null
startRecordingAt: 300
};

this.activeStream = null;
this.context = null;
this.microphone = null;
this.processor = null;
this.startTime = 0;
this.rawChunksBuffer = null;

Object.assign(this.config, config);
}
Expand Down Expand Up @@ -15864,26 +15869,118 @@ var MicRecorder = function () {
return;
}

// Send microphone data to LAME for MP3 encoding while recording.
_this.lameEncoder.encode(event.inputBuffer.getChannelData(0));
var rawChunk = event.inputBuffer.getChannelData(0);

if (_this.config.encodeAfterRecord) {
// Save copy of raw chunk for future encoding
_this.rawChunksBuffer.push(Object.assign([], rawChunk));
} else {
// Send microphone data to LAME for MP3 encoding while recording.
_this.lameEncoder.encode(rawChunk);
}
};

// Begin retrieving microphone data.
this.microphone.connect(this.processor);
this.processor.connect(this.context.destination);
this.connectMicrophone();
}
}, {
key: 'stop',
key: 'initialize',


/**
* Requests access to the microphone and starts recording
* @return Promise
*/
value: function initialize() {
var _this2 = this;

var _config = this.config,
deviceId = _config.deviceId,
encodeAfterRecord = _config.encodeAfterRecord;

var AudioContext = window.AudioContext || window.webkitAudioContext;
this.context = new AudioContext();
this.config.sampleRate = this.context.sampleRate;
this.rawChunksBuffer = encodeAfterRecord ? [] : null;
this.lameEncoder = new Encoder(this.config);
this.i = 0;

var audio = deviceId ? { deviceId: { exact: deviceId } } : true;

return new Promise(function (resolve, reject) {
navigator.mediaDevices.getUserMedia({ audio: audio }).then(function (stream) {
_this2.addMicrophoneListener(stream);
resolve(stream);
}).catch(function (err) {
reject(err);
});
});
}
}, {
key: 'start',


/**
* Initializes or resumes recording
* @return Promise
*/
value: function start() {
if (!this.processor || !this.microphone) {
return this.initialize();
} else {
this.connectMicrophone();
return Promise.resolve();
}
}

/**
* Pause recording
* @return Promise
*/

}, {
key: 'pause',
value: function pause() {
this.disconnectMicrophone();
return Promise.resolve();
}
}, {
key: 'connectMicrophone',


/**
* Start retrieving microphone data
*/
value: function connectMicrophone() {
if (this.processor && this.microphone) {
this.microphone.connect(this.processor);
this.processor.connect(this.context.destination);
}
}

/**
* Stop retrieving microphone data
*/

}, {
key: 'disconnectMicrophone',
value: function disconnectMicrophone() {
if (this.processor && this.microphone) {
this.microphone.disconnect();
this.processor.disconnect();
}
}

/**
* Disconnect microphone, processor and remove activeStream
* @return MicRecorder
*/

}, {
key: 'stop',
value: function stop() {
if (this.processor && this.microphone) {
// Clean up the Web Audio API resources.
this.microphone.disconnect();
this.processor.disconnect();
this.disconnectMicrophone();

// If all references using this.context are destroyed, context is closed
// automatically. DOMException is fired when trying to close again
Expand All @@ -15897,48 +15994,30 @@ var MicRecorder = function () {
this.activeStream.getAudioTracks().forEach(function (track) {
return track.stop();
});
this.processor = null;
this.microphone = null;
}

return this;
}
}, {
key: 'start',


/**
* Requests access to the microphone and start recording
* @return Promise
*/
value: function start() {
var _this2 = this;

var AudioContext = window.AudioContext || window.webkitAudioContext;
this.context = new AudioContext();
this.config.sampleRate = this.context.sampleRate;
this.lameEncoder = new Encoder(this.config);

var audio = this.config.deviceId ? { deviceId: { exact: this.config.deviceId } } : true;

return new Promise(function (resolve, reject) {
navigator.mediaDevices.getUserMedia({ audio: audio }).then(function (stream) {
_this2.addMicrophoneListener(stream);
resolve(stream);
}).catch(function (err) {
reject(err);
});
});
}
}, {
key: 'getMp3',


/**
* Return Mp3 Buffer and Blob with type mp3
* @return {Promise}
* @return Promise
*/
value: function getMp3() {
var _this3 = this;

if (this.config.encodeAfterRecord) {
this.rawChunksBuffer.forEach(function (rawChunk) {
_this3.lameEncoder.encode(rawChunk);
});
this.rawChunksBuffer = null;
}

var finalBuffer = this.lameEncoder.finish();

return new Promise(function (resolve, reject) {
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

75 changes: 60 additions & 15 deletions samples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ <h1>Mic Recorder to Mp3 Example</h1>

<hr />

<button class="btn btn-primary">Start recording</button>
<div title="Warning: Disable this option can cause audio distortion">
<input id="encode-after-record" type="checkbox" checked>
Encode after record
</div>

<br />
<br />

<button id="start-pause" class="btn btn-primary"></button>
<button id="stop" class="btn btn-danger" disabled></button>

<br />
<br />
Expand All @@ -25,19 +34,52 @@ <h1>Mic Recorder to Mp3 Example</h1>
<!-- <script src="https://unpkg.com/mic-recorder-to-mp3"></script> -->
<script src="../dist/index.js"></script>
<script>
const button = document.querySelector('button');
const recorder = new MicRecorder({
bitRate: 128
});
const LABELS = {
START: 'Start recording',
PAUSE: 'Pause recording',
RESUME: 'Resume recording',
STOP: 'Stop recording'
};

const encodeAfterRecordCheck = document.getElementById('encode-after-record');
const startPauseButton = document.getElementById('start-pause');
const stopButton = document.getElementById('stop');
let recorder
initRecorder()

startPauseButton.textContent = LABELS.START;
stopButton.textContent = LABELS.STOP;

encodeAfterRecordCheck.addEventListener('change', initRecorder)
startPauseButton.addEventListener('click', startRecording);
stopButton.addEventListener('click', stopRecording);

button.addEventListener('click', startRecording);
function initRecorder() {
recorder = new MicRecorder({
bitRate: 128,
encodeAfterRecordCheck: encodeAfterRecordCheck.checked
});
}

function startRecording() {
recorder.start().then(() => {
button.textContent = 'Stop recording';
button.classList.toggle('btn-danger');
button.removeEventListener('click', startRecording);
button.addEventListener('click', stopRecording);
encodeAfterRecordCheck.disabled = true;
startPauseButton.textContent = LABELS.PAUSE;
startPauseButton.classList.add('btn-info');
stopButton.disabled = false;
startPauseButton.removeEventListener('click', startRecording);
startPauseButton.addEventListener('click', pauseRecording);
}).catch((e) => {
console.error(e);
});
}

function pauseRecording() {
recorder.pause().then(() => {
startPauseButton.textContent = LABELS.RESUME;
startPauseButton.classList.remove('btn-info');
startPauseButton.removeEventListener('click', pauseRecording);
startPauseButton.addEventListener('click', startRecording);
}).catch((e) => {
console.error(e);
});
Expand All @@ -46,6 +88,8 @@ <h1>Mic Recorder to Mp3 Example</h1>
function stopRecording() {
recorder.stop().getMp3().then(([buffer, blob]) => {
console.log(buffer, blob);
encodeAfterRecordCheck.disabled = false;
stopButton.disabled = true;
const file = new File(buffer, 'music.mp3', {
type: blob.type,
lastModified: Date.now()
Expand All @@ -57,14 +101,15 @@ <h1>Mic Recorder to Mp3 Example</h1>
li.appendChild(player);
document.querySelector('#playlist').appendChild(li);

button.textContent = 'Start recording';
button.classList.toggle('btn-danger');
button.removeEventListener('click', stopRecording);
button.addEventListener('click', startRecording);
startPauseButton.textContent = LABELS.START;
startPauseButton.classList.remove('btn-info');
startPauseButton.removeEventListener('click', startRecording);
startPauseButton.removeEventListener('click', pauseRecording);
startPauseButton.addEventListener('click', startRecording);
}).catch((e) => {
console.error(e);
});
}
</script>
</body>
</html>
</html>
2 changes: 1 addition & 1 deletion src/encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@ class Encoder {

return this.dataBuffer;
}
};
}

export default Encoder;
Loading