Я не знаю, возможно ли то, что я хочу сделать, в iOS 13. Я хочу иметь возможность отправлять на мой сервер несколько аудиозаписей всего за одно взаимодействие с пользователем. Я использую API Web Audio.
В результате некоторых исследований я обнаружил, что new AudioContext()
должен вызываться из обработчика пользовательского ввода, как нажатие кнопки.
Он должен быть вызван перед getUserMedia, так как он возвращает Promise, и каждый фрагмент кода, который выполняется здесь после, рассматривается как автоматически созданный сценарий, в результате чего контекст остается приостановленным.
function WzRecorder(config) {
var self = this;
var recording = false;
this.start = function() {
// reset any previous data
recordedData = [];
recordingLength = 0;
// webkit audio context shim
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (audioCtx.createJavaScriptNode) {
audioNode = audioCtx.createJavaScriptNode(bufferSize, 1, 1);
} else if (audioCtx.createScriptProcessor) {
audioNode = audioCtx.createScriptProcessor(bufferSize, 1, 1);
} else {
throw 'WebAudio not supported!';
}
audioNode.connect(audioCtx.destination);
navigator.mediaDevices.getUserMedia({audio: true})
.then(onMicrophoneCaptured)
.catch(onMicrophoneError);
};
function onMicrophoneCaptured(microphone) {
// save the stream so we can disconnect it when we're done
window.localStream = microphone;
audioInput = audioCtx.createMediaStreamSource(microphone);
audioInput.connect(audioNode);
audioNode.onaudioprocess = onAudioProcess;
recording = true;
self.startDate = new Date();
config.onRecordingStart && config.onRecordingStart();
sampleRate = audioCtx.sampleRate;
var source = audioCtx.createMediaStreamSource(microphone);
var analyser = audioCtx.createAnalyser();
analyser.fftSize = 2048;
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
source.connect(analyser);
}
function stopRecording(callback) {
// stop recording
recording = false;
// to make sure onaudioprocess stops firing
window.localStream.getTracks().forEach( (track) => { track.stop(); });
audioInput.disconnect();
audioNode.disconnect();
exportWav({
sampleRate: sampleRate,
recordingLength: recordingLength,
data: recordedData
}, function(buffer, view) {
self.blob = new Blob([view], { type: 'audio/wav' });
callback && callback(self.blob);
});
}
function onAudioProcess(e) {
if (!recording) {
return;
}
recordedData.push(new Float32Array(e.inputBuffer.getChannelData(0)));
recordingLength += bufferSize;
}
}
Так что прямо сейчас, если пользователь нажимает кнопку, которая запускает WzRecorder.start
, он начнет, а затем остановит запись через X секунд. Я хочу, чтобы это повторялось без нажатия пользователем кнопки.
У меня есть другой код, который вызывает WzRecorder.start
и WzRecorder.stop
каждые X секунд. Проблема заключается в том, что после вызова WzRecorder.start
с этим кодом он достигает на MicrophoneCaptured, но звук остается пустым. Однако красный микрофон в моем браузере показывает, что он останавливается и запускается соответствующим образом.
Я попытался разделить new AudioContext()
и getUserMedia
, но когда я хотел вызвать getUserMedia, у него все еще было предыдущее аудио.
Если onMicrophoneCapture
нужно использовать audioCtx
, это делает значит, я не могу делать то, что хочу?
или если пользователь запускает new AudioContext()
, должен быть способ запустить и остановить рекордер?