I have the following setup when I want to track a bunch of metadata when a user listens to an audio from my app. However, for some reason, length_played
always remain 0
and time_listened
is inaccurate since. I believe that is the case because updated values of spokenText
and speakStartTime
are not available when onSpeakDone
callback is executed.
I am new to React Native and I am sure I am overlooking something here. Can you please point me into the right direction?
LOG:
!!!
{"length": 460, "length_played": 0, "name": "San Diego", "termination_kind": "done", "time_listened": 1718124515}
!!!
Code
export default function PlaceCard({ className, isCurrent, latitude, longitude, placeName }: PlaceCardProps) {
const { place } = usePlace(latitude, longitude, placeName)
const { name, summary } = place
const speaking = useAppStore(state => state.speaking)
const setSpeaking = useAppStore(state => state.setSpeaking)
const setCanSpeak = useAppStore(state => state.setCanSpeak)
const [spokenText, setSpokenText] = useState('')
const [speakStartTime, setSpeakStartTime] = useState(0)
const unspokenText = summary.slice(spokenText.length)
const onSpeakBoundary = useCallback(({ charIndex, charLength }: NativeBoundaryEvent) => {
const spoken = summary.slice(0, charIndex) + summary.slice(charIndex, charIndex + charLength)
setSpokenText(spoken)
}, [summary])
const onSpeakDone = useCallback((termination: string) => {
setSpeaking(false)
const metadata = {
length: summary.length,
length_played: spokenText.length,
name,
termination_kind: termination,
time_listened: Math.round((Date.now() - speakStartTime) / 1000),
}
console.log('!!!')
console.log(metadata)
console.log('!!!')
logEvent('place_summary_play', metadata)
setSpokenText('')
setSpeakStartTime(0)
}, [spokenText, speakStartTime, name, summary, setSpeaking, setSpokenText, setSpeakStartTime])
useEffect(() => {
if (place.summaryState === 'complete')
setCanSpeak(true)
const options: Speech.SpeechOptions = {
language: 'en-US',
onBoundary: onSpeakBoundary,
onDone: () => onSpeakDone('done'),
onError: () => onSpeakDone('error'),
onStart: () => setSpeakStartTime(Date.now()),
voice: 'com.apple.ttsbundle.siri_Nicky_en-US_compact',
}
speaking ? Speech.speak(place.summary, options) : Speech.stop()
}, [place.summary, place.summaryState, speaking, setCanSpeak, onSpeakDone, onSpeakBoundary])
if (!place)
return null
return (
<View className={`${className}`}>
<SafeAreaView>
<ScrollView
className="h-full"
refreshControl={<CustomRefreshControl />}
stickyHeaderIndices={[0]}
>
<Header isCurrent={isCurrent} place={place} />
<Images place={place} />
<Summary place={place} spokenText={spokenText} unspokenText={unspokenText} />
<LearnMore place={place} />
<NearbyPlaces place={place} />
</ScrollView>
</SafeAreaView>
</View>
)
}
I was expecting the updated values of spokenText
and speakStartTime
to be available inside onSpeakDone
callback.