Answer please
I am working on a React project where I need to extract audio from a video file, process it, and upload it for analysis. The code works perfectly on desktop browsers and Android devices, but it fails on iPhones. The error I get on iPhones is related to FileReader.readAsArrayBuffer and AudioContext.decodeAudioData.
this is error message
const handleFileChange = (event) => {
setFile(event.target.files[0]);
};
const handleDrop = (event) => {
event.preventDefault();
const droppedFile = event.dataTransfer.files[0];
setFile(droppedFile);
};
const handleDragOver = (event) => {
event.preventDefault();
};
const extractAudioFromVideo = async (file) => {
return new Promise((resolve, reject) => {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const reader = new FileReader();
reader.onload = function () {
const arrayBuffer = reader.result;
audioContext.decodeAudioData(arrayBuffer).then((decodedAudioData) => {
const offlineAudioContext = new OfflineAudioContext(
decodedAudioData.numberOfChannels,
decodedAudioData.duration * decodedAudioData.sampleRate,
decodedAudioData.sampleRate
);
const soundSource = offlineAudioContext.createBufferSource();
soundSource.buffer = decodedAudioData;
soundSource.connect(offlineAudioContext.destination);
soundSource.start();
offlineAudioContext.startRendering().then((renderedBuffer) => {
const wavBlob = audioBufferToWav(renderedBuffer);
resolve(wavBlob);
}).catch((err) => {
console.error('Error during offline audio rendering:', err);
reject(err);
});
}).catch((err) => {
console.error('Error decoding audio data:', err);
reject(err);
});
};
reader.onerror = function (err) {
console.error('Error reading file:', err);
reject(err);
};
if (file instanceof Blob) {
console.log('File is a Blob, reading as ArrayBuffer');
reader.readAsArrayBuffer(file);
} else {
console.error('File must be an instance of Blob');
reject(new Error('File must be an instance of Blob'));
}
});
};
const audioBufferToWav = (buffer) => {
const numOfChan = buffer.numberOfChannels,
length = buffer.length * numOfChan * 2 + 44,
bufferArray = new ArrayBuffer(length),
view = new DataView(bufferArray),
channels = [],
sampleRate = buffer.sampleRate;
let offset = 0;
let pos = 0;
setUint32(0x46464952); // "RIFF"
setUint32(length - 8); // file length - 8
setUint32(0x45564157); // "WAVE"
setUint32(0x20746d66); // "fmt " chunk
setUint32(16); // length = 16
setUint16(1); // PCM (uncompressed)
setUint16(numOfChan);
setUint32(sampleRate);
setUint32(sampleRate * 2 * numOfChan); // avg. bytes/sec
setUint16(numOfChan * 2); // block-align
setUint16(16); // 16-bit (hardcoded in this demo)
setUint32(0x61746164); // "data" - chunk
setUint32(length - pos - 4); // chunk length
for (let i = 0; i < buffer.numberOfChannels; i++) {
channels.push(buffer.getChannelData(i));
}
while (pos < length) {
for (let i = 0; i < numOfChan; i++) {
const sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
view.setInt16(pos, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true); // write 16-bit sample
pos += 2;
}
offset++;
}
return new Blob([bufferArray], { type: "audio/wav" });
function setUint16(data) {
view.setUint16(pos, data, true);
pos += 2;
}
function setUint32(data) {
view.setUint32(pos, data, true);
pos += 4;
}
};
const pollAudioProcessingStatus = async (publicId) => {
try {
const response = await axios.get(`https://node-ts-boilerplate-production-79e3.up.railway.app/api/v1/audio/status/${publicId}`);
if (response.data.status === 'processing') {
setTimeout(() => pollAudioProcessingStatus(publicId), 3000); // poll every 3 seconds
} else {
setAudioResponse(response.data);
setAudioProcessing(false);
analyzeTextWithGpt(response.data.results.amazon.text);
}
} catch (error) {
console.error('Error polling audio processing status:', error);
setError('Error polling audio processing status');
setAudioProcessing(false);
}
};
const analyzeTextWithGpt = async (text) => {
try {
const response = await axios.post('https://node-ts-boilerplate-production-79e3.up.railway.app/api/v1/audio/analyze-text', { text });
setGptResponse(response.data);
} catch (error) {
console.error('Error analyzing text with GPT-3:', error);
setError('Error analyzing text with GPT-3');
}
};
const handleSubmit = async (event) => {
event.preventDefault();
setError(null);
setAudioResponse(null);
setVideoResponse(null);
setGptResponse(null);
setLoadingStage('uploading');
setAudioProcessing(true);
try {
const audioBlob = await extractAudioFromVideo(file);
const audioFormData = new FormData();
audioFormData.append('audio', audioBlob, 'audio.wav');
audioFormData.append('language', language); // Pass the selected language
const videoFormData = new FormData();
videoFormData.append('video', file);
videoFormData.append('language', language); // Pass the selected language
axios.post('https://node-ts-boilerplate-production-79e3.up.railway.app/api/v1/audio/uploadd', audioFormData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(audioUploadResponse => {
const publicId = audioUploadResponse.data.public_id;
pollAudioProcessingStatus(publicId);
}).catch(err => {
console.error('Error uploading audio file:', err);
setError('Error uploading audio file');
setLoadingStage(null);
setAudioProcessing(false);
});
axios.post('https://node-ts-boilerplate-production-79e3.up.railway.app/api/v1/video/upload', videoFormData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(videoUploadResponse => {
setVideoResponse(videoUploadResponse.data);
setLoadingStage(null);
}).catch(err => {
console.error('Error uploading video file:', err);
setError('Error uploading video file');
setLoadingStage(null);
});
} catch (err) {
console.error('Error processing file:', err);
setError('Error processing file');
setLoadingStage(null);
setAudioProcessing(false);
}
};
The above code handles the file reading and audio extraction. Here are the issues I’m facing:
On iPhones, FileReader.readAsArrayBuffer seems to fail.
AudioContext.decodeAudioData throws errors on iPhones.
What could be causing these issues specifically on iPhones, and how can I make this code compatible across all devices, including iPhones?
Additional Information:
I have tested this on various browsers on iPhones, and the issue persists.
The file is being read as a Blob instance correctly.
Any insights or solutions would be greatly appreciated!