
أصدقاء ، اليوم أريد أن أتحدث معك حول المكالمات. بالنسبة للبعض ، هذا موضوع جديد تمامًا. بالنسبة للآخرين ، إنها متعة خالصة من المعجبين على مستوى "ولكن هل يجب أن أرسل Skype إلي؟" للثالث ، حاجة مفاجئة للحياة. الخيار الأخير هو خيارنا.
في هذه المقالة ، سأريك مثالًا صغيرًا ولكنه قابل للتطبيق ، مما يسمح لك حرفيًا بإجراء اتصال WEB الخاص بك والاتصال بصديق مباشرةً من المستعرض حرفيًا على ركبة عدة عشرات من خطوط جافا سكريبت.
حول التقنيات والبروتوكولات

إنه عام 2019 ، ومن دواعي سرورنا ، أن هناك بالفعل أداة جاهزة لتنفيذ R eal- T ime C ommunication (RTC) للويب ، وهي WebRTC . قبل بضع سنوات كان في التنمية النشطة. لا تزال واجهة برمجة التطبيقات قيد الانتهاء ، لكن التكنولوجيا أصبحت المعيار الفعلي وهي مدعومة في معظم المتصفحات الشائعة. في هذه المقالة ، لن نتحدث عن التكنولوجيا نفسها ، يمكنك قراءة المزيد على موقع المطورين أو البحث عن مقالات على المحور على سبيل المثال ، هنا .
ولكن قبل أن نبدأ ، أريد أن أوضح بضع نقاط.
- أولاً ، يعمل WebRTC على رأس مجموعة من البروتوكولات ، وحتى بالنسبة لاتصالات p2p ، ستحتاج إلى نوع من الخوادم يمكن للعملاء من خلاله إيجاد وتكوين صداقات مع بعضهم البعض. مثالنا سوف يستخدم بروتوكول SIP ، والذي يمكنك قراءة المزيد عنه ، على سبيل المثال ، هنا .
- ستحتاج إلى خادم يدعم جميع العناصر المذكورة أعلاه - مثل FreeSwitch أو Asterisk.
نترك هذه الأشياء خارج نطاق المقال. نحن نفترض أنك محظوظ مثلنا ، وأنك قمت بالفعل بتكوين الاتصال الهاتفي عبر بروتوكول الإنترنت تحت تصرفك.
حسنًا ، أطول جزء من المقالة هو الخلف ، دعنا نرمز!
تخطيط الصفحة

أولاً ، نحتاج إلى صفحة سنتصل بها ، وحقول لإدخال اسم المستخدم وكلمة المرور ورقم الهاتف واثنين من الأزرار. في أبسط إصدار ، سيبدو مثل هذا:
<div class="container"> <div class="input-group mb-6"> <div class="input-group-prepend"> <span class="input-group-text">Login</span> </div> <input id="loginText" type="text" class="form-control"> <div class="input-group-prepend"> <span class="input-group-text">Password</span> </div> <input id="passwordText" type="password" class="form-control"> <button id="loginButton" type="button" class="btn btn-primary" onclick="login()">Login</button> <button id="logOutButton" type="button" class="btn btn-primary d-none" onclick="logout()">LogOut</button> </div> <div class="input-group mb-6 d-none" id="callPanel"> <input id="callNumberText" type="text" class="form-control" placeholder="Call number"> <button id="callNumberButton" type="button" class="btn btn-success" onclick="call()">Call</button> <button id="hangUpButton" type="button" class="btn btn-danger d-none" onclick="hangUp()">Hang Up</button> </div> <audio id="localAudio" autoPlay muted></audio> <audio id="remoteAudio" autoPlay></audio> <audio id="sounds" autoPlay></audio> </div>
ستقوم عناصر الصوت "بإرسال" و "استقبال" الصوت ، وللجمال ، من خلال الأصوات ، تشغيل أصوات الطلب الهاتفي.
واجهة المستخدم جاهزة ، لا يمكنك العثور على خطأ مع UX ، فلنجعلها تعمل.
نحن ربط JSSIP

