I am creating an app with a text-to-speech functionality. You click a button on the front-end (React Native), and it requests the server (Node.js) to ask Google TTS to generate an MP3 file, which I would then like the app to play aloud.
However, when I run it on my android phone, I keep on getting the same error 'name is null' from my front-end when creating and playing the sound object from the server response. I know the server-side URL works because when I type it in browser, I am able to download the MP3 directly.
I haven't been able to find much via documentation, so have been using ChatGPT to help me debug, but to no avail... I have tried a bunch of alternative fetch (rn-fetch-blob) and encoders, but nothing has helped.
Thank you very much for your help <3
Below are the relevant functions server-side and client-side:
Index.js (server)
app.get('/tts', async (req, res) => {
const text = 'hello, world!';
// Construct the request
const request = {
input: { text: text },
// Select the language and SSML voice gender (optional)
voice: { languageCode: 'en-US', ssmlGender: 'NEUTRAL' },
// select the type of audio encoding
audioConfig: { audioEncoding: 'MP3' },
};
try {
// Performs the text-to-speech request
const [response] = await textToSpeechClient.synthesizeSpeech(request);
// Set response headers to indicate MP3 content
res.set('Content-Type', 'audio/mpeg');
res.set('Content-Disposition', 'attachment; filename=output.mp3');
// Send the audio content back to the client
console.log(response.audioContent);
res.send(response.audioContent);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
Client-side function for playing the sound:
import Sound from 'react-native-sound';
const speakMessage = async () => {
try {
const response = await fetch('* URL - hidden for privacy reasons :) *');
const audioArrayBuffer = await response.arrayBuffer();
// Convert ArrayBuffer to Uint8Array
const audioUint8Array = new Uint8Array(audioArrayBuffer);
// Create blob from Uint8Array
const blob = new Blob([audioUint8Array], { type: 'audio/mpeg' });
// Check if filename is available (replace 'output.mp3' with actual filename if available)
const filename = 'output.mp3';
// Ensure filename is not null or empty
if (!filename) {
console.error('Error: Invalid filename');
return;
}
console.log('Blob:', blob);
console.log('Filename:', filename);
// Create a new Sound instance from the blob
const sound = new Sound(blob, filename, (error) => {
if (error) {
console.log('Error loading sound:', error);
} else {
console.log('Sound loaded successfully');
// Play the sound
sound.play((success) => {
if (success) {
console.log('Sound played successfully');
} else {
console.log('Playback failed due to audio decoding errors');
}
});
}
});
} catch (error) {
console.error('Error fetching or playing audio:', error);
}
};
Mainly debugged using ChatGPT, it made me try a bunch of different ways of fetching the file (axios, fetch) and encoders like Uint8Array, Buffer, etc..., Tried to explicitly give the sound a filename.