تحقق قنوات FAST الإيرادات من الفواصل الإعلانية. يعتمد نموذج العمل بأكمله على افتراض واحد: عندما تقول القناة "انتقل إلى الإعلان،" فإن كل نظام تابع يستمع — خادم الإعلانات، أداة الربط SSAI، مشغل التلفزيون الذكي — يسمع ذلك في نفس اللحظة تمامًا، وبنفس المدة بالضبط. SCTE-35 هو البروتوكول القياسي الذي يحمل هذه الرسالة. إذا حدث خطأ بصمت — والصمت هو وضع الفشل الافتراضي — فإن الإعلانات إما لا تُعرض، أو تُشغل في الإطار الخطأ، أو تستمر لمدة خاطئة. يرى المشاهد شاشة سوداء. ببساطة، الإيرادات لا تتحقق.
هذه هي القصة الهندسية لكيفية إصدار قنوات FAST في mStudio لإشارات SCTE-35 المتوافقة مع المعايير من مدخلات سهلة للمشغل، ولماذا قمنا ببنائها على أنها ثلاث إشارات لكل فاصل بدلاً من واحدة.
نظرة عامة سريعة
| الجانب | التفاصيل |
|---|---|
| النطاق | إشارات SCTE-35 للفواصل الإعلانية لقنوات AWS MediaLive FAST |
| سير عمل المشغل | محرر فواصل إعلانية لكل برنامج — الموضع بالثواني، المدة بالثواني |
| الإشارات الصادرة لكل فاصل | ثلاث — بداية إعلان TimeSignal، و SpliceInsert، ونهاية إعلان TimeSignal |
| قيود المدة | 10–120 ثانية، يتم التحقق منها في طبقة البيانات |
| المستهلكون اللاحقون | المشغلات، وخوادم الإعلانات، و AWS MediaTailor (المصممة ولكن لم يتم ربطها بعد) هي أمثلة. |
| الحالة | إصدار إشارات SCTE-35 قيد الإنتاج؛ دمج SSAI قيد التصميم |
المشكلة التجارية
كل فاصل إعلاني على قناة FAST هو حدث إيرادي. تصدر القناة علامة تقول "سيُعرض إعلان هنا، وسيدوم 30 ثانية، يرجى الاستعداد." تقوم الأنظمة التابعة — مثل Google Ad Manager و AWS MediaTailor وخوادم الإعلانات الإقليمية وحزم SDK لمشغلات التلفزيون الذكية — بقراءة تلك العلامة وتحديد ما سيتم دمجه.
عندما تكون العلامة صحيحة، يُعرض الفاصل الإعلاني بسلاسة، ويتم احتساب مرات الظهور، ويحصل المشغل على الأجر. عندما تكون العلامة خاطئة — مدة خاطئة، شكل خاطئ، تنسيق خاطئ — يقوم نظام الإعلانات إما برفضها (لا يتم عرض إعلان) أو قبولها بشكل غير صحيح (إعلان بمدة خاطئة، أو إعلان يتجاوز مدته إلى البرنامج التالي). كلتا النتيجتين تكلفان أموالاً حقيقية، وكلتاهما تفشلان بصمت. تستمر القناة في البث. يرى المشاهد شاشة سوداء أو قطعًا غير لائق. خط أنابيب تحقيق الدخل ينتج أرقامًا أقل فقط ولا توجد رسالة خطأ للمتابعة.
الهدف الهندسي ليس "دعم الإعلانات". بل هو: يجب أن يصل كل فاصل إعلاني يحدده المشغل إلى كل مستهلك تابع كإشارة SCTE-35 متوافقة مع المعايير، في الإطار المحدد الذي اختاره المشغل، في كل مرة.
ما هو SCTE-35 في الواقع (النسخة المختصرة في 90 ثانية)
SCTE-35 هو معيار لإدراج رسائل الإشارات في بث الفيديو. لا تحمل الإشارات محتوى إعلانيًا؛ بل تحمل إشارات — "يبدأ الفاصل الإعلاني هنا،" "ينتهي الفاصل الإعلاني هنا،" "طول هذا المقطع N ثانية." يقرأ النظام التابع هذه الإشارات ويتصرف بناءً عليها: طبقة SSAI تدمج إعلانًا إبداعيًا حقيقيًا في HLS manifest، يقوم مشغل التلفزيون الذكي بتشغيل تراكب، ويسجل خادم الإعلانات فرصة للإعلان.
شكلان للإشارات مهمان لحالة الاستخدام الخاصة بنا:
- SpliceInsert — إشارة SCTE-35 الأصلية. تحمل SpliceEventId، ومدة بالثواني، وعلامة "خارج الشبكة". تقرأ معظم خوادم الإعلانات الكلاسيكية هذه الإشارة.
- TimeSignal — الإشارة الأحدث والأكثر تعبيرًا. تحمل SegmentationDescriptor مع SegmentationTypeId (52 = بداية إعلان الموفر، 53 = نهاية إعلان الموفر) و SegmentationDuration بوحدات 90,000 تكة. تفضل أنظمة SSAI والمشغلات الحديثة هذا الشكل لأنه يتزاوج بسلاسة بين البداية والنهاية.
كلا الشكلين صحيحان وفق SCTE-35. يفضل المستهلكون اللاحقون المختلفون أشكالًا مختلفة. إصدار شكل واحد فقط يترك إيرادات غير محققة.
لماذا هذا مهم. تطبيق ساذج يصدر إشارة SpliceInsert واحدة لكل فاصل إعلاني ويعتبر الأمر منتهيًا. يعمل الفاصل الإعلاني على المشغلات القديمة ويتعطل بصمت على SSAI. نصف مخزون إعلاناتك يحقق دخلاً؛ ونصفه لا يحقق. لن تعرف أي منهما حتى تأتي أرقام إيراداتك منخفضة.
لماذا تفشل المناهج الساذجة
الاختصارات مغرية لأنها كلها تقريبًا تعمل.
- "أثناء وقت الترميز، أدخل الإعلانات في الفيديو الأصلي." لا يوجد مجال للمرونة. لا يمكن للمشغل اختبار A/B للموضع، ولا يمكنه تغيير الإعلانات بعد النشر، ولا يمكنه تشغيل إعلانات مستهدفة إقليميًا أو للجمهور. السبب الأساسي لوجود قنوات FAST هو تحقيق الدخل من نفس المحتوى بطرق متعددة — وحرق الإعلانات في وقت الترميز يحول دون ذلك.
- "استخدم إدراج الإعلانات من جانب العميل." حجب الإعلانات بسيط. مسار كود مختلف لكل جهاز. لا توجد تخصيصات من جانب الخادم. ويتجاوز SSAI بالكامل، مما يعني انخفاض CPMs.
- "فقط قم بإصدار إشارة SpliceInsert واحدة لكل فاصل." الخطأ الأكثر شيوعًا في الإنتاج. يعمل على بعض المشغلات، ويتجاهله بصمت أنظمة SSAI التي تريد إشارات TimeSignal لربط البداية/النهاية. تحقيق دخل جزئي، دون وجود خطأ للتحقيق فيه.
- "عبر عن كل شيء بوحدات 90 kHz ticks لأن المواصفات تذكرها." المواصفات أكثر إزعاجًا من ذلك. SpliceInsert.Duration تكون بالثواني. أما SegmentationDuration فتكون بوحدات 90 kHz ticks. يؤدي خلطها إلى إنتاج إشارات تجاوز التحقق من المخطط وتُشحن، ثم تفشل عند المشغل كمدد خاطئة التكوين. لن يكتشفها المرمز. سيتجاوز المشغل الفاصل ببساطة.
- "اسمَح لـ MediaLive بالتأكيد." لن يفعل. تقبل MediaLive الفواصل المتداخلة، والفواصل ذات المدة الصفرية، والمدد المستحيلة للتجزئة دون شكوى. يجب أن يتم التأكيد قبل أن يرى MediaLive الإجراء.
المفتاح الذي كان لدينا هو الحدود الفاصلة بين واجهة مستخدم المشغل (UI) — حيث تكون الفواصل الإعلانية مجرد أزواج {position, duration} — وجدول MediaLive، حيث يجب أن تكون كل إشارة مثالية.
حلنا
تعامل مع الفاصل الإعلاني ككائن بيانات من الدرجة الأولى من البداية إلى النهاية. يحدده المشغل بأبسط المصطلحات الممكنة. يتحقق الواجهة الخلفية (backend) منه مرة واحدة في طبقة المخطط. تقوم Lambda بترجمته إلى مجموعة من ثلاث إشارات عند وقت النشر، مع التعبير عن كل إشارة في الأساس الزمني الذي تتطلبه مواصفاتها الخاصة. لا يحتاج أي شيء آخر في المكدس (stack) إلى معرفة SCTE-35 — تعيش الترجمة في دالة واحدة، في نفس Lambda التي تمتلك كل إجراء جدولة آخر.
الرسم التخطيطي 1 · خط أنابيب علامات الإعلان الشامل

