---
title: "Headless Hook"
description: "useThunderPhone React hook વડે સંપૂર્ણ કસ્ટમ વૉઇસ UI બનાવો"
---

`useThunderPhone` હૂક તમને યુઝર ઇન્ટરફેસ પર સંપૂર્ણ નિયંત્રણ આપે છે, જ્યારે ThunderPhone વૉઇસ સેશન, ઑડિયો રૂટિંગ અને કનેક્શન સ્ટેટનું સંચાલન કરે છે. જ્યારે તમને સંપૂર્ણપણે કસ્ટમ UI જોઈએ ત્યારે તેનો ઉપયોગ કરો -- તમારા પોતાના બટનો, લેઆઉટ, એનિમેશન અને બ્રાન્ડિંગ સાથે -- જ્યારે ThunderPhone આંતરિક રીતે બધું સંભાળે છે.

## હેડલેસ હૂકનો ઉપયોગ ક્યારે કરવો

પૂર્વનિર્મિત `ThunderPhoneWidget` કોમ્પોનેન્ટ મોટા ભાગના ઉપયોગના કેસ આવરી લે છે, પરંતુ જ્યારે તમને નીચેની જરૂર હોય ત્યારે હેડલેસ હૂકનો ઉપયોગ કરો:

- તમારી એપ્લિકેશનની ડિઝાઇન સિસ્ટમ સાથે મેળ ખાતું સંપૂર્ણપણે કસ્ટમ કૉલ UI
- રીઅલ-ટાઇમ ઑડિયો લેવલ દ્વારા સંચાલિત ઑડિયો-પ્રતિક્રિયાશીલ વિઝ્યુઅલાઇઝેશન (વેવફોર્મ્સ, ઓર્બ્સ, ધબકતા ઇન્ડિકેટર્સ)
- કસ્ટમ કૉલ ફ્લો, જેમ કે કૉલ પહેલાંના ફોર્મ, કૉલ પછીના સર્વે અથવા વૉઇસ સાથે ઇનલાઇન ચેટ
- હાલની કોમ્પોનેન્ટ લાઇબ્રેરીમાં એકીકરણ (Material UI, Chakra, Radix, વગેરે)

---

## ઇન્સ્ટોલેશન

```bash
npm install @thunderphone/widget
```

<Note>
  હેડલેસ હૂક માટે `@thunderphone/widget/style.css` ઇમ્પોર્ટ કરવાની જરૂર **નથી**, કારણ કે તમે તમારું પોતાનું UI પ્રદાન કરી રહ્યા છો. જોકે, તમારે એ જ `@thunderphone/widget` પેકેજ ઇન્સ્ટોલ કરવું આવશ્યક છે.
</Note>

---

