معمارية تطبيقات المصادر المفتوحة › Asterisk 1 / 51 التالي

Asterisk

معمارية تطبيقات المصادر المفتوحة (المجلد الأول)Asterisk

معمارية تطبيقات المصادر المفتوحة (المجلد الأول) Asterisk

Russell Bryant

إذا استمتعت بهذه الكتب، فقد يعجبك أيضًا التصميم البرمجي بالأمثلة في بايثون (Software Design by Example in Python) والتصميم البرمجي بالأمثلة في جافاسكربت (Software Design by Example in JavaScript).

Asterisk[1] هو نظام مفتوح المصدر لتطبيقات الهاتف، موزَّع بموجب رخصة GPLv2. وباختصار، هو تطبيق خادم لإجراء المكالمات الهاتفية واستقبالها وتنفيذ معالجة مخصَّصة عليها.

بدأ المشروع على يد Mark Spencer عام 1999. كانت لدى Mark شركة اسمها Linux Support Services، وكان يحتاج إلى نظام هاتفي يساعده على تشغيل أعماله. لم يكن لديه الكثير من المال لإنفاقه على شراء نظام، فصنع نظامه بنفسه. ومع ازدياد شهرة Asterisk، حوّلت Linux Support Services تركيزها إلى Asterisk وغيّرت اسمها إلى Digium, Inc.

اسم Asterisk مشتق من محرف البدل (wildcard) في يونكس، وهو *. والهدف من مشروع Asterisk هو أن يفعل كل ما يخصّ الهاتف. ومن خلال السعي وراء هذا الهدف، يدعم Asterisk اليوم قائمة طويلة من التقنيات لإجراء المكالمات الهاتفية واستقبالها. وتشمل ذلك بروتوكولات VoIP (الصوت عبر بروتوكول الإنترنت) العديدة، فضلًا عن وصالات تماثلية ورقمية مع شبكة الهاتف التقليدية، أي PSTN (شبكة الهاتف العمومية المحولة). وتُعدّ هذه القدرة على إدخال أنواع مختلفة من المكالمات الهاتفية إلى النظام وإخراجها منه إحدى نقاط قوة Asterisk الرئيسية.

بمجرد إجراء مكالمات هاتفية من نظام Asterisk وإليه، تتوفر ميزات إضافية كثيرة يمكن استخدامها لتخصيص معالجة المكالمة الهاتفية. وبعض هذه الميزات تطبيقات عامة جاهزة وكبيرة، مثل البريد الصوتي. وهناك ميزات أصغر يمكن دمجها معًا لبناء تطبيقات صوتية مخصَّصة، مثل تشغيل ملف صوتي، أو قراءة الأرقام، أو التعرف على الكلام.

1.1. المفاهيم المعمارية الجوهرية

يتناول هذا القسم بعض المفاهيم المعمارية الجوهرية لجميع أجزاء Asterisk. وتُعدّ هذه الأفكار هي الأساس الذي تقوم عليه بنية Asterisk.

1.1.1. القنوات

تمثّل القناة في Asterisk اتصالًا بين نظام Asterisk ونقطة طرفية هاتفية ما (الشكل 1.1). والمثال الأكثر شيوعًا هو عندما يتصل هاتف بنظام Asterisk. ويمثَّل هذا الاتصال بقناة واحدة. وفي شيفرة Asterisk، توجد القناة على هيئة نسخة (instance) من بنية البيانات ast_channel. وقد يكون سيناريو المكالمة هذا، على سبيل المثال، مكالمة من متصل يتفاعل مع البريد الصوتي.

ساق مكالمة واحدة ممثَّلة بقناة واحدة

الشكل 1.1: ساق مكالمة واحدة ممثَّلة بقناة واحدة

1.1.2. جسر القنوات

ربما يكون سيناريو مكالمة أكثر ألفة هو الاتصال بين هاتفين، حيث اتصل شخص يستخدم الهاتف A بشخص على الهاتف B. وفي سيناريو المكالمة هذا، توجد نقطتان طرفيتان هاتفيتان متصلتان بنظام Asterisk، لذا توجد قناتان لهذه المكالمة (الشكل 1.2).

ساقا مكالمة ممثَّلتان بقناتين

الشكل 1.2: ساقا مكالمة ممثَّلتان بقناتين

عندما تُوصَل قنوات Asterisk بهذه الطريقة، يُشار إليها بأنها جسر قنوات (channel bridge). وتجسر القنوات هو فعل ربط القنوات ببعضها لغرض تمرير الوسائط بينها. وتُعدّ تدفّقات الوسائط في الغالب تدفّقات صوتية. غير أنه قد تتضمّن المكالمة أيضًا تدفق فيديو أو تدفق نصوص. وحتى في الحالة التي يوجد فيها أكثر من تدفق وسائط (مثل الصوت والفيديو معًا)، فإن Asterisk ما زال يتعامل معها بقناة واحدة لكل طرف من أطراف المكالمة. وفي الشكل 1.2، حيث توجد قناتان للهاتفين A و B، يتحمل الجسر مسؤولية تمرير الوسائط القادمة من الهاتف A إلى الهاتف B، وكذلك تمرير الوسائط القادمة من الهاتف B إلى الهاتف A. وتتم مفاوضة جميع تدفقات الوسائط عبر Asterisk. ولا يُسمح بأي شيء لا يفهمه Asterisk ولا يسيطر عليه تحكمًا كاملًا. وهذا يعني أن Asterisk قادر على التسجيل، ومعالجة الصوت، والترجمة بين التقنيات المختلفة.