البنية
- محرر الفواصل الإعلانية الأمامي (Frontend ad-break editor) — يقوم المشغلون بإضافة فواصل إعلانية لكل برنامج عن طريق تحديد إزاحة الموضع (ثوانٍ من بداية البرنامج) ومدة (ثوانٍ). تعتبر فتحات الإعلانات الترويجية جزءًا من نموذج البيانات وجاهزة لطبقة التشغيل.
- مجموعة AdMarker (MongoDB) — مستند واحد لكل برنامج يحتوي على فواصل إعلانية، يشير إلى الفيديو. تخزن مصفوفة adBreaks[] أزواج {position, duration} مع قيام Mongoose بفرض 10 ≤ duration ≤ 120 عند وقت الحفظ. تحمل الإعلانات الترويجية مرجع adBreakId للاقتران اللاحق.
- الواجهة الخلفية لـ NestJS (schedule.service.ts) — عند وقت النشر، يربط كل جدول بـ AdMarker الخاص به ويعيد تسمية الحقول لتتوافق مع عقد Lambda (position → offsetSeconds، duration → durationSeconds). جلب مجمع واحد، لا يوجد مشكلة N+1.
- منسق Lambda (fastChannel-lambda-fun/index.js) — يمتلك ترجمة SCTE-35. لكل فاصل إعلاني، يصدر مجموعة الإشارات الثلاث إلى نفس BatchUpdateScheduleCommand الذي يحمل مفاتيح الإدخال والعلامات المائية. يتم تحديد إصدار أسماء الإجراءات لكل برنامج بحيث يمكن للمسح اليتيم (orphan sweep) إقرانها بعد نشر جزئي.
- AWS MediaLive — يتلقى الإجراءات، ويصدر علامات #EXT-SCTE35 في HLS manifest في الثانية التي اختارها المشغل.
قرارات هندسية رئيسية
1. ثلاث إشارات لكل فاصل إعلاني، وليست واحدة
يصدر كل فاصل إعلاني ثلاثة إجراءات منفصلة في نفس اللحظة المنطقية في البرنامج.
الرسم التخطيطي 2 · دورة حياة فاصل إعلاني واحد