سنستخدم مكتبة يتم فيها تنفيذ كل ما هو مطلوب بالفعل - JSSIP . يمكنك الاطلاع على الوثائق: كل شيء موصوف بتفاصيل كافية هناك وحتى هناك مثال تنفيذ جاهز. أي أننا لا نحتاج عملياً إلى فعل أي شيء - ما عليك سوى تبسيط كل شيء قدر الإمكان ومعرفة ما هو.
بعد إدخال تسجيل الدخول / كلمة المرور (يجب أن تكون مسجلة على خادم الاتصال الهاتفي الخاص بك) تحتاج إلى تسجيل الدخول إلى الخادم. نحن نفعل هذا:
socket = new JsSIP.WebSocketInterface("wss://webrtcserver:port/ws"); _ua = new JsSIP.UA( { uri: "sip:" + this.loginText.val() + "@webrtcserver", password: this.passwordText.val(), display_name: this.loginText.val(), sockets: [socket] });
على طول الطريق ، يمكنك الاشتراك في الأحداث المتصلة والمتصلة والقيام بشيء مفيد هناك. ولكن دعنا ننتقل إلى حدث التسجيل:
his._ua.on('registered', () => { console.log("UA registered"); this.loginButton.addClass('d-none'); this.logOutButton.removeClass('d-none'); this.loginText.prop('disabled', true); this.passwordText.prop('disabled', true); $("#callPanel").removeClass('d-none'); });
نحن هنا بحاجة فقط إلى تغيير حالة الأزرار: إظهار ما يلزم ، إخفاء ما لا لزوم له. وإذا حدث خطأ ما في تسجيل الدخول فجأة ، فإننا بصق الخطأ في السجل:
this._ua.on('registrationFailed', (data) => { console.error("UA registrationFailed", data.cause); });
هذا يكفي لتسجيل الدخول. يبقى للحصول على الجهاز برميل مع
this._ua.start () ؛
إذا تم تحديد الخادم بشكل صحيح وتم قبول اسم المستخدم / كلمة المرور الخاصة بك ، فسيظهر حقل لإدخال الهاتف وسيظهر زر الاتصال.
للتسجيل ، تحتاج إلى استدعاء this._ua.stop () ، كل شيء بسيط.
قم بإجراء مكالمة
الآن - أهم شيء: تحتاج إلى الاتصال بالرقم الذي تم إدخاله.
this.session = this._ua.call(number, { pcConfig: { hackStripTcp: true,
يرجى ملاحظة: نحن نقوم بتمكين تعدد الإرسال بشكل صريح ، كما يجب تمكين هذا الإعداد على الخادم الخاص بك. في حالة العلامة النجمية ، هذا هو rtcp_mux = نعم في إعدادات sip.conf.
يعتمد المزيد من التفاعل على عمليات الاسترجاعات ، والتي يجب أن نضمن فيها اتجاه دفق الصوت والفيديو إلى عنصر الصفحة المقابل وإرسال الرسائل الضرورية بالترتيب الصحيح إلى الخادم.
بشكل عام ، كل شيء منطقي جدا. أثناء الاتصال ['التقدم'] - قم بتشغيل أصوات الاتصال. في مثالنا ، نلعب الصوت الخاص بنا ، ولكن كما لاحظ pvsur بحق ، يمكنك أيضًا الحصول عليه من الجانب المتصل وسماع استجابة المحرر التلقائي مثل "ترك رسالة بعد الصافرة" ، إذا كان هناك واحد.
بمجرد أن حصلت على ["مقبول"] - قم بتشغيل الصوت الذي تمت الإجابة عليه. بمجرد أن يلتقط المشترك الهاتف ، سوف نحصل على دفق الصوت ووضعه في عنصر التحكم عن بعد [الصوت] و [addstream].
في نهاية المكالمة ، قم بإغلاق closeMediaStream. يمكنك الاسترخاء.
قليلا عن العملية
أثناء الاختبار ، تم اكتشاف شيئين.
- في chrome ، كان هناك تأخير لعدة ثوان في بداية الاتصال ، وهو أمر مزعج للغاية. اكتشفنا من سجلات أنه ذهب إلى خادم الجليد ، وهو أمر غير مطلوب على الإطلاق ، لأن لدينا خادمنا الخاص. لذلك ، في تهيئة JSSIP ، قمنا ببساطة بإزالتها ، وأصبحنا أجمل على الفور. انظر pcConfig.iceServers و pcConfig.hackStripTcp.
- النجمة لدينا لديها بروتوكول WSS مع تشفير SIP. هذا مطلوب من قبل المتصفح عند استخدام موقع HTTPS. لكن العلامة النجمية تستخدم WS بناءً على معلمات الاتصال التي تحتوي فيها مكتبة JSSIP على واصف WS الثابت. يشير مطورو المكتبة في الوقت نفسه إلى معايير لا توجد فيها متطلبات في هذا الموضوع. والزملاء من الأستر لا يريدون إصلاح أي شيء. بشكل عام ، طريق مسدود. حسنًا ، في هذا الوقت ، نجد في المصدر السطر this._configuration.contact_uri = URI الجديد (...) ، وغيّر النقل: 'ws' للنقل: 'wss' واستمر في الاستمتاع بالحياة.
بشكل عام ، المثال جاهز ، يمكنك القيام به والاتصال به. لا حاجة لوضع أي هواتف لينة أو تطوير الخاصة بك. لا داعي للقلق بشأن نشر هذا البرنامج على سيارات العملاء. مجرد فتح المتصفح والاتصال.
تتيح لك مكتبة أخرى طلب أرقام إضافية في وضع النغمة. وهذا يعني أنه يمكنك الاتصال ، على سبيل المثال ، بمركز اتصال البنك والوصول إلى العنصر المطلوب في القائمة الصوتية. للقيام بذلك ، فقط قم بتشغيل الأمر التالي:
this._call.sendDTMF('. ')
عن فاكابي

كان هناك العديد من النقاط التي جعلتني عصبية حقًا.
تركت هذا الجزء خارج نطاق المقالة ، ولكن بالإضافة إلى المكالمات الصادرة ، نحتاج أيضًا إلى قبول المكالمات الواردة. ولبعض الوقت اضطررت إلى القرفصاء بمكالمة واردة ، والتي جاءت ثم توقفت. تم تحديد كل شيء بواسطة إعداد rtcpMuxPolicy المذكور أعلاه وتمكين الإرسال المتعدد على العلامة النجمية ، لكننا كنا أغبياء لبعض الوقت.
وما زالت هناك مشاكل في الاتصال بنفسك - عند إجراء مكالمة ومكالمة على نفس الجهاز. لا أتذكر بالضبط ، ولكن تم إنشاء الاتصال بنجاح ، لم تكن هناك أخطاء ولا صوت أيضًا :) الوقت ينفد ، لذلك سجلنا في هذا التأثير الخاص. لكن ضع في اعتبارك أن اختبار المكالمات الواردة أفضل على سيارة منفصلة.
استنتاج
أخيرًا ، أود الإشارة إلى أننا اختبرنا حزمة JSSIP + Asterisk في مركز الاتصال لدينا ، كل شيء يعمل بشكل جيد ، على الأقل في الكروم ، وهو ما يناسبنا تمامًا. الشيء الرئيسي هو السماح للمتصفح بالوصول إلى أجهزة الوسائط وتسجيل المستخدمين على خادم الاتصال.
يمكنك أن ترى المثال النهائي على جيثب .
روابط مفيدة
حول webrct
حول SIP: tyts ، tyts
حول النجمة
مكتبة Jssip