عند جسر قناتين معًا، هناك طريقتان يمكن استخدامهما لتحقيق ذلك: الجسر العام (generic bridging) والجسر الأصلي (native bridging). والجسر العام هو جسر يعمل بغض النظر عن تقنيات القنوات المستخدمة. فهو يمرر كل الصوت والإشارات عبر واجهات القنوات التجريدية في Asterisk. ورغم أن هذه أكثر طرق الجسر مرونة، فهي أيضًا الأقل كفاءة بسبب مستويات التجريد اللازمة لإنجاز المهمة. ويوضّح الشكل 1.2 جسرًا عامًا.

أما الجسر الأصلي فهو طريقة خاصة بتقنية بعينها لربط القنوات ببعضها. فإذا كانت قناتان متصلتان بـ Asterisk باستخدام تقنية نقل وسائط واحدة، فقد توجد طريقة لربطهما تكون أكفأ من المرور عبر طبقات التجريد الموجودة في Asterisk والمصمَّمة لربط التقنيات المختلفة ببعضها. فمثلًا، إذا استُخدمت أجهزة متخصصة للاتصال بشبكة الهاتف، فقد يكون من الممكن جسر القنوات على مستوى الأجهزة بحيث لا تضطر الوسائط إلى الصعود عبر التطبيق إطلاقًا. وفي حالة بعض بروتوكولات VoIP، من الممكن أن تُرسل نقاطُ الطرف تدفّقات وسائطها إلى بعضها مباشرة، بحيث لا يظلّ تمرير سوى معلومات إشارات المكالمة عبر الخادم.

يتَّخذ القرار بين الجسر العام والجسر الأصلي عبر مقارنة القناتين عند حان وقت جسرهما. فإذا أفادت كلتا القناتين بأنهما تدعمان طريقة الجسر الأصلي نفسها، فستُستخدم تلك الطريقة. وإلا فستُستخدم طريقة الجسر العام. ولتحديد ما إذا كانت قناتان تدعمان طريقة الجسر الأصلي نفسها، يُستخدم مقارنة بسيطة لمؤشر دالة بلغة C. ومن المؤكد أنه ليس أكثر الطرق أناقة، لكننا لم نواجه حتى الآن أي حالة لم يكن فيها كافيًا لاحتياجاتنا. أما توفير دالة جسر أصلي لقناة فستتم مناقشته بمزيد من التفصيل في القسم 1.2. ويوضّح الشكل 1.3 مثالًا على جسر أصلي.

مثال على جسر أصلي

الشكل 1.3: مثال على جسر أصلي

1.1.3. الإطارات

يتم الاتصال ضمن شيفرة Asterisk أثناء المكالمة عبر استخدام الإطارات (frames)، وهي نسخ (instances) من بنية البيانات ast_frame. وقد تكون الإطارات إما وسائط أو إشارات. وخلال مكالمة هاتفية أساسية، يمرّ عبر النظام تدفّق من إطارات الوسائط التي تحمل الصوت. وتُستخدم إطارات الإشارات لإرسال رسائل حول أحداث إشارات المكالمة، مثل ضغط زر، أو وضع مكالمة في الانتظار، أو قطع مكالمة.

قائمة أنواع الإطارات المتاحة معرَّفة بشكل ثابت. وتُوسم الإطارات بنوع فرعي مُرمَّز رقميًا. ويمكن العثور على القائمة الكاملة في الشيفرة المصدرية في include/asterisk/frame.h؛ ومن أمثلتها:

  • VOICE: تحمل هذه الإطارات جزءًا من تدفق صوتي.
  • VIDEO: تحمل هذه الإطارات جزءًا من تدفق فيديو.
  • MODEM: الترميز المستخدم للبيانات في هذا الإطار، مثل T.38 لإرسال الفاكس عبر الإنترنت. والاستخدام الأساسي لهذا النوع من الإطارات هو التعامل مع الفاكس. ومن المهم ألّا تُترك إطارات البيانات دون أي مساس كي يتم فك ترميز الإشارة بنجاح عند الطرف الآخر. وهذا يختلف عن إطارات AUDIO، لأنه في تلك الحالة يُقبل التحويل إلى مرمِّزات صوتية أخرى لتوفير النطاق الترددي على حساب جودة الصوت.
  • CONTROL: رسالة إشارات المكالمة التي يشير إليها هذا الإطار. وتُستخدم هذه الإطارات للإشارة إلى أحداث إشارات المكالمة. وتشمل هذه الأحداث الرد على الهاتف، أو قطع المكالمة، أو وضعها في الانتظار، إلخ.
  • DTMF_BEGIN: أي رقم بدأ للتو. يُرسَل هذا الإطار عندما يضغط المتصل على مفتاح DTMF[2] على هاتفه.
  • DTMF_END: أي رقم انتهى للتو. يُرسَل هذا الإطار عندما يتوقف المتصل عن الضغط على مفتاح DTMF على هاتفه.

1.2. تجريدات مكوّنات Asterisk