تتشارك إشارات TimeSignal للبداية والنهاية في SegmentationUpid لتمكين الأنظمة اللاحقة من إقرانها بشكل حتمي. تحمل إشارة SpliceInsert قيمة SpliceEventId فريدة لإزالة التكرار على مستوى المشغل. يقرأ المستهلكون المختلفون إشارات مختلفة. يغطي إصدار الإشارات الثلاث كل عقد نهتم به اليوم وكل عقد محتمل في المستقبل.
خطأ إنتاجي شائع. إصدار إشارة SpliceInsert واحدة وافتراض أن بقية النظام البيئي سيكتشف الأمر. تسقط أنظمة SSAI بصمت الفواصل التي تفتقر إلى إشارات TimeSignal المطابقة؛ وتتجاهل خوادم الإعلانات الكلاسيكية الإشارات التي تحتوي على TimeSignal-فقط. بدون الإشارات الثلاث، يتم تحقيق الدخل من كل فاصل إعلاني بواسطة جزء من مكدسك اللاحق ويفوت الباقي — وتكتشف ذلك من تقرير الإيرادات، وليس من السجلات.
2. أساسان زمنيان، تتم تسويتهما في دالة واحدة
SpliceInsert.Duration تكون بالثواني. أما SegmentationDuration داخل وصف TimeSignal فتكون بوحدات 90,000 تكة. نفس المدة المنطقية، تشفيران — والخطأ الأكثر شيوعًا في SCTE-35 هو الخلط بينهما.
الرسم التخطيطي 3 · منطق تحويل الوقت