## મૂળભૂત ઉપયોગ

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function CustomCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  const handleClick = () => {
    if (phone.state === 'connected') {
      phone.disconnect()
    } else {
      phone.connect()
    }
  }

  return (
    <>
      <button onClick={handleClick} disabled={phone.state === 'connecting'}>
        {phone.state === 'connecting'
          ? 'Connecting...'
          : phone.state === 'connected'
            ? 'End call'
            : 'Start call'}
      </button>
      {phone.audio}
    </>
  )
}
```

<Warning>
  **તમારે તમારા કોમ્પોનેન્ટ ટ્રીમાં ક્યાંક `phone.audio` રેન્ડર કરવું આવશ્યક છે.** તે એક અદૃશ્ય React એલિમેન્ટ છે જે આંતરિક ઑડિયો કનેક્શનનું સંચાલન કરે છે. જો તમે તેને છોડી દો, તો કોઈ ઑડિયો ચાલશે નહીં અને સેશન કાર્ય કરશે નહીં.
</Warning>

---

## વિકલ્પો

`UseThunderPhoneOptions` મારફતે આ વિકલ્પો `useThunderPhone` ને આપો:

| વિકલ્પ | પ્રકાર | આવશ્યક | ડિફૉલ્ટ | વર્ણન |
|--------|------|----------|---------|-------------|
| `publishableKey` | `string` | હા | -- | પબ્લિશેબલ API કી (`pk_live_...`). એજન્ટ કીની વિજેટ રૂપરેખાંકનમાંથી આપમેળે નક્કી થાય છે. |
| `apiBase` | `string` | ના | `'https://api.thunderphone.com/v1'` | API બેઝ URL ઓવરરાઇડ. |
| `language` | `string` | ના | -- | પ્રતિ-સેશન ભાષા ઓવરરાઇડ -- `en`, `es`, અથવા `fr-FR` જેવા ભાષા કોડ અથવા લોકેલ. સેટ ન કરેલ હોય ત્યારે, એજન્ટની રૂપરેખાંકિત ભાષા લાગુ પડે છે. |
| `voice` | `string` | ના | -- | પ્રતિ-સેશન વૉઇસ ઓવરરાઇડ -- `maria` જેવા વૉઇસ નામ. સેટ ન કરેલ હોય ત્યારે, એજન્ટનો રૂપરેખાંકિત વૉઇસ લાગુ પડે છે. |
| `context` | `string` | ના | -- | એજન્ટને મોકલવામાં આવતો પ્રતિ-સેશન તથ્યાત્મક પેજ અથવા સાઇટ કોન્ટેક્સ્ટ. સર્વર-સાઇડ પર 12,000 અક્ષરો સુધી ટૂંકો કરવામાં આવે છે. |
| `onConnect` | `() => void` | ના | -- | વૉઇસ સેશન કનેક્ટ થાય ત્યારે કૉલ થાય છે. |
| `onDisconnect` | `() => void` | ના | -- | સેશન સમાપ્ત થાય ત્યારે કૉલ થાય છે. |
| `onError` | `(error) => void` | ના | -- | ભૂલો થાય ત્યારે કૉલ થાય છે. ભૂલમાં `error` (કોડ) અને `message` ફીલ્ડ હોય છે. |
| `ringtone` | `boolean \| string` | ના | `false` | કનેક્ટ કરતી વખતે રિંગટોન વગાડો. ડિફૉલ્ટ રિંગટોન માટે `true`, અથવા કસ્ટમ ઑડિયો માટે URL સ્ટ્રિંગ. |

<Note>
  હૂક હેડલેસ છે: તે `ThunderPhoneWidget` ના દેખાવ પ્રોપ્સ (`theme`, `primaryColor`, `title`, `position`, `className`) સ્વીકારતું **નથી**. તેમને પાસ કરવાથી TypeScript ભૂલ થાય છે -- પ્રસ્તુતિ સંપૂર્ણપણે તમે બનાવવાની છે.
</Note>

---

## રિટર્ન વેલ્યુ

હૂક `UseThunderPhoneReturn` ઑબ્જેક્ટ રિટર્ન કરે છે:

| પ્રોપર્ટી | પ્રકાર | વર્ણન |
|----------|------|-------------|
| `state` | `'idle' \| 'connecting' \| 'connected' \| 'disconnected' \| 'error'` | વર્તમાન કનેક્શન સ્થિતિ. |
| `connect` | `() => void` | વૉઇસ સેશન શરૂ કરો. |
| `disconnect` | `() => void` | વર્તમાન સેશન સમાપ્ત કરો. |
| `toggleMute` | `() => void` | માઇક્રોફોન મ્યૂટને ચાલુ/બંધ કરો. |
| `isMuted` | `boolean` | માઇક્રોફોન હાલમાં મ્યૂટ છે કે નહીં. |
| `error` | `string \| undefined` | સ્થિતિ `'error'` હોય ત્યારે એરર મેસેજ. |
| `agentName` | `string \| undefined` | કનેક્ટેડ એજન્ટનું ડિસ્પ્લે નામ. |
| `audioLevel` | `number` | **ડિપ્રિકેટેડ -- હંમેશા `0`.** બેકવર્ડ્સ કમ્પેટિબિલિટી માટે રાખવામાં આવેલો સ્થિર પ્લેસહોલ્ડર; તે ક્યારેય અપડેટ થતો નથી. તેના બદલે `audioLevelRef.current` વાંચો. |
| `audioLevelRef` | `React.RefObject<number>` | રિયલ-ટાઇમ ઑડિયો લેવલ (0--1) ધરાવતો મ્યૂટેબલ ref -- એજન્ટના અવાજ અને વિઝિટરના માઇક્રોફોનમાંથી જે વધુ ઊંચો હોય તે -- Reactના રેન્ડર સાયકલની બહાર, દરેક એનિમેશન ફ્રેમ પર અપડેટ થાય છે. સ્મૂથ, જૅન્ક-મુક્ત એનિમેશન માટે `requestAnimationFrame` લૂપમાં `audioLevelRef.current` વાંચો, અથવા React સ્ટેટમાં વેલ્યુ જરૂરી હોય ત્યારે તેને નિયમિત અંતરે સેમ્પલ કરો. |
| `audio` | `ReactNode` | ઑડિયો કનેક્શન હેન્ડલ કરતું અદૃશ્ય એલિમેન્ટ -- **રેન્ડર કરવું આવશ્યક છે**. |

---

## ઑડિયો-પ્રતિક્રિયાશીલ UI

`audioLevelRef` ref તમને React રિ-રેન્ડર ટ્રિગર કર્યા વિના ફ્રેમ-રેટ ઑડિયો લેવલ આપે છે, જેથી તે સરળ વેવફોર્મ વિઝ્યુઅલાઇઝેશન, પલ્સ થતા ઓર્બ્સ અથવા વાતચીત સાથે જોડાયેલા કોઈપણ એનિમેશન ચલાવવા માટે આદર્શ બને છે. લેવલ એજન્ટના અવાજ અથવા મુલાકાતીના માઇક્રોફોનમાંથી જે વધુ ઊંચો હોય તે દર્શાવે છે.

### વેવફોર્મ ઉદાહરણ

```tsx
import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function WaveformCall() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    const canvas = canvasRef.current
    if (!canvas) return
    const ctx = canvas.getContext('2d')!

    let animId: number
    const draw = () => {
      const level = phone.audioLevelRef.current ?? 0
      ctx.clearRect(0, 0, canvas.width, canvas.height)

      // Draw bars that react to audio level
      const barCount = 24
      const barWidth = canvas.width / barCount
      for (let i = 0; i < barCount; i++) {
        const distance = Math.abs(i - barCount / 2) / (barCount / 2)
        const height = level * canvas.height * (1 - distance * 0.6)
        const y = (canvas.height - height) / 2
        ctx.fillStyle = '#0ea5e9'
        ctx.fillRect(i * barWidth + 1, y, barWidth - 2, height)
      }

      animId = requestAnimationFrame(draw)
    }
    animId = requestAnimationFrame(draw)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <canvas ref={canvasRef} width={240} height={80} />
      )}
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