Asterisk تطبيق معياري بدرجة عالية (modular). وهناك تطبيق نواة يُبنى من الشيفرة المصدرية الموجودة في المجلد main/ ضمن شجرة المصدر. غير أنه ليس مفيدًا جدًا بمفرده. فتعمل تطبيق النواة في المقام الأول كسجلّ وحدات (module registry). كما يحتوي على شيفرة تعرف كيفية وصل جميع الواجهات التجريدية ببعضها لتشغيل المكالمات الهاتفية. وتُسجَّل التطبيقات الملموسة لهذه الواجهات بواسطة وحدات قابلة للتحميل في وقت التشغيل.

افتراضيًا، تُحمَّل جميع الوحدات الموجودة في مجلد وحدات Asterisk محدَّد مسبقًا على نظام الملفات عند بدء التطبيق الرئيسي. وقد اختُير هذا النهج لبساطته. غير أنه يوجد ملف إعدادات يمكن تحديثه لتحديد أي الوحدات تُحمَّل بالضبط وبأي ترتيب تُحمَّل. وهذا يجعل الإعداد أكثر تعقيدًا قليلًا، لكنه يتيح القدرة على تحديد أن الوحدات غير اللازمة لا ينبغي تحميلها. والفائدة الأساسية هي تقليل البصمة الذاكرية (memory footprint) للتطبيق. غير أنه توجد أيضًا بعض الفوائد الأمنية. فمن الأفضل ألّا تُحمَّل وحدة تقبل اتصالات عبر الشبكة إذا لم تكن مطلوبة فعلًا.

عند تحميل الوحدة، فإنها تسجّل جميع تنفيذاتها لتجريدات المكوّنات لدى تطبيق نواة Asterisk. وهناك أنواع عديدة من الواجهات يمكن للوحدات تنفيذها وتسجيلها مع نواة Asterisk. ويُسمح للوحدة بتسجيل أي عدد من هذه الواجهات المختلفة كما تشاء. وعلى نحو عام، تُجمَّع الوظائف المترابطة في وحدة واحدة.

1.2.1. مُشغِّلات القنوات

واجهة مشغّل القنوات في Asterisk هي أكثر الواجهات تعقيدًا وأهميتها. وتوفّر واجهة برمجة تطبيقات القنوات في Asterisk تجريد بروتوكول الهاتف، ما يتيح لجميع ميزات Asterisk الأخرى أن تعمل بمعزل عن بروتوكول الهاتف المستخدم. وهذا المكوّن مسؤول عن الترجمة بين تجريد القنوات في Asterisk وبين تفاصيل تقنية الهاتف التي ينفّذها.

يُسمّى تعريف واجهة مشغّل القنوات في Asterisk بواجهة ast_channel_tech. وهي تحدد مجموعة من الدوال التي يجب على مشغّل القنوات تنفيذها. وأول دالة يجب على مشغّل القنوات تنفيذها هي دالة مصنع ast_channel، وهي الدالة requester في ast_channel_tech. وعندما تُنشأ قناة Asterisk، سواء لمكالمة هاتفية واردة أو صادرة، فإن تنفيذ ast_channel_tech المرتبط بنوع القناة المطلوب مسؤول عن إنشاء ast_channel وتهيئته لتلك المكالمة.

بمجرد إنشاء ast_channel، يصبح لديه مرجع إلى ast_channel_tech التي أنشأته. وهناك عمليات عديدة أخرى يجب معالجتها بطريقة خاصة بكل تقنية. وعندما يجب تنفيذ تلك العمليات على ast_channel، تُؤجَّل معالجة العملية إلى الدالة المناسبة من ast_channel_tech. ويعرض الشكل 1.2 قناتين في Asterisk. والشكل 1.4 يتوسّع في ذلك لعرض قناتين مُجسَّرتين وكيف تتّسع تنفيذات تقنية القنوات في الصورة.

تقنية القنوات وطبقات القنوات التجريدية

الشكل 1.4: تقنية القنوات وطبقات القنوات التجريدية

أهم الدوال في ast_channel_tech هي:

  • requester: يُستخدم هذا الاستدعاء (callback) لطلب من مشغّل القنوات أن ينشئ كائن ast_channel ويهيئه بما يلائم نوع هذه القناة.
  • call: يُستخدم هذا الاستدعاء لبدء مكالمة صادرة إلى نقطة الطرف التي يمثّلها ast_channel.
  • answer: تُستدعى عندما يقرّر Asterisk أنه يجب عليه الرد على المكالمة الواردة المرتبطة بهذا ast_channel.
  • hangup: تُستدعى عندما يحدّد النظام أن المكالمة يجب قطعها. عندئذ يبلّغ مشغّل القنوات نقطة الطرف بأن المكالمة انتهت بطريقة خاصة بالبروتوكول.
  • indicate: بمجرد إقامة المكالمة، هناك عدد من الأحداث الأخرى التي قد تحدث وتحتاج إلى إخبار نقطة الطرف بها. فمثلًا، إذا وُضع الجهاز في وضع الانتظار، تُستدعى هذه الدالة للإشارة إلى تلك الحالة. وقد تكون هناك طريقة خاصة بالبروتوكول للإشارة إلى أن المكالمة كانت في وضع الانتظار، أو قد يقوم مشغّل القنوات ببساطة بتشغيل الموسيقى المخصَّصة للانتظار على الجهاز.
  • send_digit_begin: تُستدعى هذه الدالة للإشارة إلى بداية إرسال رقم (DTMF) إلى هذا الجهاز.
  • send_digit_end: تُستدعى هذه الدالة للإشارة إلى نهاية إرسال رقم (DTMF) إلى هذا الجهاز.
  • read: تُستدعى هذه الدالة من نواة Asterisk لقراءة ast_frame من نقطة الطرف هذه. وast_frame هو تجريد في Asterisk يُستخدم لتغليف الوسائط (مثل الصوت أو الفيديو)، فضلًا عن الإشارة إلى الأحداث.
  • write: تُستخدم هذه الدالة لإرسال ast_frame إلى هذا الجهاز. وسيأخذ مشغّل القنوات البيانات ويحزّمها في حزم بما يلائم بروتوكول الهاتف الذي ينفّذه، ثم يمرّرها إلى نقطة الطرف.
  • bridge: هذه هي دالة الاستدعاء الخاصة بالجسر الأصلي لهذا النوع من القنوات. فكما نُوقش سابقًا، يكون الجسر الأصلي هو الحالة التي يتمكّن فيها مشغّل القنوات من تنفيذ طريقة جسر أكفأ لقناتين من النوع نفسه، بدلًا من تمرير كل الإشارات والوسائط عبر طبقات تجريد إضافية غير ضرورية. وهذا مهم للغاية لأسباب تتعلق بالأداء.

