> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Azure Communication Services

## अवलोकन

इस तरीके से आपके एजेंट को एक **फ़ोन नंबर** मिलता है। कॉलर इस पर डायल करता है, [Azure Communication Services](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/call-automation) (ACS) **दो-तरफ़ा मीडिया स्ट्रीमिंग** के साथ कॉल का जवाब देता है, और एक छोटा ब्रिज मानक [एजेंट WebSocket प्रोटोकॉल](/docs/hi/eleven-agents/libraries/web-sockets) का इस्तेमाल करके ACS और ElevenLabs एजेंट के बीच PCM ऑडियो रिले करता है। यह कॉन्टैक्ट सेंटर / IVR पैटर्न है — [SIP ट्रंकिंग](/docs/hi/eleven-agents/phone-numbers/sip-trunking) डिप्लॉयमेंट जैसा ही सेटअप, जिसमें ACS कैरियर है।

यह Teams से भी दो तरीकों से जुड़ता है: Calling Plan वाला Teams यूज़र सीधे ACS नंबर डायल कर सकता है, या आप नंबर के आगे **Teams Phone Extensibility** लगा सकते हैं, ताकि Teams रिसोर्स अकाउंट पर आने वाली कॉल ACS पर रूट हों।

> **Note**
>
> ACS केवल कुछ [सीमित देशों](https://learn.microsoft.com/en-us/azure/communication-services/concepts/numbers/sub-eligibility-number-capability) में PSTN नंबर प्रोविज़न करता है।
> अगर आपके क्षेत्र में नंबर उपलब्ध नहीं है, तो [SIP ट्रंकिंग](/docs/hi/eleven-agents/phone-numbers/sip-trunking) वाले SIP प्रोवाइडर का इस्तेमाल करें, या [Graph calling bot](/docs/hi/eleven-agents/phone-numbers/microsoft-teams/graph-media-bot) इस्तेमाल करें।

## यह कैसे काम करता है

![एक कॉलर ACS नंबर डायल करता है; ACS, Event Grid के ज़रिए ब्रिज को IncomingCall भेजता है, जो दो-तरफ़ा PCM 16k मीडिया स्ट्रीमिंग के साथ जवाब देता है और उसे WebSocket पर ElevenLabs एजेंट तक रिले करता है](/docs/_fern-files/elevenlabs.docs.buildwithfern.com/e77a27148e217fc7dc06c25007c1c141913fc831cbfe8a2f57405137646271af/assets/images/conversational-ai/teams-acs-architecture.svg)

दोनों लेग पर ऑडियो **PCM 16 kHz मोनो** होता है (एजेंट का इनपुट/आउटपुट फ़ॉर्मैट `pcm_16000` है), इसलिए यह बिना री-सैंपलिंग के base64 के रूप में पास होता है।

ब्रिज ये रूट एक्सपोज़ करता है:

| रूट                      | उद्देश्य                                                                                     |
| ------------------------ | -------------------------------------------------------------------------------------------- |
| `POST /api/incomingCall` | Event Grid वेबहुक: सब्सक्रिप्शन सत्यापित करता है, फिर मीडिया स्ट्रीमिंग के साथ `answer_call` |
| `POST /api/callbacks`    | Call Automation लाइफ़साइकल इवेंट (`CallConnected`, `CallDisconnected`, `AddParticipant*`)    |
| `GET\|WS /ws`            | ACS मीडिया-स्ट्रीमिंग सॉकेट ↔ ElevenLabs                                                     |
| `POST /api/outboundCall` | वैकल्पिक: आउटबाउंड कॉल करें, जो जवाब देने वाले को एजेंट से जोड़ती है                         |

## ज़रूरतें

1. एक **पेड** Azure सब्सक्रिप्शन (MCA / EA / Pay-As-You-Go) — मुफ़्त/ट्रायल/स्पॉन्सरशिप सब्सक्रिप्शन नंबर नहीं खरीद सकते।
2. एक [Azure Communication Services रिसोर्स](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/create-communication-resource)।
3. सार्वजनिक WebSocket के साथ ब्रिज के लिए एक HTTPS होस्ट (Azure Container Apps, App Service, या VM)।
4. दोनों लेग पर **PCM 16000 Hz** पर सेट एक [ElevenLabs एजेंट](/docs/hi/eleven-agents/quickstart): **Voice** टैब में TTS आउटपुट फ़ॉर्मैट और **Advanced** टैब में यूज़र इनपुट ऑडियो फ़ॉर्मैट।

## अनुमतियां और रोल

| स्कोप              | रोल / अनुमति                                     | कारण                                                                |
| ------------------ | ------------------------------------------------ | ------------------------------------------------------------------- |
| Azure RBAC         | रिसोर्स ग्रुप पर **Contributor**                 | ACS रिसोर्स, Container App और Event Grid सब्सक्रिप्शन बनाना         |
| Azure सब्सक्रिप्शन | सब्सक्रिप्शन पर **Owner या Contributor**         | फ़ोन नंबर खरीदना (वरना खरीदने का विकल्प बंद रहता है)                |
| बिलिंग             | **MCA / EA / Pay-As-You-Go** सब्सक्रिप्शन प्रकार | मुफ़्त, ट्रायल, स्पॉन्सरशिप और Dev सब्सक्रिप्शन नंबर नहीं खरीद सकते |

> **Note**
>
> **Contributor** के तहत (Owner नहीं), `az containerapp up` मैनेज्ड-आइडेंटिटी ACR pull
> रोल असाइनमेंट नहीं बना सकता। इसके बजाय registry admin यूज़र सक्षम करें और उसे अटैच करें — चरण 2 में चेतावनी देखें।

## चरण 1 — ACS रिसोर्स और नंबर प्रोविज़न करें

```bash
RG=my-rg
# Register providers (once)
az provider register -n Microsoft.Communication --wait
az provider register -n Microsoft.EventGrid --wait

# Create the ACS resource
az communication create --name my-acs --resource-group $RG \
  --location global --data-location unitedstates
```

रिसोर्स में नंबर खरीदें (Portal → आपका ACS रिसोर्स → **Phone numbers → Get**, या [phone-numbers SDK](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number))। कॉल का **जवाब देने** वाले एजेंट के लिए **inbound calling** वाला नंबर काफ़ी है; अगर आप `/api/outboundCall` भी चाहते हैं, तो **outbound** क्षमता जोड़ें।

![ACS रिसोर्स का Phone numbers पेज, जिसमें सक्रिय नंबर उनकी कॉलिंग क्षमताओं के साथ सूचीबद्ध हैं](/docs/_fern-img/9d14034ee9f81e2ebcf64e30371f914ef6f87a8da30ac250e702662f2e5e1cc1.webp)

CLI से सत्यापित करने के लिए (`az extension add --name communication` ज़रूरी है), और ब्रिज द्वारा `ACS_CONNECTION_STRING` के रूप में इस्तेमाल की जाने वाली कनेक्शन स्ट्रिंग पाने के लिए:

```bash
CONN=$(az communication list-key -n my-acs -g $RG --query primaryConnectionString -o tsv)
az communication phonenumber list --connection-string "$CONN" --query "[].phoneNumber"
```

## चरण 2 — ब्रिज डिप्लॉय करें

ब्रिज `azure-communication-callautomation` का उपयोग करने वाला एक छोटा Flask + `flask-sock` ऐप है। इनबाउंड फ़्लो का मुख्य भाग:

**`bridge.py (excerpt)`**

```python title="bridge.py (excerpt)"
from azure.communication.callautomation import (
    CallAutomationClient, MediaStreamingOptions, StreamingTransportType,
    MediaStreamingContentType, MediaStreamingAudioChannelType, AudioFormat,
)

@app.route("/api/incomingCall", methods=["POST"])
def incoming_call():
    for event in request.get_json():
        # Event Grid subscription validation handshake
        if event.get("eventType") == "Microsoft.EventGrid.SubscriptionValidationEvent":
            return jsonify({"validationResponse": event["data"]["validationCode"]})

        if event.get("eventType") == "Microsoft.Communication.IncomingCall":
            client = CallAutomationClient.from_connection_string(ACS_CONNECTION_STRING)
            client.answer_call(
                incoming_call_context=event["data"]["incomingCallContext"],
                callback_url=f"https://{HOST}/api/callbacks",
                media_streaming=MediaStreamingOptions(
                    transport_url=f"wss://{HOST}/ws",
                    transport_type=StreamingTransportType.WEBSOCKET,
                    content_type=MediaStreamingContentType.AUDIO,
                    audio_channel_type=MediaStreamingAudioChannelType.MIXED,
                    start_media_streaming=True,
                    enable_bidirectional=True,
                    audio_format=AudioFormat.PCM16_K_MONO,
                ),
            )
    return jsonify({"status": "ok"})
```

`/ws` सॉकेट पर PCM16 को दोनों दिशाओं में रिले करें: ACS `AudioData` फ़्रेम को ElevenLabs में `{"user_audio_chunk": "<base64>"}` के रूप में फ़ॉरवर्ड करें, और एजेंट का ऑडियो वापस `{"Kind":"AudioData","AudioData":{"Data":"<base64>"},"StopAudio":null}` के रूप में भेजें। ACS का पहला फ़्रेम `AudioMetadata` होता है (नेगोशिएट किया गया फ़ॉर्मैट) — इसे लॉग करें और अनदेखा करें। ElevenLabs वाला भाग मानक [एजेंट WebSocket प्रोटोकॉल](/docs/hi/eleven-agents/libraries/web-sockets) है।

> **Note**
>
> ACS हर दिशा के लिए अलग JSON केसिंग इस्तेमाल करता है: इसके **भेजे** गए इनबाउंड फ़्रेम camelCase (`kind`,
> `audioData.data`) में होते हैं, जबकि इसके **अपेक्षित** आउटबाउंड फ़्रेम PascalCase (`Kind`, `AudioData.Data`,
> `StopAudio`) में होते हैं। दोनों केस अलग रखें — नीचे दिया रिले इसे ही दर्शाता है।

**`bridge.py — media relay`**

```python title="bridge.py — media relay"
import asyncio, json, os, queue, threading, websockets
from flask_sock import Sock

sock = Sock(app)
AGENT_ID = os.environ["ELEVENLABS_AGENT_ID"]
# US default; data residency: wss://api.eu.residency.elevenlabs.io, .in., or .sg.
EL_ORIGIN = os.environ.get("ELEVENLABS_ORIGIN", "wss://api.elevenlabs.io")
EL_WS = f"{EL_ORIGIN}/v1/convai/conversation?agent_id={AGENT_ID}"

@sock.route("/ws")
def media_stream(ws):
    loop = asyncio.new_event_loop()
    el = {"ws": None}
    to_acs = queue.Queue()  # outbound frames; only this handler thread touches `ws`

    async def el_session():
        async with websockets.connect(EL_WS) as elws:
            el["ws"] = elws
            await elws.send(json.dumps({"type": "conversation_initiation_client_data"}))
            async for msg in elws:
                data = json.loads(msg)
                kind = data.get("type")
                if kind == "audio":  # agent audio -> caller
                    b64 = data["audio_event"]["audio_base_64"]
                    to_acs.put({"Kind": "AudioData", "AudioData": {"Data": b64}, "StopAudio": None})
                elif kind == "ping":
                    await elws.send(json.dumps({"type": "pong", "event_id": data["ping_event"]["event_id"]}))
                elif kind == "interruption":  # barge-in
                    to_acs.put({"Kind": "StopAudio", "AudioData": None, "StopAudio": {}})

    threading.Thread(target=lambda: loop.run_until_complete(el_session()), daemon=True).start()

    # Keep all ACS-socket I/O on this one thread: receive with a short timeout,
    # then drain any audio the ElevenLabs thread queued. Sending from the other
    # thread would race flask-sock and corrupt the stream.
    try:
        while True:
            raw = ws.receive(timeout=0.02)  # None when no frame arrived this tick
            if raw:
                evt = json.loads(raw)
                if evt.get("kind") == "AudioData" and el["ws"]:  # caller audio -> agent
                    asyncio.run_coroutine_threadsafe(
                        el["ws"].send(json.dumps({"user_audio_chunk": evt["audioData"]["data"]})), loop)
            while not to_acs.empty():
                ws.send(json.dumps(to_acs.get_nowait()))
    except Exception:
        pass  # ACS socket closed
```

> **Note**
>
> यह रिले जानबूझकर न्यूनतम रखा गया है। प्रोडक्शन के लिए लॉगिंग, रिकनेक्शन और व्यवस्थित
> टियरडाउन जोड़ें। पूरा मैसेज रेफ़रेंस [WebSocket दस्तावेज़](/docs/hi/eleven-agents/libraries/web-sockets) में है।

> **Note**
>
> `EL_WS` एक **पब्लिक** एजेंट से कनेक्ट होता है। प्राइवेट एजेंट के लिए, ब्रिज से सर्वर-साइड एक अल्पकालिक
> साइन किया हुआ URL मांगें — आपकी API key के साथ `GET /v1/convai/conversation/get-signed-url?agent_id=...`
> — और इसके बजाय लौटे हुए URL से कनेक्ट करें। [डेटा रेज़िडेंसी](/docs/hi/overview/administration/data-residency) के लिए `ELEVENLABS_ORIGIN` को अपने
> रेज़िडेंसी होस्ट (`wss://api.eu.residency.elevenlabs.io`, `.in.`, या `.sg.`) पर सेट करें — साइन किए गए URL अनुरोध
> मेल खाते `https://` होस्ट का उपयोग करते हैं।

Azure Container Apps पर डिप्लॉय करें और सार्वजनिक FQDN कैप्चर करें:

```bash
az containerapp up --name acs-el-bridge --resource-group $RG \
  --source . --ingress external --target-port 8080 \
  --env-vars ELEVENLABS_AGENT_ID=$AGENT_ID \
    ELEVENLABS_ORIGIN=wss://api.elevenlabs.io

FQDN=$(az containerapp show -n acs-el-bridge -g $RG \
  --query properties.configuration.ingress.fqdn -o tsv)
```

फिर ऐप पर `BRIDGE_PUBLIC_HOST=$FQDN` और ACS कनेक्शन स्ट्रिंग (सीक्रेट के रूप में) सेट करें।

> **Warning**
>
> **Contributor** के तहत (Owner नहीं), `az containerapp up` मैनेज्ड-आइडेंटिटी ACR
> pull रोल नहीं बना सकता। registry admin यूज़र सक्षम करें (`az acr update --admin-enabled true`) और इसे
> `az containerapp registry set` के साथ अटैच करें, फिर `az containerapp update --image ...` चलाएं।

## चरण 3 — IncomingCall को ब्रिज पर रूट करें

ACS रिसोर्स पर एक Event Grid सब्सक्रिप्शन बनाएं, जो `IncomingCall` को ब्रिज पर पोस्ट करे। ब्रिज का वैलिडेशन हैंडशेक (ऊपर) सब्सक्रिप्शन अपने-आप पूरा कर देता है।

```bash
ACS_ID=$(az communication show -n my-acs -g $RG --query id -o tsv)
az eventgrid event-subscription create \
  --name acs-incomingcall \
  --source-resource-id "$ACS_ID" \
  --endpoint "https://$FQDN/api/incomingCall" \
  --endpoint-type webhook \
  --included-event-types Microsoft.Communication.IncomingCall

# Verify — should print "Succeeded"
az eventgrid event-subscription show --name acs-incomingcall \
  --source-resource-id "$ACS_ID" --query provisioningState -o tsv
```

सब्सक्रिप्शन ACS रिसोर्स के **Events** पेज में दिखाई देता है:

![ACS रिसोर्स का Events पेज, जिसमें Microsoft.Communication.IncomingCall से फ़िल्टर किया गया acs-incomingcall वेबहुक सब्सक्रिप्शन सूचीबद्ध है](/docs/_fern-img/f310aed9637e06b81906ca188350e3e721aaa5f4de69af2b3b6e7d157817a1ea.webp)

नंबर डायल करें — एजेंट जवाब देगा।

## इसे Teams से कनेक्ट करना

* **सीधा डायल:** Teams Phone + Calling Plan वाला Teams यूज़र ACS नंबर को किसी भी बाहरी नंबर की तरह डायल कर सकता है।
* **Teams रिसोर्स अकाउंट (TPE):** [Teams Phone Extensibility](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/tpe/teams-phone-extensibility-quickstart) के साथ Teams रिसोर्स अकाउंट को ACS रिसोर्स से बाइंड करें, ताकि रिसोर्स अकाउंट पर कॉल वही `IncomingCall` → ब्रिज फ़्लो ट्रिगर करें।

## कॉल का अंत

जब एजेंट बातचीत समाप्त करता है (जैसे अपने **End Call** टूल से), ElevenLabs WebSocket बंद कर देता है। ACS लेग को हैंग अप करें, ताकि कॉलर डेड लाइन पर न रहे:

```python
CallAutomationClient.from_connection_string(ACS_CONNECTION_STRING) \
    .get_call_connection(call_connection_id).hang_up(is_for_everyone=True)
```

## किसी व्यक्ति को वॉर्म ट्रांसफ़र

ElevenLabs के नेटिव ट्रांसफ़र टूल केवल तब लागू होते हैं जब टेलीफ़ोनी ElevenLabs के पास हो। इसलिए यहां एजेंट एक **कस्टम क्लाइंट टूल** (जैसे `transfer_to_human`) ट्रिगर करता है, जिसे आपका ब्रिज ब्लाइंड ट्रांसफ़र के बजाय `add_participant` के साथ लाइव कॉल में व्यक्ति को **जोड़कर** (वॉर्म) संभालता है:

```python
conn = client.get_call_connection(call_connection_id)
conn.add_participant(
    PhoneNumberIdentifier(human_number),
    source_caller_id_number=PhoneNumberIdentifier(your_outbound_number),
    invitation_timeout=30,
)
# then mute the bot and skip the end-of-call hangup so the human's leg survives
```

ACS `/api/callbacks` पर `AddParticipantSucceeded` / `AddParticipantFailed` कॉलबैक भेजता है। एजेंट को `client_tool_result` लौटाएं, ताकि वह अपनी हैंडऑफ़ लाइन बोल सके। एजेंट-साइड कॉन्फ़िगरेशन के लिए [सिस्टम टूल्स](/docs/hi/eleven-agents/customization/tools/system-tools/transfer-to-number) देखें।

> **Tip**
>
> टूल ट्रिगर होते ही ट्रांसफ़र गार्ड सेट करें (`add_participant` कॉल करने से पहले), वरना तेज़ EL
> WebSocket क्लोज़ हैंगअप के साथ रेस कर सकता है और व्यक्ति के जुड़ने से पहले कॉल ड्रॉप हो सकती है।

## समस्या निवारण

#### कोई IncomingCall ब्रिज तक नहीं पहुंच रहा

पुष्टि करें कि Event Grid सब्सक्रिप्शन प्रोविज़न हुआ है (`provisioningState: Succeeded`) और
ब्रिज के `/api/incomingCall` ने वैलिडेशन इको लौटाया है। पुष्टि करें कि नंबर में इनबाउंड
कॉलिंग है और वह उसी ACS रिसोर्स में है जिस पर सब्सक्रिप्शन है। सब्सक्रिप्शन के
**Filters** टैब में इवेंट प्रकारों में **Incoming Call** शामिल होना चाहिए:

![इवेंट सब्सक्रिप्शन का Filters टैब, जिसमें इवेंट प्रकार Incoming Call पर फ़िल्टर किया गया है](/docs/_fern-img/c7026e86d96551d713e4fd7d5753062f643fcd6a67b455866bb8f1bbb6b57eb1.webp)

#### अंतरराष्ट्रीय नंबर के लिए \`CreateCallFailed\` / \`AddParticipantFailed\`

कुछ गंतव्यों (जैसे भारत) के लिए ACS आउटबाउंड प्रतिबंधित या रुक-रुक कर काम करता है। समर्थित
गंतव्य इस्तेमाल करें या व्यक्ति के लेग के आगे SIP/Operator नंबर लगाएं। ब्रिज लॉजिक प्रभावित नहीं होता —
यह आउटबाउंड लेग पर कैरियर-लेवल विफलता है।

#### ऑडियो विकृत है या गलत गति से चल रहा है

दोनों पक्ष PCM 16 kHz मोनो होने चाहिए। एजेंट के इनपुट/आउटपुट फ़ॉर्मैट को `pcm_16000` पर सेट करें; ब्रिज
`conversation_initiation_metadata` से नेगोशिएट किया फ़ॉर्मैट लॉग करता है।

#### नंबर नहीं खरीद पा रहे / मेरे देश में नंबर उपलब्ध नहीं है

नंबर खरीदने के लिए पेड सब्सक्रिप्शन प्रकार (MCA/EA/PAYG) चाहिए। अगर ACS आपके देश में नंबर नहीं देता,
तो इसके बजाय [SIP](/docs/hi/eleven-agents/phone-numbers/sip-trunking) प्रोवाइडर इस्तेमाल करें।

## उपयोगी लिंक

* [ACS Call Automation अवलोकन](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/call-automation)
* [ACS ऑडियो स्ट्रीमिंग](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/audio-streaming-concept)
* [कॉल नियंत्रण कार्रवाइयां (ट्रांसफ़र / प्रतिभागी जोड़ें)](https://learn.microsoft.com/en-us/azure/communication-services/how-tos/call-automation/actions-for-call-control)
* [Teams Phone Extensibility](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/tpe/teams-phone-extensibility-quickstart)
* [एजेंट WebSocket प्रोटोकॉल](/docs/hi/eleven-agents/libraries/web-sockets)
* [ElevenLabs SIP ट्रंकिंग](/docs/hi/eleven-agents/phone-numbers/sip-trunking)