🎤 Micdrop

Hooks and Call State

The hooks live in @micdrop/react and are the same ones a web app uses, since the call state is the same on both platforms.

Terminal window
npm install @micdrop/react

useMicdropState

Returns the whole state of the call, and re-renders when any of it changes.

import { useMicdropState } from '@micdrop/react'
import { Text } from 'react-native'
function CallStatus() {
const state = useMicdropState()
if (state.isReconnecting) return <Text>Reconnecting</Text>
if (state.isStarting) return <Text>Starting</Text>
if (!state.isStarted) return <Text>Ready</Text>
if (state.isUserSpeaking) return <Text>Listening</Text>
if (state.isAssistantSpeaking) return <Text>Speaking</Text>
if (state.isProcessing) return <Text>Thinking</Text>
return <Text>Your turn</Text>
}
FieldTypeMeaning
isStartingbooleanThe call is opening
isStartedbooleanThe call is running
isReconnectingbooleanThe connection dropped and is being retried
isListeningbooleanWaiting for the user to speak
isUserSpeakingbooleanThe user is speaking right now
isProcessingbooleanThe server is working on an answer
isAssistantSpeakingbooleanThe answer is being played
isMutedbooleanThe microphone is off, the call is running
isPausedbooleanBoth sides are on hold
isMicStartedbooleanThe microphone is capturing
conversationMicdropConversationEverything said so far
speakerDeviceId'speaker' | 'earpiece'Where the voice is played
micDevicesMicdropDevice[]Inputs the OS offers
speakerDevicesMicdropDevice[]Outputs the OS offers
micDeviceIdstring | undefinedInput in use
errorMicdropClientErrorThe last error, if any

useMicdropError

Called when the microphone is refused, the server is unreachable, or the call is rejected. The codes are the same as in the browser, see Error handling.

import { useMicdropError } from '@micdrop/react'
import { useCallback, useState } from 'react'
function CallScreen() {
const [message, setMessage] = useState<string>()
useMicdropError(
useCallback((error) => setMessage(error.message || error.code), [])
)
return <Text>{message}</Text>
}

Wrap the callback in useCallback, the hook resubscribes whenever it changes.

useMicdropEndCall

Called when the assistant hangs up on its own, see Auto end call.

import { useMicdropEndCall } from '@micdrop/react'
import { Micdrop } from '@micdrop/react-native'
import { useCallback } from 'react'
function CallScreen() {
useMicdropEndCall(
useCallback(() => {
Micdrop.stop()
navigation.goBack()
}, [navigation])
)
}

useMicdropToolCall

Called when the agent runs one of its tools, with its name, parameters and output.

import { useMicdropToolCall } from '@micdrop/react'
import { useCallback } from 'react'
function CallScreen() {
useMicdropToolCall(
useCallback((toolCall) => {
if (toolCall.name === 'openMap') {
showMap(toolCall.parameters.place)
}
}, [])
)
}

useMicVolume and useSpeakerVolume

Levels in decibels, updated about ten times a second, for a meter or a pulsing avatar. Silence reads as -Infinity, so map the range you care about.

import { useMicVolume } from '@micdrop/react'
import { View } from 'react-native'
function MicMeter() {
const { micVolume } = useMicVolume()
const ratio = Math.max(0, Math.min(1, (micVolume + 60) / 60))
return <View style={{ width: `${ratio * 100}%`, height: 8 }} />
}

useSpeakerVolume works the same way for the assistant voice, and follows what is being heard rather than what has arrived, so a burst of audio does not light the meter up all at once.