بمجرد انتهاء المكالمة، ستستدعي شيفرة معالجة القنوات التجريدية الموجودة في نواة Asterisk الاستدعاء ast_channel_tech hangup ثم تُتلف كائن ast_channel.

1.2.2. تطبيقات خطة الاتصال

يضبط مديرو Asterisk توجيه المكالمات باستخدام خطة اتصال Asterisk، الموجودة في الملف /etc/asterisk/extensions.conf. وتتكون خطة الاتصال من سلسلة من قواعد المكالمات المسماة الامتدادات (extensions). وعندما تصل مكالمة هاتفية إلى النظام، يُستخدم الرقم المُطلب للعثور على الامتداد في خطة الاتصال الذي ينبغي استخدامه لمعالجة المكالمة. ويشمل الامتداد قائمة من تطبيقات خطة الاتصال التي ستُنفَّذ على القناة. أما التطبيقات المتاحة للتنفيذ في خطة الاتصال فتُحفظ في سجل تطبيقات. ويُملأ هذا السجل في وقت التشغيل مع تحميل الوحدات.

يضم Asterisk ما يقارب مئتي تطبيق مضمَّنة. وتعريف التطبيق فضفِيّ ومرن إلى حد كبير. ويمكن للتطبيقات استخدام أي من واجهات برمجة تطبيقات Asterisk الداخلية للتفاعل مع القناة. فبعض التطبيقات تنفّذ مهمة واحدة، مثل Playback الذي يشغّل ملفًا صوتيًا للمتصل. وهناك تطبيقات أخرى أكثر تعقيدًا بكثير وتنفّذ عددًا كبيرًا من العمليات، مثل تطبيق Voicemail.

باستخدام خطة اتصال Asterisk، يمكن استخدام تطبيقات متعددة معًا لتخصيص معالجة المكالمات. وإذا لزم تخصيص أكثر شمولًا يتجاوز ما يمكن إنجازه في لغة خطة الاتصال المتاحة، فهناك واجهات برمجة نصية (scripting) تتيح تخصيص معالجة المكالمات باستخدام أي لغة برمجة. وحتى عند استخدام واجهات البرمجة النصية هذه مع لغة برمجة أخرى، فإن تطبيقات خطة الاتصال لا تزال تُستدعى للتفاعل مع القناة.

قبل أن ندخل في مثال، فلننظر في صياغة خطة اتصال Asterisk التي تتعامل مع المكالمات الموجَّهة إلى الرقم 1234. ولاحظ أن اختيار 1234 هنا اعتباطي. فهي تستدعي ثلاثة تطبيقات من تطبيقات خطة الاتصال. أولًا، ترد على المكالمة. ثم تشغّل ملفًا صوتيًا. وأخيرًا، تقطع المكالمة.

; Define the rules for what happens when someone dials 1234.
;
exten => 1234,1,Answer()
    same => n,Playback(demo-congrats)
    same => n,Hangup()

تُستخدم الكلمة المفتاحية exten لتعريف الامتداد. وعلى يمين سطر exten، يعني 1234 أننا نعرّف القواعد الخاصة بما يحدث عندما يتصل أحدهم بالرقم 1234. ويعني 1 التالية أن هذه هي الخطوة الأولى التي تُتَّخذ عند طلب هذا الرقم. وأخيرًا، توجّه Answer النظام إلى الرد على المكالمة. أما السطران التاليان اللذان يبدأان بالكلمة المفتاحية same فهما قاعدتان للامتداد الأخير الذي حُدِّد، وهو في هذه الحالة 1234. وn اختصار لقول إن هذه هي الخطوة التالية الواجب اتخاذها. ويحدد العنصر الأخير في تلك السطور الإجراء الواجب اتخاذه.

إليك مثالًا آخر على استخدام خطة اتصال Asterisk. في هذه الحالة، يُرد على مكالمة واردة. ويُشغَّل للمتصل نغمة تنبيه، ثم تُقرأ منه حتى 4 أرقام وتُخزَّن في المتغير DIGITS. ثم تُقرأ الأرقام مرة أخرى إلى المتصل. وأخيرًا، تنتهي المكالمة.