### પલ્સિંગ ઓર્બ ઉદાહરણ

```tsx
import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function PulsingOrb() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const orbRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    let animId: number
    const animate = () => {
      const level = phone.audioLevelRef.current ?? 0
      if (orbRef.current) {
        const scale = 1 + level * 0.5
        orbRef.current.style.transform = `scale(${scale})`
        orbRef.current.style.opacity = `${0.6 + level * 0.4}`
      }
      animId = requestAnimationFrame(animate)
    }
    animId = requestAnimationFrame(animate)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div style={{ textAlign: 'center' }}>
      <div
        ref={orbRef}
        style={{
          width: 80,
          height: 80,
          borderRadius: '50%',
          background: '#0ea5e9',
          margin: '20px auto',
          transition: 'transform 0.05s ease-out',
        }}
      />
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

### બોલવાનું સૂચક ઉદાહરણ

વોલ્યુમ સાથે બદલાતા React-રેન્ડર કરેલા UI માટે -- જેમ કે થ્રેશોલ્ડ-આધારિત "બોલી રહ્યા છે" બેજ -- `audioLevelRef.current` ને નિયમિત અંતરાલે સેમ્પલ કરો અને પરિણામને state માં સંગ્રહિત કરો:

```tsx
import { useEffect, useState } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function SpeakingBadge() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const [speaking, setSpeaking] = useState(false)

  useEffect(() => {
    if (phone.state !== 'connected') {
      setSpeaking(false)
      return
    }
    const interval = setInterval(() => {
      setSpeaking((phone.audioLevelRef.current ?? 0) > 0.1)
    }, 100)
    return () => clearInterval(interval)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <span>{speaking ? 'Speaking' : 'Listening'}</span>
      )}
      <button onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}>
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

