I have an app that generates stories for children. It uses a text-to-speech (TTS) API which returns the text in a readablestream for consumption for the client and then uses Howler to play the audio. One issue with this is that it won't stream the audio data -- it waits to read all the chunks into the blob before playing them, which results in additional delay. Since Howler.js doesn't support true audio streaming out of the box, I need to use the HTML5 Audio API.I was going to use the MediaSource (MSE) API with an audio element for this, but then I learned that MSE does not work in mobile devices (or, am I misunderstood?). Does anyone have any advice on how I can stream the audio as soon as possible? Here is my current code setup: <template> <UButton @click="generateSpeech()">Generate Speech</UButton> <audio :src="audioSrc" controls></audio></template><script setup>import { Howl } from 'howler'const isPlayable = ref(false)let audioDataChunks = []let howl;const audioSrc = ref(null)const formattedStory = 'In this heartfelt tale, a young pig named Pippin forms an unexpected friendship with a small spider named Silky. Pippin is initially afraid of Silky, but through mutual kindness and understanding, they become inseparable friends. The story gently explores themes of friendship, empathy, and overcoming fears. <break time="2.0s" /> The Tale of Pippin and Silky <break time="1.5s" /> Once upon a time, in a peaceful farm nestled in the countryside, lived a young pig named Pippin. Pippin was a joyful and curious piglet, but there was one thing he feared more than anything - spiders. One day, while exploring the farm, Pippin discovered a small spider, no bigger than a button, in his favorite mud puddle. Do you remember a time when you were afraid of something? What helped you overcome your fear? <break time="3.0s" /> The spider was Silky, a tiny, friendly creature who had spun a delicate web across the corner of the puddle. Pippin squealed in fright and backed away, but Silky only waved her eight legs in a friendly manner. Pippin was surprised. He had always imagined spiders to be scary and mean, but Silky didn\'t seem to be either of those things. She seemed... kind. Has there been a time when something wasn\'t as scary as you first thought? <break time="3.0s" /> Feeling braver, Pippin took a step closer and introduced himself. Silky replied in her soft, sweet voice, "Hello, Pippin\'! I mean no harm.'const generateSpeech = async (formattedStory) => { try { const response = await $fetch("/api/generate-text-to-speech", { method: "POST", headers: { accept: "audio/mpeg", }, responseType: 'stream', body: { text: formattedStory } }); const reader = response.getReader(); // While true loop for streaming while (true) { const { done, value } = await reader.read(); if (done) { break; } audioDataChunks.push(value); } const blob = new Blob(audioDataChunks, { type: 'audio/mpeg' }); const blobURL = URL.createObjectURL(blob); // Initialize Howler.js Howl object howl = new Howl({ src: [blobURL], format: ['mp3'], html5: true, // <-- I thought this would stream the audio ??? onload: () => { isPlayable.value = true audioSrc.value = blobURL }, onloaderror: (id, err) => { console.error("Load error: ", err) } }) } catch (e) { console.error("Audio generation failed: ", e); }}</script>
|