exten => 5678,1,Answer()
    same => n,Read(DIGITS,beep,4)
    same => n,SayDigits(${DIGITS})
    same => n,Hangup()

كما ذُكر سابقًا، فإن تعريف التطبيق فضفِيّ ومرن إلى حد كبير—النموذج الأولي (prototype) للدالة المسجَّلة بسيط جدًا:

int (*execute)(struct ast_channel *chan, const char *args);

غير أن تنفيذات هذه التطبيقات تستغل فعليًا جميع واجهات برمجة التطبيقات الموجودة في include/asterisk/.

1.2.3. دوال خطة الاتصال

تأخذ معظم تطبيقات خطة الاتصال سلسلة من الوسائط. ورغم أن بعض القيم قد تكون مكتوبة بشكل ثابت (hard coded)، فإن المتغيرات تُستخدم في المواضع التي تحتاج فيها السلوك إلى أن يكون أكثر ديناميكية. ويعرض المثال التالي مقطعًا من خطة الاتصال يُعيِّن متغيرًا ثم يطبع قيمته إلى واجهة سطر الأوامر في Asterisk باستخدام تطبيق Verbose.

exten => 1234,1,Set(MY_VARIABLE=foo)
    same => n,Verbose(MY_VARIABLE is ${MY_VARIABLE})

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

يوضح المثال التالي استخدام دالة من دوال خطة الاتصال. أولًا، يطبع قيمة CallerID الخاصة بالقناة الحالية إلى واجهة سطر الأوامر في Asterisk. ثم يغيّر CallerID باستخدام تطبيق Set. وفي هذا المثال، Verbose وSet تطبيقات، بينما CALLERID دالة.

exten => 1234,1,Verbose(The current CallerID is ${CALLERID(num)})
    same => n,Set(CALLERID(num)=<256>555-1212)

نحتاج هنا إلى دالة من دوال خطة الاتصال بدل متغير بسيط فقط، لأن معلومات CallerID مخزَّنة في بنى بيانات على نسخة ast_channel التي تمثّل القناة. وشيفرة دالة خطة الاتصال تعرف كيفية ضبط قيم هذه البنى واسترجاعها.

من الأمثلة الأخرى على استخدام دالة من دوال خطة الاتصال، إضافة معلومات مخصَّصة إلى سجلات المكالمات، والمشار إليها بـ CDRs (سجلات تفاصيل المكالمات). وتتيح الدالة CDR استرجاع معلومات سجل تفاصيل المكالمة، فضلًا عن إضافة معلومات مخصَّصة.

exten => 555,1,Verbose(Time this call started: ${CDR(start)})
    same => n,Set(CDR(mycustomfield)=snickerdoodle)

1.2.4. مُحوِّلات الترميز

في عالم VOIP، تُستخدم مرمِّزات (codecs) متعددة لترميز الوسائط المُرسلة عبر الشبكات. ويقدّم تنوّع هذه الخيارات مقايضات بين جودة الوسائط واستهلاك المعالج (CPU) ومتطلبات النطاق الترددي. ويدعم Asterisk مرمِّزات عديدة مختلفة ويعرف كيفية الترجمة بينها عند الحاجة.

عند إعداد مكالمة، سيحاول Asterisk دفع نقطتي الطرف إلى استخدام مرمِّز وسائط مشترك حتى لا تكون إعادة الترميز مطلوبة. غير أن ذلك ليس ممكنًا دائمًا. وحتى إذا كان مرمِّز مشترك قيد الاستخدام، فقد تظل إعادة الترميز مطلوبة. فمثلًا، إذا كان Asterisk مُهيَّأ لإجراء بعض معالجة الإشارات على الصوت أثناء مروره عبر النظام (مثلًا لزيادة مستوى الصوت أو خفضه)، فسيحتاج Asterisk إلى إعادة ترميز الصوت إلى صيغة غير مضغوطة قبل أن يتمكّن من إجراء معالجة الإشارات. ويمكن أيضًا تهيئة Asterisk لإجراء تسجيل للمكالمات. فإذا اختلفت صيغة التسجيل المُهيَّأة عن صيغة المكالمة، فستكون إعادة الترميز مطلوبة.

تفاوض الترميز

الطريقة المستخدمة والتفاوض على المرمِّز الذي سيُستخدم لتدفّق وسائط تعتمد على التقنية المستخدمة في ربط المكالمة بـ Asterisk. ففي بعض الحالات، مثل مكالمة على شبكة الهاتف التقليدية (PSTN)، قد لا يكون هناك أي تفاوض لإجرائه. غير أن في حالات أخرى، ولا سيما عند استخدام بروتوكولات الإنترنت، هناك آلية تفاوض تُستخدم للتعبير عن القدرات والتفضيلات والاتفاق على مرمِّز مشترك.