تعيش عملية التحويل في buildProgramActions وهناك فقط. يوجد مكان واحد موثوق للبحث عندما تكون مدة الإشارة خاطئة، ومكان واحد للتغيير إذا تطورت المواصفات.
المقايضة التي قمنا بها عن قصد. كان بإمكاننا تخزين كلا الأساسين الزمنيّين في مستند AdMarker والسماح لـ Lambda بنسخهما. لم نفعل ذلك عمدًا: تخزين قيمة الثواني فقط يعني وجود رقم واحد فقط للمشغل لتعيينه، ورقم واحد فقط للتحقق منه، ورقم واحد فقط يمكن أن يكون خاطئًا. قيمة 90 kHz مشتقة، ولا يتم تخزينها أبدًا. لا يمكن للبيانات المشتقة أن تنحرف.
3. الموضع نسبي، ووقت التشغيل مطلق
يقول المشغل "فاصل إعلاني عند 720 ثانية في البرنامج." تقوم Lambda بحساب وقت تشغيل UTC الفعلي كـ programStartTime + offsetSeconds × 1000 وتضع هذه العلامة على الإجراء. كل إجراء جدولة آخر — تبديل الإدخال، تشغيل العلامة المائية، نهاية البرنامج — يستخدم نفس خط أنابيب تحويل الإزاحة إلى الطابع الزمني. تهبط إشارات الإعلانات على نفس حدود الإطارات مثل كل شيء آخر، دون أي غموض حول أي ساعة تملك الجدول الزمني.
4. التحقق من الصحة في طبقة البيانات، وليس في الاتصال
يفرض مخطط AdMarker أن duration ∈ [10, 120] ثانية عند وقت حفظ Mongoose. فاصل إعلاني خارج النطاق لا يصل أبدًا إلى Lambda. يتم قص الفواصل الإعلانية التي قد تتجاوز نهاية البرنامج في وقت البناء بدلاً من رفضها — لا يفقد المشغلون عملهم بسبب فاصل إعلاني واحد سيء. أنواع الأخطاء التي لا يمكن أن تحدث أكثر إثارة للاهتمام من تلك التي يمكن أن تحدث.
5. فصل إصدار الإشارات عن SSAI
ما نقوم بشحنه اليوم هو طبقة الإشارات. إدراج الإعلانات من جانب الخادم (SSAI) عبر AWS MediaTailor — والذي سيستهلك هذه الإشارات لدمج إعلانات إبداعية حقيقية في HLS manifest — مصمم بالكامل ولم يتم ربطه بعد. الترتيب المتعمد: الحصول على طبقة الإشارات صحيحة أولاً، في الإنتاج، تُستخدم بواسطة قنوات حقيقية، قبل تشغيل SSAI. عندما يصبح التكامل مباشرًا، ستكون الإشارات موجودة بالفعل. يحصل النظام اللاحق على عقد نظيف للاستهلاك من اليوم الأول.
لماذا هذا الترتيب مهم. تصحيح أخطاء SSAI يكون صعبًا عندما تكون إشاراتك خاطئة، لأن كل فشل يبدو وكأنه فشل في SSAI حتى عندما تكون الإشارات هي السبب. من خلال شحن طبقة الإشارات بمعزل أولاً والتحقق منها مقابل مشغلات وخوادم إعلانات حقيقية، أزلنا فئة كاملة من الالتباس في التكامل قبل أن يحدث.
النتائج
- كل فاصل إعلاني يحدده المشغل يصدر مكدس SCTE-35 من ثلاث إشارات متوافقة مع المعايير في HLS manifest للقناة — في الثانية الصحيحة، مقابل الأساس الزمني الصحيح.
- تعيش طبقة الترجمة في دالة واحدة. تغييرات المواصفات أو المستهلكون اللاحقون الجدد هي تغيير في ملف واحد، وليست بحثًا عبر قاعدة الكود.
- يتم التحقق من صحة المدة في طبقة البيانات، قبل أن تصل أي إشارة إلى المرمز. تظهر أخطاء المشغل في واجهة المستخدم (UI)، وليس بصمت أثناء البث — لا يمكن للإشارات المشوهة أن تصل إلى MediaLive.
- توليد الإشارات حتمي: مدخلات المشغل المتطابقة تنتج إجراءات SCTE-35 متطابقة، لذا يتصرف نفس الفاصل بنفس الطريقة عبر كل عملية نشر وكل قناة.
- تم شحن طبقة الإشارات وهي حية. تم تصميم مستهلك SSAI (MediaTailor) وهو جاهز للربط — وعندما يتم ذلك، ستكون إشارات كل قناة موجودة بالفعل في انتظاره.
مكدس التقنيات: AWS MediaLive · AWS Lambda · NestJS · MongoDB · TypeScript · Node 18 · SCTE-35 (Scte35TimeSignalSettings, Scte35SpliceInsertSettings) · AWS SDK v3