<Warning>
  લેવલ હંમેશા `audioLevelRef.current` માંથી વાંચો. રિટર્ન ઑબ્જેક્ટ પરનો `audioLevel` નંબર **deprecated છે અને હંમેશા `0` રહે છે** -- તેના પર આધારિત કોઈપણ લોજિક શાંતિથી શૂન્ય વાંચશે.
</Warning>

---

## સ્થિતિ મશીન

`state` પ્રોપર્ટી આ જીવનચક્રને અનુસરે છે:

```
idle --> connecting --> connected --> disconnected --> idle (after 1.5s)
                  \
                   --> error (stays until connect() is called again)
```

| સ્થિતિ | વર્ણન |
|-------|-------------|
| `idle` | કોઈ સક્રિય સેશન નથી. `connect()` કૉલ કરવા માટે તૈયાર છે. |
| `connecting` | સેશન સ્થાપિત થઈ રહ્યું છે. આ સ્થિતિ દરમિયાન કોલ બટન નિષ્ક્રિય કરો. |
| `connected` | વૉઇસ સેશન સક્રિય છે. વપરાશકર્તા એજન્ટ સાથે વાત કરી રહ્યા છે. |
| `disconnected` | સેશન સ્વચ્છ રીતે સમાપ્ત થયું છે. 1.5 સેકન્ડ પછી આપમેળે પાછું `idle` પર જાય છે. |
| `error` | કંઈક ખોટું થયું છે. સંદેશ માટે `phone.error` તપાસો. સ્થિતિ પોતાની મેળે **સાફ થતી નથી** -- ફરીથી `connect()` કૉલ કરવાથી નવો પ્રયાસ શરૂ થાય છે અને ભૂલ રીસેટ થાય છે. |

---

## ઉદાહરણો

### મ્યૂટ નિયંત્રણ સાથે

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function CallWithMute() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div>
      {phone.state === 'connected' && (
        <div>
          <p>Talking to {phone.agentName ?? 'Agent'}</p>
          <button onClick={phone.toggleMute}>
            {phone.isMuted ? 'Unmute' : 'Mute'}
          </button>
          <button onClick={phone.disconnect}>End call</button>
        </div>
      )}

      {phone.state !== 'connected' && (
        <button
          onClick={phone.connect}
          disabled={phone.state === 'connecting'}
        >
          {phone.state === 'connecting' ? 'Connecting...' : 'Call support'}
        </button>
      )}

      {phone.state === 'error' && (
        <p style={{ color: 'red' }}>{phone.error}</p>
      )}

      {phone.audio}
    </div>
  )
}
```

### રિંગટોન સાથે

ફોન કૉલનું અનુકરણ કરવા માટે કનેક્ટ કરતી વખતે રિંગિંગ અવાજ વગાડો:

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function PhoneCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connecting'
          ? 'Ringing...'
          : phone.state === 'connected'
            ? 'Hang up'
            : 'Call'}
      </button>
      {phone.audio}
    </>
  )
}
```

રિંગટોન `connecting` સ્થિતિ દરમિયાન સતત વાગે છે અને એજન્ટ કનેક્ટ થાય ત્યારે ધીમે ધીમે બંધ થાય છે. બિલ્ટ-ઇન ડિફૉલ્ટ રિંગટોન માટે `true` પાસ કરો અથવા તમારી પોતાની ઑડિયો ફાઇલ વાપરવા માટે URL સ્ટ્રિંગ પાસ કરો.