على سبيل المثال، في حالة SIP (أكثر بروتوكولات VOIP شيوعًا)، إليك نظرة عامة على كيفية إجراء تفاوض المرمِّز عندما تُرسَل مكالمة إلى Asterisk.

  1. ترسل نقطة الطرف طلب مكالمة جديدًا إلى Asterisk يتضمن قائمة المرمِّزات التي توافق على استخدامها.
  2. يستشير Asterisk إعداداته التي وفّرها المدير، والتي تتضمن قائمة بالمرمِّزات المسموح بها بالترتيب المفضَّل. ويستجيب Asterisk باختيار المرمِّز الأكثر تفضيلًا (استنادًا إلى تفضيلاته المُهيَّأة) والمدرَج ضمن المسموح به في إعدادات Asterisk على أنه مدعوم أيضًا في الطلب الوارد.

أحد المجالات التي لا يتعامل معها Asterisk جيدًا هو المرمِّزات الأكثر تعقيدًا، ولا سيما الفيديو. فقد أصبحت متطلبات تفاوض المرمِّزات أكثر تعقيدًا خلال العشر سنوات الماضية. ولدينا المزيد من العمل لنتمكن من التعامل بشكل أفضل مع أحدث المرمِّزات الصوتية ومن دعم الفيديو بصورة أفضل بكثير مما نفعله اليوم. وهذه إحدى أعلى الأولويات في التطوير الجديد للإصدار الرئيسي القادم من Asterisk.

تقدّم وحدات مُحوِّل الترميز تنفيذًا واحدًا أو أكثر لواجهة ast_translator. ويمتلك المترجم (translator) سمات للصيغة المصدرية وصيغة الوجهة. كما يوفّر استدعاءً (callback) يُستخدم لتحويل جزء من الوسائط من الصيغة المصدرية إلى صيغة الوجهة. وهو لا يعرف شيئًا عن مفهوم المكالمة الهاتفية. فهو لا يعرف سوى كيفية تحويل الوسائط من صيغة إلى أخرى.

لمزيد من المعلومات التفصيلية حول واجهة برمجة تطبيقات المترجم، راجع include/asterisk/translate.h وmain/translate.c. ويمكن العثور على تنفيذات تجريد المترجم في المجلد codecs.

1.3. الخيوط

Asterisk تطبيق كثيف الخيوط إلى حد بعيد. فهو يستخدم واجهة برمجة تطبيقات الخيوط في POSIX لإدارة الخيوط والخدمات المرتبطة بها مثل الأقفال (locking). وكل شيفرة Asterisk التي تتفاعل مع الخيوط تفعل ذلك عبر مجموعة من الأغلاف (wrappers) المستخدمة لأغراض التشخيص (debugging). ويمكن تصنيف معظم خيوط Asterisk إما كخيط مراقبة شبكة (Network Monitor Thread) أو كخيط قناة (Channel Thread) (ويُشار إليه أحيانًا أيضًا باسم خيط PBX، لأن غرضه الأساسي هو تشغيل PBX لقناة ما).

1.3.1. خيوط مراقبة الشبكة

توجد خيوط مراقبة الشبكة في كل مشغّل قنوات رئيسي في Asterisk. وهي مسؤولة عن مراقبة الشبكة التي تتصل بها (سواء كانت شبكة إنترنت أو PSTN أو غير ذلك)، ومراقبة المكالمات الواردة أو أنواع أخرى من الطلبات الواردة. وهي تتولى خطوات الاتصال الأولية مثل المصادقة والتحقق من الرقم المُطلب. وبمجرد اكتمال إعداد المكالمة، ستنشئ خيوط المراقبة نسخة (instance) من قناة Asterisk (ast_channel)، وتبدأ خيط قناة للتعامل مع المكالمة طوال ما تبقّى من مدتها.

1.3.2. خيوط القنوات

كما نوقش سابقًا، القناة مفهوم أساسي في Asterisk. والقنوات إما واردة أو صادرة. ويُنشأ القناة الواردة عندما تصل مكالمة إلى نظام Asterisk. وهذه القنوات هي التي تنفّذ خطة اتصال Asterisk. ويُنشأ خيط لكل قناة واردة تنفّذ خطة الاتصال. ويُشار إلى هذه الخيوط باسم خيوط القنوات.

تُنفَّذ تطبيقات خطة الاتصال دائمًا في سياق خيط القناة. وتُنفَّذ دوال خطة الاتصال تقريبًا دائمًا كذلك. ومن الممكن قراءة دوال خطة الاتصال وكتابتها من واجهة غير متزامنة مثل واجهة سطر الأوامر في Asterisk. غير أن خيط القناة يظل دائمًا هو المالك لبنية البيانات ast_channel وهو المتحكم في عمر الكائن.

1.4. سيناريوهات المكالمات

قدَّمت القسمان السابقان واجهات مهمة لمكوّنات Asterisk، فضلًا عن نموذج تنفيذ الخيوط. وفي هذا القسم، يُفكَّك بعض سيناريوهات المكالمات الشائعة لبيان كيف تعمل مكوّنات Asterisk معًا لمعالجة المكالمات الهاتفية.

1.4.1. الاستماع إلى البريد الصوتي

