> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wave.sa/llms.txt
> Use this file to discover all available pages before exploring further.

# الاتّصال عبر الويب (WebRTC)

> أجرِ مكالمات صوتيّة من المتصفّح مباشرةً عبر Wave Calling SDK.

تتيح لك **Calling SDK** إجراء مكالمات صوتيّة حقيقيّة من المتصفّح عبر WebRTC — دون
إضافات. تُضمّن سكربتًا واحدًا، وتمنحه مفتاح API، ثمّ تستدعي `connect()` ثمّ
`initCall()`. يتولّى Wave تسجيل SIP والوسائط وبيانات الجلسة قصيرة العمر نيابةً عنك.

<Note>
  يستخدم الاتّصال عبر الويب نطاق `webrtc:write`. في **sandbox** تكون المكالمات مقيّدة
  بالأصل (origin) وبوجهة رقم تسجيلك؛ ويزيل مفتاح **production** (`sk_live_`) قيد
  الوجهة.
</Note>

## التثبيت

<CodeGroup>
  ```bash npm theme={null}
  npm install @wave-sa/calling-sdk
  ```

  ```html CDN theme={null}
  <script src="https://unpkg.com/@wave-sa/calling-sdk"></script>
  <!-- يوفّر المتغيّر العامّ `Wave.SDK` -->
  ```
</CodeGroup>

## قبل البدء

1. **اسمح بأصلك.** في لوحة تحكّم Wave، أضِف الأصل الذي يعمل عليه تطبيقك (مثل
   `https://app.example.com`) إلى **الأصول المسموح بها** لمشروعك. تجلب الـ SDK جلستها
   من `/v1/webrtc/config` التي ترفض أيّ أصل ليس على القائمة.
2. **استخدم مفتاح `webrtc:write`.** يُرسَل المفتاح من المتصفّح، لذا فهو مقيّد بالأصل
   بحكم التصميم.

<Warning>
  المفتاح المُضمَّن في المتصفّح مرئيّ لأيّ شخص يحمّل صفحتك. يقيّده Wave بالأصل (وبالوجهة
  في sandbox) لاحتواء الأثر — لكن في production عامِل المفتاح المُضمَّن كأنّه عامّ
  واقصره على `webrtc:write` فقط.
</Warning>

## بداية سريعة

```javascript theme={null}
import { WaveSDK } from "@wave-sa/calling-sdk";

const sdk = new WaveSDK(
  { apiKey: "sk_live_xxxxxxxxxxxx", apiUrl: "https://api.wave.sa/v1" },
  {
    onConnected: () => console.log("مُسجَّل — جاهز للاتّصال"),
    onCallProgress: () => console.log("يرنّ…"),
    onCallConnected: () => console.log("في مكالمة"),
    onCallEnded: () => console.log("انتهت المكالمة"),
    onFailed: (err) => console.error(err.code, err.message),
  },
);

await sdk.connect();              // جلب الجلسة، فتح WebSocket، تسجيل SIP
await sdk.initCall("+966500000000"); // اتّصال
// … لاحقًا
await sdk.endCall();
sdk.disconnect();
```

## الإعدادات

`new WaveSDK(config, events)`

| الخيار        | النوع            | ملاحظات                                            |
| ------------- | ---------------- | -------------------------------------------------- |
| `apiKey`      | نصّ              | **مطلوب.** مفتاحك `sk_sandbox_` / `sk_live_`.      |
| `destination` | نصّ              | رقم افتراضيّ اختياريّ لـ `initCall()`.             |
| `locale`      | `"en"` \| `"ar"` | لغة الواجهة. الافتراضيّ `"en"`.                    |
| `apiUrl`      | نصّ              | أساس الـ API. الافتراضيّ `https://api.wave.sa/v1`. |

## الدوالّ