### ઇવેન્ટ કૉલબૅક સાથે

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function TrackedCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    onConnect: () => {
      analytics.track('call_started')
    },
    onDisconnect: () => {
      analytics.track('call_ended')
    },
    onError: (error) => {
      analytics.track('call_error', { code: error.error, message: error.message })
    },
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'Hang up' : 'Talk to AI'}
      </button>
      {phone.audio}
    </>
  )
}
```

### સંપૂર્ણ કસ્ટમ UI

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function FullCustomUI() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div className="call-panel">
      <div className="call-status">
        {phone.state === 'idle' && <span>Ready</span>}
        {phone.state === 'connecting' && <span className="pulse">Connecting...</span>}
        {phone.state === 'connected' && (
          <span>On call with {phone.agentName}</span>
        )}
        {phone.state === 'error' && <span className="error">{phone.error}</span>}
      </div>

      <div className="call-controls">
        {phone.state === 'connected' ? (
          <>
            <button className="mute-btn" onClick={phone.toggleMute}>
              {phone.isMuted ? 'Unmute' : 'Mute'}
            </button>
            <button className="end-btn" onClick={phone.disconnect}>
              End
            </button>
          </>
        ) : (
          <button
            className="start-btn"
            onClick={phone.connect}
            disabled={phone.state === 'connecting'}
          >
            Start call
          </button>
        )}
      </div>

      {/* Required -- handles audio under the hood */}
      {phone.audio}
    </div>
  )
}
```

---

## સૂચનાઓ

<AccordionGroup>
  <Accordion title="હંમેશા phone.audio રેન્ડર કરો">
    `phone.audio` એલિમેન્ટ અદૃશ્ય છે, પરંતુ જરૂરી છે. તેને તમારા JSX માં ગમે ત્યાં મૂકો -- તે કોઈ દૃશ્યમાન DOM રેન્ડર કરતું નથી, પરંતુ અંદરથી WebRTC ઑડિયો કનેક્શનનું સંચાલન કરે છે.
  </Accordion>

  <Accordion title="કનેક્ટ કરતી વખતે બટન અક્ષમ કરો">
    `connecting` સ્થિતિ 1-3 સેકન્ડ સુધી રહી શકે છે. ડુપ્લિકેટ કનેક્શન પ્રયાસો અટકાવવા માટે આ સ્થિતિ દરમિયાન કૉલ બટન અક્ષમ કરો.
  </Accordion>

  <Accordion title="ભૂલની સ્થિતિને સુવ્યવસ્થિત રીતે હેન્ડલ કરો">
    જ્યારે સ્થિતિ `error` હોય, ત્યારે વપરાશકર્તાને `phone.error` દર્શાવો અને તમારું કૉલ બટન સક્ષમ રાખો. હૂક પોતાની મેળે `error` સ્થિતિ છોડતું નથી -- ફરીથી `connect()` કૉલ કરવાથી નવો પ્રયાસ શરૂ થાય છે અને અગાઉની ભૂલ દૂર થાય છે.
  </Accordion>

  <Accordion title="સાઇડ ઇફેક્ટ્સ માટે કૉલબૅક્સનો ઉપયોગ કરો">
    `onConnect`, `onDisconnect`, અને `onError` કૉલબૅક્સ સ્થિતિને પોલ કર્યા વિના એનાલિટિક્સ, લૉગિંગ અથવા અન્ય એપ્લિકેશન લૉજિક ટ્રિગર કરવા માટે આદર્શ છે.
  </Accordion>

  <Accordion title="audioLevelRef માંથી ઑડિયો લેવલ વાંચો">
    `audioLevelRef` એકમાત્ર લાઇવ ઑડિયો-લેવલ સ્રોત છે. વેવફોર્મ જેવી સરળ એનિમેશન માટે `requestAnimationFrame` ની અંદર `audioLevelRef.current` વાંચો (ref વાંચવાથી ફરીથી રેન્ડર થતું નથી), અથવા તેને નિયમિત અંતરાલે સેમ્પલ કરીને React-રેન્ડર કરેલા UI માટે પરિણામને state માં સંગ્રહો. `audioLevel` નંબર ડિપ્રિકેટેડ છે અને હંમેશા `0` હોય છે -- તેના પર લૉજિક બનાવશો નહીં.
  </Accordion>
</AccordionGroup>