أحد أمثلة سيناريوهات المكالمات هو عندما يتصل أحدهم بنظام الهاتف للاستماع إلى بريده الصوتي. وأول مكوّن رئيسي يشارك في هذا السيناريو هو مشغّل القنوات. وسيكون مشغّل القنوات مسؤولًا عن التعامل مع طلب المكالمة الواردة من الهاتف، وهو ما سيحدث في خيط المراقبة الخاص به. وبحسب تقنية الهاتف المستخدمة لإيصال المكالمة إلى النظام، قد يلزم إجراء نوع من التفاوض لإعداد المكالمة. ومن خطوات إعداد المكالمة أيضًا تحديد الوجهة المقصودة للمكالمة. وعادة ما يحدّدها الرقم الذي طلبه المتصل. غير أنه في بعض الحالات لا يتوفر رقم محدَّد لأن التقنية المستخدمة لإيصال المكالمة لا تدعم تحديد الرقم المطلوب. ومن أمثلة ذلك مكالمة واردة على خط هاتف تماثلي.

إذا تحقّق مشغّل القنوات من أن إعدادات Asterisk تحتوي على امتدادات معرَّفة في خطة الاتصال (إعدادات توجيه المكالمات) للرقم المطلوب، فإنه سيقوم عندئذ بتخصيص كائن قناة Asterisk (ast_channel) وإنشاء خيط قناة. ويتولى خيط القناة المسؤولية الأساسية عن التعامل مع بقية المكالمة (الشكل 1.5).

مخطط تسلسل إعداد المكالمة

الشكل 1.5: مخطط تسلسل إعداد المكالمة

تتعامل الحلقة الرئيسية في خيط القناة مع تنفيذ خطة الاتصال. فهي تنتقل إلى القواعد المعرَّفة للامتداد المطلوب وتنفّذ الخطوات التي حُدِّدت. وفيما يلي مثال على امتداد معبَّر عنه بصياغة خطة الاتصال extensions.conf. يرد هذا الامتداد على المكالمة وينفّذ تطبيق VoicemailMain عندما يتصل أحدهم بالرقم *123. وهذا التطبيق هو ما يتصل به المستخدم كي يتمكّن من الاستماع إلى الرسائل المتروكة في صندوق بريده.

exten => *123,1,Answer()
    same => n,VoicemailMain()

عندما ينفّذ خيط القناة تطبيق Answer، سيرد Asterisk على المكالمة الواردة. ويتطلب الرد على مكالمة معالجة خاصة بالتقنية، لذا إلى جانب بعض المعالجة العامة للرد، تُستدعى الدالة answer في البنية ast_channel_tech المرتبطة للتعامل مع الرد على المكالمة. وقد ينطوي ذلك على إرسال حزمة خاصة عبر شبكة إنترنت، أو رفع خط تماثلي من الخطّاف (off hook)، إلخ.

الخطوة التالية هي أن ينفّذ خيط القناة VoicemailMain (الشكل 1.6). ويوفّر هذا التطبيق الوحدة app_voicemail. ومن الأمور المهمة ملاحظتها أن شيفرة البريد الصوتي، رغم تعاملها مع قدر كبير من تفاعلات المكالمة، لا تعرف شيئًا عن التقنية المستخدمة لإيصال المكالمة إلى نظام Asterisk. فتجريد قناة Asterisk يخفي هذه التفاصيل عن تنفيذ البريد الصوتي.

هناك ميزات عديدة مشمولة في توفير وصول المتصل إلى بريده الصوتي. غير أن جميعها منفذ أساسًا في قراءة ملفات صوتية وكتابتها استجابةً لمدخلات المتصل، ولا سيما في صورة ضغطات المفاتيح. ويمكن تسليم أرقام DTMF إلى Asterisk بطرق عديدة مختلفة. ومرة أخرى، تُتعامل هذه التفاصيل بواسطة مشغّلات القنوات. وبمجرد وصول ضغطة مفتاح إلى Asterisk، تُحوَّل إلى حدث ضغط مفتاح عام ثم تُمرَّر إلى شيفرة البريد الصوتي.

من أهم الواجهات في Asterisk التي ناقشناها هي واجهة مُحوِّل الترميز. وهذه التنفيذات للمُحوِّلات مهمة جدًا لسيناريو المكالمة هذا. فعندما تريد شيفرة البريد الصوتي تشغيل ملف صوتي للمتصل، فقد لا تكون صيغة الصوت في الملف الصوتي مطابقة للصيغة المستخدمة في الاتصال بين نظام Asterisk والمتصل. وإذا تطلّب الأمر إعادة ترميز الصوت، فسيبني مسار ترجمة من مُحوِّل ترميز واحد أو أكثر للانتقال من الصيغة المصدرية إلى صيغة الوجهة.

مكالمة إلى VoicemailMain

الشكل 1.6: مكالمة إلى VoicemailMain

في مرحلة ما، سينتهي المتصل من التفاعل مع نظام البريد الصوتي ويقطع المكالمة. وسيكتشف مشغّل القنوات حدوث ذلك ويحوّله إلى حدث إشارة قناة عام في Asterisk. وستستقبل شيفرة البريد الصوتي حدث الإشارة هذا وتخرج، إذ لا يبقى شيء يمكن فعله بمجرد أن يقطع المتصل المكالمة. وستعود السيطرة إلى الحلقة الرئيسية في خيط القناة لمتابعة تنفيذ خطة الاتصال. وبما أنه لا توجد معالجة إضافية لخطة الاتصال في هذا المثال، فسيُتاح إلى مشغّل القنوات فرصة للتعامل مع المعالجة الخاصة بالتقنية عند قطع المكالمة، ثم يُتلف كائن ast_channel.

1.4.2. مكالمة مُجسَّرة

