40 KiB
سناریوی اجرایی Softphone سازمانی حسابیکس — رله رسانه از طریق Connector
کد افزونه: asterisk_issabel_connector
نام قابلیت: Softphone داخلبرنامهای (حالت رله + حالت مستقیم اختیاری)
نسخه سند: 1.2.0
تاریخ: ۱۴۰۵/۰۵/۱۵ (2026-08-06)
وضعیت: پیادهسازی فعال — R1 تقریباً کامل (باقی: UAT Issabel واقعی)
وابستگی پایه: سند TELEPHONY_ASTERISK_ISSABEL_PLUGIN_EXECUTION_PLAN.md (فازهای ۰–۴ CTI موجود)
پیشرفت پیادهسازی (بهروز ۱۴۰۵/۰۵/۱۵ — جلسه ۲)
| فاز | وضعیت | توضیح |
|---|---|---|
| R0 | ✅ جزئی / در lab | قرارداد پروتکل، AudioSocket، تونل WSS، پروفایل pcm_ws_v1 |
| R1 | ✅ کاملشده در کد (بهجز UAT فیزیکی) | میکروفون/پخش واقعی، UI endpoint_mode، Phone Bar، Click-to-Call→Relay |
| R2–R5 | ⏳ نشده | طبق برنامه |
تصمیم اجرایی R0 (انحراف کنترلشده از aiortc روز اول):
مسیر رسانه فاز ۱ = PCM16LE 8kHz روی WSS (pcm_ws_v1) بین کلاینت ↔ Media Hub ↔ Connector ↔ AudioSocket. این بدون لایسنس، بدون expose کردن PJSIP، و سازگار با Asterisk است. ارتقا به WebRTC/aiortc/Opus در R3 بهعنوان transport جایگزین پشت همان سشن/تونل انجام میشود.
۰. خلاصه اجرایی
امروز افزونهٔ تلفن حسابیکس یک CTI کامل است (Screen Pop، Click-to-Call، تاریخچه، ضبط، داشبورد، کنترل تماس) ولی رسانهٔ صوت داخل اپ وجود ندارد؛ اپراتور هنوز به Softphone/تلفن SIP خارجی وابسته است.
بسیاری از سازمانها دسترسی بیرونی به PBX را میبندند (هیچ WSS/SIP/RTP ورودی از اینترنت به Issabel). بنابراین رجیستر مستقیم PJSIP/WebRTC از بیرون برای آنها عملاً غیرممکن یا ناامن است.
تصمیم قفلشده این سند:
| موضوع | تصمیم |
|---|---|
| حالت پیشفرض Softphone | Media Relay از طریق Connector — بدون باز کردن پورت PBX به اینترنت |
| حالت اختیاری | Direct WebRTC/PJSIP برای سازمانهایی که VPN/LAN یا WSS عمومی دارند |
| مسیر صدا در Relay | کلاینت ↔ لبه رسانه حسابیکس ↔ تونل خروجی Connector ↔ Asterisk محلی |
| مسیر کنترل/CRM | همان CTI فعلی (AMI + API + WS) |
| ابزارها | فقط OSS بدون لایسنس تجاری |
| Desk Phone / Click-to-Call | حفظ میشود (حالت سوم) |
هدف: اپراتور روی وب / اندروید / ویندوز از داخل حسابیکس تماس بگیرد و جواب دهد، بدون Zoiper/MicroSIP، حتی وقتی PBX کاملاً پشت فایروال است.
۱. مسئله، هدف و محدودیتها
۱.۱ مسئله
- سازمانها نمیخواهند پورت SIP/WSS/RTP سانترال را به اینترنت باز کنند.
- اپراتورهای دورکار / شعب / وباپ نمیتوانند مستقیم به PBX برسند.
- الگوی فعلی Connector (فقط خروجی HTTPS) برای CTI عالی است، ولی برای صوت هنوز کانالی نیست.
- وعدهٔ «نمونه اولیه» قابل قبول نیست؛ باید کیفیت و پایداری مرکز تماس سازمانی باشد.
۱.۲ هدف محصولی
- Softphone حرفهای داخل حسابیکس
- کاهش نرمافزار جانبی
- کار روی Web + Android + Windows
- یکپارچگی کامل با Pop / تاریخچه / گزارش / ضبط / Live Dashboard
- دو مسیر اتصال رسانه (Relay پیشفرض، Direct اختیاری)
- بدون وابستگی به SDK پولی یا لایسنس تجاری VoIP
۱.۳ خارج از محدوده (این نسخه)
- جایگزینی Issabel/IVR builder
- تماس ویدیویی سازمانی (فاز بعدی اختیاری)
- Whisper/Barge سرپرست (بکلاگ پس از هسته)
- ذخیرهٔ ابری اجباری همهٔ ضبطها (همان سیاست فعلی لینک/آپلود اختیاری)
- پشتیبانی PBX غیر Asterisk-family
۱.۴ فرضیات عملیاتی ایران
- PBX معمولاً فقط خروجی HTTPS دارد.
- کیفیت لینک شعب متغیر است → نیاز به jitter buffer، reconnect، و مانیتور کیفیت.
- گواهی TLS معتبر برای لبه حسابیکس در دسترس است؛ برای Direct روی PBX ممکن است گواهی داخلی باشد.
- بسیاری مشتریان Issabel 4/5 با Asterisk 13–18 دارند → باید مسیر صوت با قابلیتهای رایج Asterisk سازگار باشد و fallback داشته باشد.
۲. اصول معماری (قفلشده)
- صدا از API کسبوکار حسابیکس عبور داده نمیشود بهصورت RTP خام روی REST؛ از سرویس لبه رسانه و تونل دوطرفه استفاده میشود.
- کنترل تماس و CRM از مسیر CTI فعلی میماند؛ Softphone فقط endpoint رسانه و UX اپراتور است.
- Connector هرگز پورت ورودی اینترنت لازم ندارد (در حالت Relay).
- Asterisk روی localhost با Connector حرف میزند (AudioSocket / ARI ExternalMedia / Local SIP).
- Credential دائم SIP در کلاینت ذخیره نمیشود (مگر حالت Direct با سیاست صریح ادمین).
- یک Engine Abstraction در Flutter هر دو حالت Relay و Direct را پشت یک API واحد UI میگذارد.
- چندمستأجری سخت: هر سشن رسانه به
business_id + pbx_id + user_id + extensionقفل است. - فقط OSS رایگان در مسیر بحرانی صوت/سیگنالینگ.
۳. دو حالت رسانه + یک حالت Desk
۳.۱ جدول حالتها
| کد حالت | نام | چه زمانی | نیاز شبکه به PBX از کلاینت | نیاز تنظیم روی PBX |
|---|---|---|---|---|
relay |
رله از طریق افزونه | پیشفرض سازمانی | فقط به حسابیکس (HTTPS/WSS) | Connector Media Worker + dialplan/AudioSocket |
direct |
رجیستر مستقیم WebRTC/PJSIP | اختیاری اگر ادمین فعال کند | دسترسی به WSS/SIP PBX (LAN/VPN/پورت باز) | endpoint PJSIP با webrtc=yes + WSS |
desk |
تلفن رومیزی / Softphone خارجی | مثل امروز | — | داخلی SIP موجود + Click-to-Call AMI |
هر telephony_user_extensions فیلد جدید میگیرد:
endpoint_mode: relay | direct | desk
preferred_mode: ...
allow_mode_fallback: bool
روی PBX هم:
pbx.settings.softphone = {
"relay_enabled": true,
"direct_enabled": false,
"media_codec_prefs": ["opus", "ulaw", "alaw"],
"max_concurrent_softphone_sessions": 50
}
۳.۲ انتخاب حالت در عمل
اگر endpoint_mode=relay → همیشه Relay
اگر endpoint_mode=direct → تلاش Direct؛ اگر fail و allow_fallback → Relay
اگر endpoint_mode=desk → Originate مثل امروز (بدون media engine)
UI باید حالت فعال و دلیل fallback را شفاف نشان دهد.
۴. معماری هدف
۴.۱ نمای کلی حالت Relay (پیشفرض)
┌──────────────────────────────────────────────────────────────────────────┐
│ Flutter Softphone (Web / Android / Windows) │
│ UI: Phone Bar · Dialer · In-call controls · Device picker │
│ Engine: flutter_webrtc + SoftphoneSessionController │
└───────────────────────────────┬──────────────────────────────────────────┘
│ 1) REST: create softphone session
│ 2) WSS signaling (Hesabix)
│ 3) WebRTC media (DTLS-SRTP) → Media Edge
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ Hesabix Cloud │
│ API (FastAPI): session/auth/ACL/CRM/CTI │
│ Media Edge Service (OSS): WebRTC termination + session broker │
│ coturn (STUN/TURN) برای کلاینت ↔ Media Edge │
│ Connector Media Hub: تونلهای خروجی پایدار از Connectorها │
└───────────────────────────────▲──────────────────────────────────────────┘
│ Outbound WSS/gRPC-Web از PBX به Cloud
│ (بدون پورت ورودی روی Issabel)
┌───────────────────────────────┴──────────────────────────────────────────┐
│ Hesabix Telephony Connector (+ Media Worker) روی Issabel │
│ AMI (موجود) + Media Bridge + AudioSocket/ARI client │
└───────────────────────────────▲──────────────────────────────────────────┘
│ فقط localhost / شبکه داخلی PBX
┌───────────────────────────────┴──────────────────────────────────────────┐
│ Asterisk / Issabel │
│ صفها، ترانکها، داخلیهای رومیزی، MixMonitor، CDR │
│ کانال صوتی Softphone: AudioSocket یا ExternalMedia یا PJSIP local │
└──────────────────────────────────────────────────────────────────────────┘
۴.۲ نمای حالت Direct (اختیاری)
Flutter (sip_ua + flutter_webrtc)
│ SIP over WSS + WebRTC
▼
Issabel PJSIP WebRTC endpoint (LAN/VPN/exposed WSS)
│
▼ AMI events همچنان از Connector به Hesabix برای CRM/Pop
در Direct، حسابیکس همچنان CTI را نگه میدارد؛ فقط پای رسانه مستقیم به PBX است.
۴.۳ چرا این طرح با فایروال سازمانی سازگار است؟
- کلاینت هرگز به IP سانترال وصل نمیشود (در Relay).
- سانترال فقط خروجی به
api/mediaحسابیکس میزند — همان فلسفهٔ Connector فعلی. - واحد امنیت شبکه معمولاً این الگو را میپذیرد (مشابه ایمیل بریج/وبهوک).
۵. پشته ابزار OSS (بدون لایسنس تجاری)
همه موارد زیر رایگان/متنباز هستند و وابستگی لایسنس runtime ندارند.
۵.۱ کلاینت (Flutter)
| جزء | ابزار | مجوز تقریبی | نقش |
|---|---|---|---|
| WebRTC | flutter_webrtc |
BSD-like | میکروفون، کدک، PeerConnection |
| سیگنالینگ Relay | کد اختصاصی حسابیکس روی WS موجود/جدید | — | offer/answer/ICE/candidate |
| Softphone Direct | sip_ua (بر پایه JsSIP port) |
MIT | فقط وقتی direct فعال است |
| پخش ضبط (موجود) | flutter_sound |
— | جدا از تماس زنده |
نکته: در Relay از sip_ua استفاده نمیشود؛ چون کلاینت SIP به PBX رجیستر نمیکند. سیگنالینگ نرمافزاری حسابیکس است.
۵.۲ ابر حسابیکس
| جزء | ابزار پیشنهادی | مجوز | نقش | وضعیت |
|---|---|---|---|---|
| Media Edge (R1) | Media Hub in-process + WSS PCM | — | ختم سشن کلاینت + پل به تونل | ✅ پیاده |
| ارتقا کیفیت (R3) | aiortc یا Janus | BSD/GPL | WebRTC/Opus اختیاری | ⏳ |
| TURN/STUN | coturn | BSD | عبور NAT کلاینت | ⏳ (ICE config آماده) |
| کنترلپلین | FastAPI موجود | — | صدور سشن، ACL | ✅ |
| صف/وضعیت | حافظه نود + جدول سشن | — | presence سشنهای media | ✅ پایه |
۵.۳ Connector روی PBX
| جزء | ابزار | نقش |
|---|---|---|
| کنترل | AMI موجود (pure Python) | originate/hangup/transfer/events |
| پل رسانه | ماژول جدید Python در Connector | تبادل فریم صوت با Cloud + Asterisk |
| اتصال به Asterisk (ترجیحی) | Asterisk AudioSocket | صوت دوطرفه TCP به اپ خارجی — بدون WebRTC روی PBX |
| اتصال جایگزین | ARI ExternalMedia | اگر AudioSocket در نسخه Asterisk نباشد |
| اتصال جایگزین ۲ | PJSIP endpoint روی 127.0.0.1 |
فقط localhost؛ باز هم بدون expose اینترنت |
۵.۴ صریحاً ممنوع در این طرح
- Siprix / تجاریهای دارای لایسنس runtime
- سرویسهای ابری پولی VoIP بهعنوان مسیر اجباری
- عبور RTP از سرور اپلیکیشن بدون جداسازی Media Edge
- ذخیره رمز SIP ماندگار در LocalStorage مرورگر بدون سیاست Direct
۶. مسیر صوت و سیگنالینگ — جزئیات Relay
۶.۱ پروتکلها
| بخش | پروتکل | رمزنگاری |
|---|---|---|
| کلاینت ↔ API | HTTPS | TLS |
| کلاینت ↔ Signaling | WSS | TLS |
| کلاینت ↔ Media Edge | WebRTC (ICE/DTLS/SRTP) | DTLS-SRTP |
| Media Edge ↔ Connector | WSS یا HTTP/2 bidirectional stream روی تونل خروجی | TLS + توکن Connector |
| Connector ↔ Asterisk | AudioSocket TCP یا ARI + RTP localhost | شبکه محلی؛ ترجیحاً bind روی 127.0.0.1 |
| کنترل CTI | AMI + HTTPS webhook/poll موجود | مثل امروز |
۶.۲ کدک
ترتیب ترجیح:
- Opus بین کلاینت و Media Edge (WebRTC)
- در لبهی Connector تبدیل به slin16 / ulaw / alaw مطابق کانال Asterisk
- ترجیح Opus تا PBX فقط اگر کانال/ترانک پشتیبانی کند؛ در غیر این صورت ترنسکود در Connector Media Worker
بودجهٔ کیفیت فاز سازمانی:
- هدف عملیاتی: مکالمه قابل قبول مرکز تماس روی ADSL متوسط
- متریک: RTT، jitter، loss، bitrate، reconnect count
- UI اپراتور: نشانگر کیفیت ساده (خوب/متوسط/ضعیف)
۶.۳ مدل سشن
موجودیت جدید پیشنهادی: telephony_softphone_sessions
| فیلد | توضیح |
|---|---|
| id | UUID سشن |
| business_id / pbx_id / user_id | قفل چندمستأجری |
| extension | داخلی منطقی اپراتور |
| mode | relay | direct |
| state | creating | registered | ringing | in_call | ended | failed |
| media_edge_node | کدام نود media |
| connector_tunnel_id | شناسه تونل |
| call_id | FK به telephony_calls وقتی تماس فعال است |
| ice_policy / turn_used | برای دیباگ |
| created_at / expires_at / ended_at | TTL سشن |
| last_quality_json | نمونه متریک |
سشن رجیستر Softphone ≠ تماس. اپراتور میتواند آنلاین باشد بدون تماس فعال.
۶.۴ جریان رجیستر Relay (آنلاین شدن اپراتور)
1. کاربر وارد کسبوکار میشود؛ Phone Bar فعال است؛ endpoint_mode=relay
2. Flutter → POST /telephony/business/{id}/softphone/sessions
3. API بررسی: لایسنس افزونه، permission، mapping داخلی، pbx online، relay_enabled
4. API به Media Hub میگوید: برای این pbx تونل Connector زنده است؟
5. اگر تونل offline → خطا با پیام فارسی واضح + راهنمای Connector
6. API سشن میسازد و ticket کوتاهعمر media برمیگرداند
7. Flutter به Media Edge با WebRTC connect میشود (data/keepalive + آمادهباش صوت)
8. Connector مطلع میشود: agent X online روی extension 102
9. AMI/Presence: داخلی softphone بهعنوان در دسترس علامت میخورد (با مکانیزم تعریفشده)
10. UI: وضعیت «آماده پاسخگویی»
مهم: در Relay، «رجیستر» یعنی حضور روی Media Hub/Connector، نه REGISTER سیپ به Asterisk عمومی.
۶.۵ جریان تماس ورودی (Relay)
1. تماس وارد Issabel → صف/داخلی
2. Dialplan برای اپراتورهای Softphone-Relay بهجای حلقه SIP خارجی،
کانال را به AudioSocket(uuid) / ExternalMedia میبرد
یا از طریق Local channel کنترلشده توسط Connector
3. AMI event → Connector → Hesabix (مثل امروز) → Screen Pop
4. همزمان Media Hub: سشن صوت برای user را ring میکند
5. Flutter ringtone + دکمه Answer
6. Answer → signaling به Media Edge → Connector پل را کامل میکند
7. صوت دوطرفه برقرار
8. state machine تماس موجود (ringing→answered→completed) بدون شکست CRM
۶.۶ جریان تماس خروجی (Relay)
1. اپراتور از Dialer / PhoneLink شماره میگیرد
2. اگر mode=relay: دیگر AMI Originate به «گوشی SIP اپراتور» نمیرود
3. بهجای آن:
a) سشن media اپراتور باید online باشد
b) دستور به Connector: Originate سمت مقصد (ترانک/شماره) و Bridge به AudioSocket سشن اپراتور
4. Flutter حالت dialing/ringing/in_call را از signaling + CTI events میگیرد
5. telephony_calls با direction=outbound ثبت میشود
این دقیقاً درد Click-to-Call فعلی (وابستگی به گوشی جانبی) را حذف میکند.
۶.۷ Hold / Mute / DTMF / Transfer
| عمل | کجا اجرا شود |
|---|---|
| Mute | کلاینت (قطع track میکروفون) + اطلاع به سرور برای audit |
| Hold | ترجیحاً Asterisk hold از طریق دستور Connector (موسیقی انتظار PBX) |
| DTMF | از کلاینت بهصورت event به Connector → Play DTMF روی کانال Asterisk |
| Blind Transfer | دستور AMI/ARI موجود از UI |
| Hangup | هم media close هم AMI hangup؛ idempotent |
۶.۸ قطع شبکه و بازیابی
- قطع کوتاه کلاینت (< N ثانیه): تلاش ICE restart / re-offer؛ تماس را فوراً hangup نکن
- قطع طولانی: وضعیت
reconnecting؛ بعد از آستانه → hangup تمیز + ثبتfailed/cancelledبا علت - قطع تونل Connector: همه سشنهای Softphone آن PBX →
degraded؛ UI قرمز؛ Desk mode اگر مجاز باشد پیشنهاد شود - Heartbeat تونل رسانه جدا از heartbeat CTI (هر ۲–۵ ثانیه)
۷. اتصال Connector به Asterisk بدون expose کردن PJSIP
۷.۱ گزینه A — AudioSocket (ترجیحی)
- Asterisk اپلیکیشن
AudioSocketدارد (نسخههای جدیدتر). - Connector روی
127.0.0.1:PORTگوش میدهد. - Dialplan نمونهٔ مفهومی:
[hesabix-softphone-relay]
exten => _X.,1,NoOp(Hesabix Softphone Relay)
same => n,Set(HSX_UUID=${UNIQUEID})
same => n,AudioSocket(${HSX_UUID},127.0.0.1:9092)
same => n,Hangup()
- مزیت: بدون WebRTC روی PBX، بدون پورت اینترنت، پیادهسازی تمیز برای Agent خارجی.
- ریسک: باید نسخه Asterisk مشتری پشتیبانی کند؛ در غیر این صورت fallback.
۷.۲ گزینه B — ARI ExternalMedia
- Connector به ARI محلی وصل میشود (فقط LAN/localhost).
- کانال ExternalMedia میسازد و RTP را خودش terminate میکند.
- مزیت: کنترل برنامهای قویتر برای Bridge/Hold.
- ریسک: پیکربندی ARI و نسخه؛ کمی پیچیدهتر از AudioSocket.
۷.۳ گزینه C — PJSIP localhost-only
- یک endpoint محلی مثل
hsx-media-102فقط روی127.0.0.1. - Connector با استک SIP سبک OSS (مثلاً بخشی از pjproject/aiortc-sip یا پیادهسازی محدود) رجیستر محلی میکند.
- مزیت: سازگاری بالا با Issabel سنتی.
- ریسک: پیچیدگی SIP در Connector؛ فقط اگر A/B نشد.
۷.۴ استراتژی سازگاری Issabel
ویزارد hesabix-pbx softphone-relay-setup:
- تشخیص نسخه Asterisk
- انتخاب خودکار backend صوت: AudioSocket → ARI → Local PJSIP
- نوشتن/پیشنهاد snippet دیالپلن
- تست لوپبک صوت ۳۰ ثانیهای
- گزارش health به حسابیکس
نتیجه برای مشتری: «نیازی به باز کردن PJSIP/WebRTC به اینترنت نیست.»
اگر خواست Direct را جداگانه فعال میکند.
۸. حالت Direct (اختیاری، بدون اجبار)
برای سازمانی که VPN دارد یا WSS را عمداً باز میکند:
۸.۱ پیشنیاز PBX
- Transport WSS (مثلاً 8089) با TLS
- endpoint PJSIP با DTLS-SRTP / webrtc
- STUN/TURN مناسب شبکه همان سازمان
۸.۲ کلاینت
sip_ua+flutter_webrtc- credential از API با TTL یا از تنظیم ادمین (ترجیح TTL یکبارمصرف اگر PBX از طریق Connector provision شود)
۸.۳ CTI
- همچنان Connector رویداد AMI را برای Pop/CDR میفرستد
- باید از دوبارهشماری تماس (یک بار از SIP client و یک بار از AMI) جلوگیری شود — کلید
linkedid/uniqueid
۸.۴ امنیت Direct
- پیشفرض خاموش
- هشدار صریح در UI تنظیمات: «پورت PBX از بیرون در دسترس خواهد بود مگر پشت VPN»
- توصیه محصولی: Relay برای اینترنت؛ Direct برای LAN/VPN
۹. مدل داده و API (افزودهها)
۹.۱ جداول/فیلدهای جدید
telephony_softphone_sessions(بالا)telephony_user_extensions.endpoint_modetelephony_user_extensions.direct_sip_user(nullable)telephony_pbx_connections.settings.softphoneJSONtelephony_commands.command_typeگسترش:
softphone_bridge_in|softphone_bridge_out|softphone_dtmf|softphone_set_presencetelephony_metric_counterمتریکهای media:softphone_sessions_active,media_tunnel_up,opus_transcode_errors, ...
۹.۲ APIهای اصلی (پیشنهادی)
اپراتور (JWT کسبوکار):
POST /api/v1/telephony/business/{id}/softphone/sessions— ایجاد/تمدید سشنPOST /api/v1/telephony/business/{id}/softphone/sessions/{sid}/heartbeatDELETE /api/v1/telephony/business/{id}/softphone/sessions/{sid}— unregisterPOST /api/v1/telephony/business/{id}/softphone/calls— شروع خروجی در حالت relayPOST /api/v1/telephony/business/{id}/softphone/calls/{call_id}/answerPOST /api/v1/telephony/business/{id}/softphone/calls/{call_id}/dtmfGET /api/v1/telephony/business/{id}/softphone/devices-config— iceServers/turn موقتGET /api/v1/telephony/business/{id}/softphone/health
Connector (token موجود + قابلیت media):
GET /api/v1/telephony/connector/media/tunnel(Upgrade WSS) یا endpoint جدا روی Media HubPOST /api/v1/telephony/connector/media/eventsPOST /api/v1/telephony/connector/media/quality
ادمین کسبوکار:
- فعال/غیرفعال Relay/Direct
- سقف سشن همزمان
- اجبار mode برای همه کاربران یا per-user
۹.۳ مجوزها
جدید:
telephony.softphone— استفاده اپراتورtelephony.softphone_manage— تنظیمات mode/provisiontelephony.softphone_quality— دیدن متریک کیفیت تیم (سرپرست)
موجودها (click_to_call, control_calls, ...) حفظ میشوند.
۹.۴ رویدادهای WS
علاوه بر telephony.* فعلی:
telephony.softphone.registeredtelephony.softphone.unregisteredtelephony.softphone.incoming_mediatelephony.softphone.reconnectingtelephony.softphone.quality_changedtelephony.softphone.tunnel_down
۱۰. UX سازمانی (وب / اندروید / ویندوز)
۱۰.۱ Phone Bar (ارتقاء)
وضعیتها:
- قطع از مرکز تلفن
- Connector آنلاین / تونل رسانه قطع
- Softphone آمادهباش
- در حال زنگ
- در حال مکالمه (+ تایمر)
- در حال اتصال مجدد
دکمهها: شمارهگیر، پاسخ، قطع، mute، hold، انتقال، وضعیت هدست.
۱۰.۲ صفحه Softphone (جایگزین اسکفولد فعلی)
- نمایش داخلی و mode فعال
- تست میکروفون/بلندگو قبل از شیفت
- انتخاب دستگاه صوت (Desktop/Web)
- لاگ تشخیصی جمعوجور برای پشتیبانی (قابل کپی)
۱۰.۳ الزامات پلتفرم
| پلتفرم | الزام سازمانی |
|---|---|
| Web | HTTPS، permission میکروفون، جلوگیری از double-tab register، هشدار بستن تب هنگام مکالمه |
| Android | Foreground Service هنگام تماس، اعلان Incoming، قفل صفحه، بازیابی پس از تعویض شبکه |
| Windows | کار در tray/minimize بدون unregister، hotkey پاسخ/قطع، انتخاب device پایدار بعد از sleep |
۱۰.۴ یکپارچگی CRM
بدون تغییر فلسفه:
- Screen Pop روی ringing
- Post-call sheet
- ایجاد Person/Lead
- لینک به
crm_activities - گزارشها همان
telephony_calls
تفاوت فقط منبع رسانه است، نه مدل کسبوکار.
۱۱. امنیت، حریم خصوصی، انطباق
- توکن Connector و ticket مدیا کوتاهعمر؛ چرخشپذیر
- Media Edge جدا از API داده؛ حداقل داده CRM روی مسیر صوت نباشد
- Audit: شروع سشن، پاسخ، گوشدادن ضبط، انتقال، تغییر mode
- محدودیت نرخ ایجاد سشن per user
- انکار سشن اگر mapping داخلی نداشته باشد
- در Relay هیچ پورت PBX به اینترنت publish نشود (چکلیست نصب)
- ضبط همچنان با permission
listen_recordings - جداسازی کامل tenant در broker تونلها
- عدم نگهداری صوت مکالمه روی دیسک Media Edge مگر برای jitter کوتاه؛ SoT ضبط = PBX/سیاست فعلی
- هشدار حقوقی به مشتری: مسئولیت ضبط قانونی با پیکربندی PBX آنهاست (مثل سند قبلی)
۱۲. عملیات، نصب، مشاهدهپذیری
۱۲.۱ ویزارد نصب Relay
گامها در UI حسابیکس + CLI Connector:
- فعالسازی افزونه و ساخت PBX (موجود)
- نصب/آپدیت Connector (موجود)
hesabix-pbx softphone-relay-setup- تست تونل رسانه (سبز/قرمز)
- تست لوپبک صوت با کاربر آزمایشی
- انتخاب mode پیشفرض کاربران
- آموزش ۳۰ ثانیهای اپراتور (میکروفون/پاسخ)
۱۲.۲ متریکهای سلامت (حداقلی)
- تعداد تونلهای media online
- سشنهای softphone فعال per PBX
- نرخ شکست answer
- میانگین زمان setup تماس (ring→media connected)
- درصد استفاده TURN
- خطاهای ترنسکود
- نسخه Connector / قابلیت AudioSocket|ARI
۱۲.۳ ظرفیتسنجی اولیه
فرض فاز ۱:
- ۵۰ سشن همزمان softphone per PBX متوسط
- Media Edge افقیپذیر (چند نود پشت LB)
- یک Connector process با workerهای async برای RTP/frames
آستانه هشدار: CPU Connector > ۷۰٪ پایدار یا loss > ۵٪ در ۱ دقیقه.
۱۳. فازبندی اجرایی دقیق
فاز R0 — Discovery و Lab (۲ هفته)
هدف: اثبات کیفیت روی Issabel واقعی پشت فایروال.
وضعیت: در حال اجرا — زیرساخت PoC در مخزن آماده؛ UAT روی Issabel واقعی باقی است.
کارها:
- قرارداد معماری Relay (تونل خروجی + AudioSocket localhost)
- پروتکل فریم رسانه
HSXM+ پروفایلpcm_ws_v1 - اسکلت Media Hub در API + تونل WSS Connector
- نمونه دیالپلن
hesabix-softphone-relay.conf.sample - برپایی lab: Issabel بدون پورت ورودی + حسابیکس staging (محیط مشتری/ops)
- اندازهگیری RTT/loss/CPU روی مکالمه واقعی ۵ دقیقهای
- تصمیم backend صوت Asterisk برای R1: AudioSocket (fallback ARI/Local بعداً)
پذیرش:
- مکالمه ۲ طرفه پایدار ۵ دقیقه پشت فایروال کامل
- طراحی بدون نیاز به پورت ورودی PBX (معماری تأیید شد؛ تأیید nmap روی lab باقی است)
- Screen Pop همزمان با ringing (مسیر CTI موجود حفظ شد)
فاز R1 — هسته Softphone Relay (۵ هفته)
وضعیت: ✅ کد کامل — UAT روی Issabel واقعی باقی است.
- مدل داده سشن (
telephony_softphone_sessions) +endpoint_modeروی user_extensions + migration - API سشن/سلامت/خروجی/پاسخ/DTMF + permissions UI
- Media Hub MVP (in-process) + WS کلاینت و تونل Connector
- Media Worker در Connector (AudioSocket + MediaTunnel + دستورات softphone_*)
- Engine Flutter + جایگزینی صفحه اسکفولد Softphone
- Answer / Hangup / Mute / Dial outbound (مسیر کنترل)
- یکپارچگی با
telephony_callsبرای خروجی relay - پخش و ضبط میکروفون واقعی (
softphone_pcm_media— flutter_sound روی IO، WebAudio+VoiceWebCapture روی Web @ 8kHz) - UI تنظیمات: ویرایش
endpoint_mode/ fallback / Softphone PBX settings + ویزارد راهاندازی Relay - Phone Bar یکپارچه با SoftphoneEngineStore (پاسخ/Mute/قطع/وضعیت)
- Click-to-Call وقتی Softphone آنلاین است مسیر Relay را ترجیح میدهد
- UAT ورودی/خروجی کامل روی Web با Issabel واقعی (محیط ops)
پذیرش:
- ورودی و خروجی کامل بدون Softphone خارجی روی Web (منتظر lab Issabel)
- Android و Windows مسیر مشترک آماده (PCM via flutter_sound؛ تست دستگاه در UAT)
- desk mode Intact (Click-to-Call و originate حفظ شد)
فایلهای کلیدی اضافهشده/تغییریافته در R1
hesabixAPI/migrations/versions/20260806_000003_telephony_softphone_media_relay.pyhesabixAPI/app/services/telephony/media_hub.pyhesabixAPI/app/services/telephony/softphone_service.pyhesabixAPI/adapters/api/v1/telephony_softphone_ws.pyhesabixAPI/adapters/api/v1/telephony.py(endpointهای softphone)extraScripts/HesabixTelephonyConnector/app/media_audiosocket.pyextraScripts/HesabixTelephonyConnector/app/media_tunnel.pyextraScripts/HesabixTelephonyConnector/app/main.pyhesabixUI/.../softphone_engine.dart+softphone_ws_client_*.dart+softphone_pcm_media_*.darthesabixUI/.../telephony_softphone_page.darthesabixUI/.../telephony_hub_page.dart(تنظیمات Softphone / endpoint_mode)hesabixUI/.../telephony_phone_bar.darthesabixUI/.../telephony_session_controller.dart(اولویت Relay در Click-to-Call)
فاز R2 — CTI Sync و کنترلهای تماس (۳ هفته)
- Hold/DTMF/Transfer هماهنگ با AMI
- Presence واقعی softphone در Live Dashboard
- حذف تداخل Originate با Relay
- Fallback desk/direct طبق تنظیم
پذیرش:
- Transfer از UI در Relay
- داشبورد وضعیت idle/busy صحیح
- عدم ثبت دوبل CDR
فاز R3 — سختسازی پلتفرم و شبکه (۴ هفته)
- coturn تولید
- reconnect/ICE restart
- Android foreground + notification
- Windows tray/device
- Web multi-tab guard
- متریک کیفیت در UI و ops
پذیرش:
- تعویض WiFi↔۴G بدون hangup فوری (در آستانه تعریفشده)
- minimize ویندوز مکالمه را نکشد
- اعلان Incoming اندروید وقتی اپ پشت است
فاز R4 — Direct اختیاری + عملیات فروش (۳ هفته)
- فعالسازی
directباsip_ua - ویزارد و هشدار امنیتی
- مستندات فارسی کامل Relay vs Direct vs Desk
- UAT با ۲–۳ مشتری واقعی (یکی کاملاً قفلفایروال)
پذیرش:
- مشتری قفلفایروال فقط با Relay کار کند
- مشتری VPN بتواند Direct را انتخاب کند
- تکنسین Issabel با مستند، بدون تیم توسعه، Relay را بالا بیاورد
فاز R5 — پیشرفته (بکلاگ)
- Attended transfer پیشرفته / کنفرانس سهطرفه
- Whisper/Barge (ARI)
- ضبط سمت سرپرست زنده
- Janus بهجای aiortc اگر مقیاس ایجاب کرد
- iOS Push/CallKit کامل
جمع تا نسخه قابل فروش سازمانی Relay: حدود ۱۶–۱۸ هفته با تیم متمرکز.
۱۴. سناریوهای پذیرش Must-pass (سازمانی)
- PBX بدون هیچ پورت ورودی: اپراتور وب پاسخ میدهد و صحبت میکند.
- همان روی اندروید و ویندوز.
- خروجی از پروفیل مشتری بدون Zoiper.
- Desk-phone همزمان برای کاربر دیگر همان کسبوکار کار کند.
- قطع اینترنت شعبه: UI وضعیت تونل را نشان دهد؛ پس از وصل، بازیابی سشن.
- تعویض کسبوکار: unregister کامل و register با داخلی جدید.
- دو تب مرورگر: جلوگیری از رجیستر دوبل مخرب.
- Transfer به داخلی رومیزی و ادامه تاریخچه یکسان.
- Direct روی lab VPN کار کند بدون شکستن Relay.
- کاربر بدون permission softphone فقط desk/click-to-call ببیند.
- حمله token نامعتبر به تونل media رد شود.
- کیفیت روی ADSL متوسط «قابل بهرهبرداری شیفت ۸ ساعته» در UAT انسانی.
۱۵. ریسکها و کاهش
| ریسک | اثر | کاهش |
|---|---|---|
| تأخیر اضافه در Relay (یک hop ابری) | کیفیت پایینتر از LAN Direct | Opus، نود media نزدیک، مانیتور، گزینه Direct برای LAN |
| CPU ترنسکود روی Connector | محدودیت ظرفیت | کدک مناسب، worker جدا، سقف سشن |
| نبود AudioSocket در Asterisk قدیمی | بلاک پیادهسازی | fallback ARI / Local PJSIP |
| پیچیدگی همزمان CTI + Media | باگ حالت تماس | state machine واحد، تست ماتریسی |
| antimalware/firewall مشتری روی WSS خروجی | تونل بالا نیاید | پورت 443، دامنه رسمی، راهنمای whitelist |
| انتظار کاربر از کیفیت تلفن رومیزی | نارضایتی | هدست اجباری در آموزش، تست دستگاه، شاخص کیفیت |
| دو مسیر Direct/Relay | هزینه نگهداری | Abstraction Engine + یک UI |
۱۶. تصمیمهای محصولی که باید قبل از کدنویسی قفل شوند
| # | موضوع | پیشنهاد سند |
|---|---|---|
| 1 | پیشفرض همه مشتریان جدید | relay |
| 2 | آیا Direct در نسخه ۱ فروش باشد؟ | بله، ولی خاموش و پشت flag ادمین |
| 3 | Media Edge جدا از API یا داخلمونو | سرویس جدا hesabix-media از روز اول |
| 4 | هزینه زیرساخت TURN/Media | جزو هزینه افزونه/پلن؛ نه لایسنس شخص ثالث |
| 5 | سقف سشن همزمان پیشفرض | ۵۰ per PBX قابل تنظیم |
| 6 | آیا Click-to-Call برای کاربران Relay مخفی شود؟ | بله در UI؛ API desk فقط اگر mode=desk |
۱۷. معیار «عالی سازمانی» (تعریف Done)
این قابلیت Done است فقط اگر:
- بدون نرمافزار جانبی، شیفت کامل پشتیبانی روی وب یا ویندوز ممکن باشد.
- مشتری با PBX قفلفایروال بتواند فروخته و راهاندازی شود.
- CRM/Pop/گزارش/ضبط با همان کیفیت CTI فعلی کار کند.
- ابزار مسیر صوت لایسنس تجاری نداشته باشد.
- حالت Desk و Direct (اختیاری) بدون فروپاشی معماری پشتیبانی شوند.
- مشاهدهپذیری کافی برای پشتیبانی سطح ۲ وجود داشته باشد.
- مستند نصب فارسی توسط تکنسین Issabel مستقل اجرا شود.
۱۸. جمعبندی راهبرد
- بله، میشود صدا را از طریق افزونه/Connector رله کرد و نیازی به باز بودن PJSIP/WebRTC سانترال به اینترنت نباشد.
- رجیستر مستقیم بهعنوان گزینه برای شبکههای باز/VPN باقی میماند.
- مسیر درست: WebRTC تا ابر حسابیکس + تونل خروجی Connector + AudioSocket/ARI محلی به Asterisk + حفظ CTI فعلی.
- پشته پیشنهادی رایگان:
flutter_webrtc(+sip_uaفقط برای Direct) ·aiortc·coturn· Asterisk AudioSocket/ARI · Connector Python موجود.
قدم بعد پس از تأیید این سند: شکستن فاز R0 به تیکتهای اجرایی lab و تعیین owner برای Media Edge و Connector Media Worker — بدون شروع پیادهسازی محصول تا پایان PoC کیفیت R0.
پایان سند v1.0.0