| الدالّة                           | ما تفعله                                                                                   |
| --------------------------------- | ------------------------------------------------------------------------------------------ |
| `connect()`                       | تجلب الجلسة، تفتح قناة الإشارة، وتسجّل. تُطلق `onConnected` عند الجاهزيّة.                 |
| `initCall(destination?)`          | تحصل على الميكروفون وتتّصل. تُعيد `{ callSid, status: "initiated" }`.                      |
| `endCall()`                       | تنهي المكالمة النشطة.                                                                      |
| `muteCall()` / `unmuteCall()`     | كتم الميكروفون أو استعادته.                                                                |
| `holdCall()` / `resumeCall()`     | تعليق المكالمة أو استئنافها.                                                               |
| `sendDTMF(tones, transportType?)` | إرسال نغمات لوحة المفاتيح (`0–9 * # A–D`). الافتراضيّ RFC 2833؛ مرّر `"INFO"` لـ SIP INFO. |
| `disconnect()`                    | تفكيك كلّ شيء وتحرير الميكروفون.                                                           |
| `isMuted`                         | حالة الكتم الحاليّة.                                                                       |

## الأحداث

مرّر المُعالِجات في الوسيط الثاني للـ constructor.

| الحدث                        | يُطلَق عند                                                                                       |
| ---------------------------- | ------------------------------------------------------------------------------------------------ |
| `onConnecting()`             | فتح قناة الإشارة.                                                                                |
| `onConnected()`              | التسجيل — جاهز للاتّصال.                                                                         |
| `onCallProgress()`           | رنين الطرف الآخر.                                                                                |
| `onCallConnected()`          | الردّ على المكالمة وتدفّق الوسائط.                                                               |
| `onCallEnded()`              | إنهاؤك المكالمة عبر `endCall()`.                                                                 |
| `onCallDisconnected(reason)` | انقطاع المكالمة — `reason` هو `NETWORK_ERROR` أو `TIMEOUT` أو `SERVER_ERROR` أو `REMOTE_HANGUP`. |
| `onMuteStateChange(isMuted)` | بعد `muteCall()` / `unmuteCall()`.                                                               |
| `onHold()` / `onResumed()`   | تعليق المكالمة / استئنافها.                                                                      |
| `onFailed(error)`            | فشل الإعداد أو التسجيل — راجِع رموز الأخطاء أدناه.                                               |
| `onTokenWillExpire()`        | قبل \~60 ثانية من انتهاء بيانات الجلسة (للعلم).                                                  |
| `onSessionRefreshed()`       | تدوير بيانات الجلسة بنجاح.                                                                       |
| `onSessionEnded(reason)`     | انتهاء الجلسة عند Wave (`auth_failure` أو `revoked`).                                            |

<Note>
  لا تتعامل أنت مع كلمة مرور SIP أو رمز الجلسة. تجلبها الـ SDK، وتُبقي المكالمة حيّة،
  و**تدوّرها تلقائيًّا** قبل انتهائها بنحو دقيقة.
</Note>

## رموز الأخطاء

يمنحك `onFailed(error)` قيمة `error.code`:

| الرمز                                    | المعنى                                        |
| ---------------------------------------- | --------------------------------------------- |
| `INVALID_API_KEY_FORMAT`                 | `apiKey` ليس مفتاح Wave معروفًا.              |
| `UNSUPPORTED_BROWSER`                    | لا دعم لـ WebRTC.                             |
| `MICROPHONE_UNAVAILABLE`                 | رُفض إذن الميكروفون أو لا جهاز إدخال.         |
| `CONFIG_FAILED`                          | تعذّر جلب الجلسة — غالبًا الأصل غير مسموح به. |
| `AUTH_FAILURE`                           | رُفض المفتاح.                                 |
| `REGISTRATION_FAILED`                    | فشل تسجيل SIP.                                |
| `TURN_UNAVAILABLE`                       | لا مُرحِّل وسائط على شبكة مقيّدة.             |
| `CALL_ALREADY_ACTIVE` / `NO_ACTIVE_CALL` | سوء استخدام لحالة المكالمة.                   |
| `NOT_CONNECTED`                          | استدعاء `initCall()` قبل اكتمال `connect()`.  |
| `CALL_FAILED`                            | تعذّر إعداد المكالمة.                         |

## الخطوات التالية

<CardGroup cols={2}>
  <Card title="كيف يعمل الصوت" icon="phone-volume" href="/ar/voice/overview">
    أين تقع مكالمة المتصفّح في دورة حياة المكالمة.
  </Card>

  <Card title="المكالمات والتسجيلات" icon="clock-rotate-left" href="/ar/voice/calls-and-recordings">
    اقرأ السجلّ واجلب تسجيلًا.
  </Card>
</CardGroup>