من سيناريوهات المكالمات الشائعة جدًا في Asterisk هي مكالمة مُجسَّرة بين قناتين. وهذا هو السيناريو الذي يتصل فيه هاتف بآخر عبر النظام. وعملية إعداد المكالمة الأولية مطابقة تمامًا للمثال السابق. ويبدأ اختلاف التعامل عندما تُعدّ المكالمة ويبدأ خيط القناة في تنفيذ خطة الاتصال.

خطة الاتصال التالية مثال بسيط ينتج عنه مكالمة مُجسَّرة. وباستخدام هذا الامتداد، عندما يتصل هاتف بالرقم 1234، ستنفّذ خطة الاتصال تطبيق Dial، وهو التطبيق الرئيسي المستخدم لبدء مكالمة صادرة.

exten => 1234,1,Dial(SIP/bob)

تشير الوسائط المُمرَّرة إلى تطبيق Dial إلى أن على النظام إجراء مكالمة صادرة إلى الجهاز المشار إليه بـ SIP/bob. ويحدد الجزء SIP من هذه الوسائط أن بروتوكول SIP ينبغي أن يُستخدم لإيصال المكالمة. وسيُفسَّر bob بواسطة مشغّل القنوات الذي ينفّذ بروتوكول SIP، وهو chan_sip. وبافتراض أنه أُعدّ مشغّل القنوات بصورة صحيحة مع حساب اسمه bob، فسيعرف كيفية الوصول إلى هاتف Bob.

سيطلب تطبيق Dial من نواة Asterisk تخصيص قناة Asterisk جديدة باستخدام المعرّف SIP/bob. وستطلب النواة من مشغّل القنوات SIP إجراء التهيئة الخاصة بالتقنية. وسيبدأ مشغّل القنوات أيضًا عملية إجراء مكالمة إلى الهاتف. ومع تقدّم الطلب، ستُعاد الأحداث إلى نواة Asterisk، حيث يستلمها تطبيق Dial. وقد تشمل هذه الأحداث استجابة تفيد بأنه قُد رُدَّ على المكالمة، أو أن الوجهة مشغولة، أو أن الشبكة مزدحمة، أو أنه رُفضت المكالمة لسبب ما، أو عددًا من الاستجابات الممكنة الأخرى. وفي الحالة المثلى، سيتم الرد على المكالمة. ويُنشر حدوث الرد على المكالمة مجددًا إلى القناة الواردة. ولن يرد Asterisk على الجزء الذي دخل النظام من المكالمة حتى ترد على المكالمة الصادرة. وبمجرد الرد على القناتين، يبدأ جسر القنوات (الشكل 1.7).

مخطط كتلي لمكالمة مُجسَّرة في جسر عام

الشكل 1.7: مخطط كتلي لمكالمة مُجسَّرة في جسر عام

أثناء جسر القناة، تُمرَّر أحداث الصوت والإشارات من قناة إلى الأخرى حتى يقع حدث ما يسبب انتهاء الجسر، مثل قطع أحد طرفي المكالمة. ويبيّن مخطط التسلسل في الشكل 1.8 العمليات الرئيسية التي تُنفَّذ لإطار صوتي أثناء مكالمة مُجسَّرة.

مخطط تسلسل لمعالجة الإطار الصوتي أثناء الجسر

الشكل 1.8: مخطط تسلسل لمعالجة الإطار الصوتي أثناء الجسر

بمجرد انتهاء المكالمة، تكون عملية قطع الاتصال مشابهة جدًا للمثال السابق. والفرق الرئيسي هنا هو وجود قناتين مشاركتين. وستُنفَّذ المعالجة الخاصة بقطع الاتصال والتعلقة بتقنية القناة لكلتا القناتين قبل أن يتوقف خيط القناة عن العمل.

1.5. خاتمة

أصبح عمر معمارية Asterisk أكثر من عشر سنوات. غير أن المفاهيم الأساسية للقنوات ولمعالجة المكالمات المرنة باستخدام خطة اتصال Asterisk ما زالت تدعم تطوير أنظمة هاتفية معقدة في قطاع لا يتوقف عن التطور. وأحد المجالات التي لا تتعامل معها بنية Asterisk جيدًا هو توسيع النظام ليشمل عدة خوادم. ويعمل مجتمع تطوير Asterisk حاليًا على مشروع مصاحب اسمه Asterisk SCF (إطار عمل الاتصالات القابل للتوسّع)، والمقصود به معالجة هذه المخاوف على صعيد قابلية التوسّع.

ويُتوقَّع أن نرى خلال السنوات القليلة القادمة Asterisk، إلى جانب Asterisk SCF، يواصل السيطرة على أجزاء كبيرة من سوق الهاتف، بما في ذلك المنشآت الأكبر بكثير.

الحواشي

  1. http://www.asterisk.org/
  2. DTMF اختصار لعبارة Dual-Tone Multi-Frequency. وهي النغمة التي تُرسَل في صوت مكالمة هاتفية عندما يضغط أحدهم على مفتاح في هاتفه.

  1. http://www.asterisk.org/ ↩︎

  2. DTMF اختصار لعبارة Dual-Tone Multi-Frequency. وهي النغمة التي تُرسَل في صوت مكالمة هاتفية عندما يضغط أحدهم على مفتاح في هاتفه. ↩︎