সরাসরি পর্বে যান
পর্ব ৪০ · ৬২-এর মধ্যে · মডিউল ৬

Real-time আর streaming — WebSocket, VoIP আর ভিডিও স্ট্রিমিং

Real-time and Streaming — Video Buffering, DASH/HLS, WebSocket, VoIP Jitter Buffers, RTP, SIP and WebRTC

Taught in Bangla, this lesson compares stored video, conversational and live media and their delay tolerance. It covers client buffering, DASH and HLS adaptive bitrate streaming over HTTP and CDNs, WebSocket upgrade and framing, VoIP over RTP with jitter buffers and loss concealment, SIP signalling, and WebRTC, with simulators.

এই পর্বে যা শিখবেন

  • তিন ধরনের মাল্টিমিডিয়া অ্যাপের delay-সীমা, অডিও-ভিডিওর sampling, codec, frame আর bitrate
  • Client buffer-এর গাণিতিক মডেল (শুরুর দেরি, buffer খালি হওয়ার সময়) আর DASH/HLS-এর adaptive bitrate
  • WebSocket-এর handshake (Sec-WebSocket-Accept নিজে হিসাব করে), frame-এর গঠন, masking আর বিকল্পের সাথে তুলনা
  • VoIP-এর packet আর bandwidth হিসাব, jitter buffer-এর fixed ও adaptive playout delay, FEC আর interleaving
  • RTP/RTCP header, SIP কলের প্রবাহ, WebRTC-র পুরো কল-স্থাপন আর mesh/SFU/MCU-এর bandwidth

১ · তিন ধরনের মাল্টিমিডিয়া অ্যাপ — কে কতটা দেরি সইতে পারে

আগের পর্বগুলোতে যত অ্যাপ দেখেছেন — ওয়েবপাতা (পর্ব ৩৬), ইমেইল (পর্ব ৩৯) — সেখানে মূল চাওয়া ছিল প্রতিটি বাইট নির্ভুলভাবে পৌঁছানো; একটু দেরি হলে কেউ টেরও পায় না। মাল্টিমিডিয়ায় হিসাব উল্টো। একটি ভিডিও-কলে দুই-একটি packet হারালে কানে প্রায় ধরা পড়ে না, কিন্তু আধা সেকেন্ড দেরি হলে দুজনেই একসাথে কথা বলে ফেলেন। তাই আগে বুঝতে হবে কোন অ্যাপ কতটা দেরি সইতে পারে। মাল্টিমিডিয়া অ্যাপ মোটামুটি তিন ধরনের:

জমা ভিডিও (stored)

নাটক, টিউটোরিয়াল, সিনেমা — ফাইলটি আগে থেকেই সার্ভারে। দর্শক থামাতে, পিছোতে পারেন। শুরুতে ১–৩ সেকেন্ড অপেক্ষা মেনে নেওয়া যায়; জরুরি হলো মাঝপথে না আটকানো।

দেরি সয়: কয়েক সেকেন্ড

কথোপকথন (conversational)

ভয়েস কল, ভিডিও মিটিং, অনলাইন ক্লাসের প্রশ্নোত্তর। মুখ থেকে কানে একদিকে মোটামুটি ১৫০ মিলিসেকেন্ডের কম হলে স্বাভাবিক লাগে; ৪০০-র বেশি হলে কথা জড়িয়ে যায়।

দেরি সয়: ~১৫০ ms

Live streaming

ক্রিকেট ম্যাচ, ওয়াজ মাহফিল বা অনুষ্ঠানের সরাসরি সম্প্রচার — এক দিকে লক্ষ দর্শক। দর্শক কথা বলেন না, তাই কয়েক সেকেন্ড পিছিয়ে থাকা চলে, তবে প্রতিবেশীর টিভির চেয়ে অনেক পিছিয়ে থাকলে ছক্কার খবর আগে পাশের বাসা থেকে আসে!

দেরি সয়: কয়েক সেকেন্ড

কথোপকথনের সংখ্যাটি আসে ITU-T-র সুপারিশ G.114 থেকে: সেখানে বলা হয়েছে, বেশিরভাগ ব্যবহারে একদিকের মোট দেরি মোটামুটি ১৫০ মিলিসেকেন্ডের মধ্যে থাকলে অধিকাংশ ব্যবহারকারী সন্তুষ্ট থাকেন, আর ৪০০ মিলিসেকেন্ডের বেশি সাধারণ নেটওয়ার্ক-পরিকল্পনায় গ্রহণযোগ্য নয়। এগুলো কঠোর আইন নয়, নির্দেশিকা — কিছু মানুষ ২০০-তেও খুশি, প্রতিধ্বনি (echo) থাকলে কম দেরিতেও বিরক্ত। এই “বাজেট”-এর মধ্যে সব ধরতে হয়: codec-এর কাজ, packet বানানোর অপেক্ষা, পথের propagation আর queuing delay (পর্ব ৫), আর প্রাপকের jitter buffer.

জমা ভিডিও যেন কুরিয়ারে কিস্তিতে আসা উপন্যাস — প্রথম কয়েক অধ্যায় এলেই পড়া শুরু, শুধু পড়া যেন কুরিয়ারকে ছাড়িয়ে না যায়। ফোনালাপ যেন রাস্তার দুই পাশ থেকে কথা বলা — উত্তরে দেরি হলে আলাপ ভাঙে, একটি শব্দ হারালে আন্দাজে চলে। Live যেন রেডিওর ধারাভাষ্য — একটু পিছিয়ে থাকলে ক্ষতি নেই।

মূল ধারণা

Delay সওয়ার ক্ষমতাই protocol বাছাই ঠিক করে। কয়েক সেকেন্ডের ধৈর্য থাকলে TCP বা QUIC-এর ওপর HTTP চলে — হারানো ডেটা আবার আনার সময় buffer দেয়। ১৫০ মিলিসেকেন্ডের বাজেটে পুনঃপ্রেরণের জায়গা প্রায় নেই, তাই কথোপকথন চলে UDP-র ওপর (পর্ব ২৮), আর ক্ষতি সামলানো হয় অন্য কৌশলে।

২ · মিডিয়ার ভিত্তি — sampling, codec, frame আর bitrate

অডিও: প্রতি সেকেন্ডে কত bit

পর্ব ৭-এ দেখেছেন analog কণ্ঠ কীভাবে digital হয়: নির্দিষ্ট সময় পরপর মান মাপা (sampling), প্রতিটি মান নির্দিষ্ট স্তরে গোল করা (quantization), তারপর bit-এ লেখা — একসাথে PCM. টেলিফোনের কণ্ঠ মোটামুটি ৪ kHz পর্যন্ত ধরা হয়, তাই Nyquist অনুযায়ী প্রতি সেকেন্ডে ৮,০০০টি sample; প্রতিটি ৮ bit. ফলে:

৮,০০০ sample/সেকেন্ড × ৮ bit = ৬৪,০০০ bps = ৬৪ kbps
এটাই G.711 — টেলিফোন নেটওয়ার্কের পুরোনো, সংকোচনহীন মান (μ-law আর A-law দুই রূপে)

Codec (coder-decoder) হলো সেই পদ্ধতি যা এই কাঁচা ডেটা সংকুচিত করে আর আবার খোলে। G.711 সংকোচন প্রায় করে না, তাই মান ভালো কিন্তু ৬৪ kbps খায়। আধুনিক Opus codec (IETF, RFC 6716, ২০১২) কণ্ঠের জন্য সাধারণত ১৬–৩২ kbps-এ খুব ভালো মান দেয়, প্রয়োজনে ৬ kbps থেকে ৫১০ kbps পর্যন্ত যেতে পারে, আর গান-বাজনাও ভালো সামলায়। WebRTC-তে Opus আর G.711 দুটোই বাধ্যতামূলক codec. সংকোচন বিনামূল্যে নয়: codec-কে কয়েক মিলিসেকেন্ড কণ্ঠ জমিয়ে তারপর কাজ করতে হয়, আর এই অপেক্ষা delay বাজেট থেকে কাটা যায়।

ভিডিও: ছবির সারি আর সংকোচন

ভিডিও আসলে দ্রুত পরপর দেখানো ছবি — প্রতিটি একটি frame, সাধারণত প্রতি সেকেন্ডে ২৪–৬০টি। সংকোচন না করলে ১০৮০p-র (১৯২০ × ১০৮০ pixel) প্রতি pixel-এ ২৪ bit, ৩০ frame/সেকেন্ডে ১৯২০ × ১০৮০ × ২৪ × ৩০ ≈ ১.৪৯ Gbps লাগত! তাই ভিডিও codec দুই ধরনের অপচয় কাটে:

  • Spatial (একই ছবির ভেতরে): নীল আকাশের হাজারটি প্রায় একই pixel আলাদা করে না লিখে একসাথে বর্ণনা করা — JPEG ছবির মতো।
  • Temporal (পরপর ছবির মধ্যে): সংবাদ-পাঠকের পেছনের দেয়াল frame থেকে frame-এ বদলায় না; শুধু যা নড়েছে তা পাঠানো।

এজন্য frame তিন রকম। I-frame (key frame) নিজে নিজেই সম্পূর্ণ ছবি — বড়, কিন্তু অন্য কারও ওপর নির্ভর করে না। P-frame শুধু আগের ছবির তুলনায় পার্থক্য রাখে, B-frame আগের আর পরের দুটো ছবির সাহায্য নেয় — সবচেয়ে ছোট। একটি I-frame থেকে পরের I-frame পর্যন্ত দলটিকে GOP (group of pictures) বলে। এর নেটওয়ার্ক-ফল গুরুত্বপূর্ণ: একটি P-frame-এর packet হারালে ভুল পরের I-frame পর্যন্ত ছড়ায়; আর streaming-এর প্রতিটি segment সাধারণত I-frame দিয়ে শুরু হয়, যাতে player যেকোনো segment থেকে দেখা শুরু করতে বা অন্য মানে লাফ দিতে পারে।

প্রচলিত ভিডিও codec-এর প্রজন্ম: H.264/AVC (২০০৩) — প্রায় সব যন্ত্রে hardware সমর্থন, আজও সবচেয়ে সর্বজনীন; H.265/HEVC (২০১৩) — মোটামুটি একই মানে কম bitrate, তবে লাইসেন্সের জটিলতা; Google-এর VP9 — YouTube-এ ব্যাপক; আর Alliance for Open Media-র রয়্যালটি-মুক্ত AV1 (২০১৮) — আরও দক্ষ, কিন্তু encode-এ বেশি CPU. নতুন প্রজন্মের লাভ বিষয়বস্তু আর encoder-এর ওপর অনেক নির্ভর করে।

রেজোলিউশনআনুমানিক bitrate (H.264, ৩০ fps)মন্তব্য
৪৮০p (৮৫৪ × ৪৮০)~০.৮–২ Mbpsদুর্বল মোবাইল সংযোগে ভরসা
৭২০p (১২৮০ × ৭২০)~২–৫ Mbpsছোট পর্দায় যথেষ্ট ভালো
১০৮০p (১৯২০ × ১০৮০)~৪–৮ Mbpsখেলাধুলার মতো দ্রুত দৃশ্যে বেশি
৪K (৩৮৪০ × ২১৬০)~১৫–৪০ Mbpsসাধারণত HEVC/VP9/AV1-এ, তখন কম

এগুলো শুধু রুক্ষ পরিসর — কার্টুন কম bit-এ চলে, বৃষ্টির মধ্যে ফুটবল ম্যাচ অনেক বেশি চায়। মনে রাখার কথা: এক ধাপ রেজোলিউশন বাড়লে bitrate মোটামুটি দ্বিগুণ বা তার বেশি, আর তাই একই ভিডিওর কয়েকটি মান রেখে দেওয়া যায় (অংশ ৪)।

৩ · জমা ভিডিও streaming — buffer আর playout-এর হিসাব

সবচেয়ে সরল পদ্ধতি progressive download: ভিডিওটি একটি সাধারণ ফাইল, ব্রাউজার HTTP GET দিয়ে আনতে থাকে (পর্ব ৩৬), আর কিছুটা জমা হলেই চালানো শুরু করে। দর্শক সামনে লাফ দিলে HTTP-র Range header দিয়ে ফাইলের মাঝখান থেকে আনা যায়। Server-এর কোনো বিশেষ বুদ্ধি লাগে না — যেকোনো ওয়েব সার্ভার বা CDN কাজ করে। মূল যন্ত্রটি তাই client-এর playout buffer: নেটওয়ার্ক যে হারে ডেটা আনে (fill rate, x) আর ভিডিও যে হারে খরচ হয় (playback rate, r) — দুইয়ের পার্থক্য এই buffer শোষণ করে।

বাসার ছাদের পানির ট্যাংক ভাবুন। পাম্প (নেটওয়ার্ক) x হারে পানি তোলে, কল (player) r হারে খরচ করে। পাম্প চালিয়ে প্রথমে কিছুটা ভরে নিলেন, তারপর কল খুললেন — এটাই শুরুর দেরি। লোডশেডিংয়ে পাম্প থামলেও কিছুক্ষণ ট্যাংকের জমা পানিতে চলে; কিন্তু x যদি r-এর চেয়ে কম হয়, ট্যাংক একসময় খালি হবেই — তখন ভিডিও থেমে ঘুরতে থাকা চাকা দেখায়, যাকে বলে rebuffering বা stall.

গাণিতিক মডেল — পরীক্ষার ধাঁচের হিসাব

ধরুন ভিডিওর playback rate r bps, নেটওয়ার্ক স্থির x bps হারে আনছে, আর player চালানো শুরু করে buffer-এ Q bit জমলে। সময় t = ০-তে অনুরোধ।

  • শুরুর দেরি: Q bit জমতে লাগে tp = Q / x.
  • x ≥ r হলে: buffer কখনো কমে না — কোনো stall নেই।
  • x < r হলে: চালানো শুরুর পর buffer-এ থাকে Q − (r − x)·τ, যেখানে τ = চালানো শুরুর পর থেকে সময়। এটি শূন্য হয় τ = Q / (r − x)-এ — অর্থাৎ মোট সময় tp + Q / (r − x)-এ প্রথম stall.
শুরুর দেরি tp = Q / x  ·  x < r হলে buffer খালি হয় tp + Q / (r − x)-এ
উদাহরণ: r = ২ Mbps, x = ১.৫ Mbps, Q = ৬ Mb → tp = ৪ s; buffer খালি ৬ ÷ ০.৫ = ১২ s পরে, অর্থাৎ t = ১৬ s-এ

যাচাই: ১৬ সেকেন্ডে নামানো হয়েছে ১.৫ × ১৬ = ২৪ Mb, আর ১২ সেকেন্ড চালাতে খরচ হয়েছে ২ × ১২ = ২৪ Mb — হিসাব মিলছে। এবার প্রশ্ন উল্টো: ১০ মিনিটের (৬০০ সেকেন্ড) পুরো ভিডিও একবারও না থামিয়ে চালাতে Q কত লাগবে? দরকার Q / (r − x) ≥ ৬০০, অর্থাৎ Q ≥ ৬০০ × ০.৫ = ৩০০ Mb — আর শুরুর দেরি ৩০০ ÷ ১.৫ = ২০০ সেকেন্ড! কোনো দর্শক তিন মিনিট অপেক্ষা করবেন না। তাই সমাধান buffer বড় করা নয় — bitrate কমানো: ভিডিও যদি ১.২ Mbps-এর একটি সংস্করণে থাকে, তাহলে x > r, আর কোনো stall নেই। এই চিন্তা থেকেই adaptive bitrate.

৪ · Adaptive bitrate — DASH, HLS আর CDN

Adaptive bitrate (ABR) streaming-এ একটি ভিডিও আগে থেকেই কয়েকটি মানে encode করা থাকে — যেমন ২৪০p, ৪৮০p, ৭২০p, ১০৮০p. প্রতিটি সংস্করণকে (representation) ২ থেকে ১০ সেকেন্ডের ছোট ছোট segment-এ কাটা হয়, আর সব সংস্করণের segment সময়ের হিসাবে একই সীমানায় শুরু হয় (প্রত্যেকটির শুরুতে I-frame). Player প্রথমে একটি manifest ফাইল আনে, যেখানে লেখা কোন কোন মান আছে, প্রতিটির bitrate কত, আর segment-গুলোর URL কী। তারপর প্রতিটি segment-এর আগে player নিজেই ঠিক করে কোন মানেরটা আনবে। সার্ভার বোকা থাকে — শুধু ফাইল দেয়; বুদ্ধি থাকে client-এ।

বিষয়MPEG-DASHHLS
উৎসMPEG/ISO আন্তর্জাতিক মান (ISO/IEC 23009-1, ২০১২)Apple (২০০৯), পরে RFC 8216 (২০১৭)
ManifestXML-এর MPD (Media Presentation Description)লেখার মতো .m3u8 playlist
Segmentসাধারণত fragmented MP4শুরুতে MPEG-TS, এখন fMP4-ও
সমর্থনAndroid, অনেক ব্রাউজারে JavaScript player দিয়েiPhone/Safari-তে নিজস্ব; অন্যত্র JavaScript player দিয়ে

দুটোরই segment একই ফরম্যাটে রাখার জন্য এসেছে CMAF (Common Media Application Format) — একই fMP4 segment একবার বানিয়ে DASH আর HLS দুই manifest-ই দেখাতে পারে, ফলে CDN-এ দ্বিগুণ জায়গা লাগে না। একটি ছোট HLS master playlist দেখতে এমন:

#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480
480p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p/index.m3u8

Player কীভাবে মান বাছে — দুই ধরনের ABR

  • Throughput-ভিত্তিক: শেষ কয়েকটি segment কত দ্রুত এল তা মেপে, তার একটি নিরাপদ অংশের (যেমন ৮০%) মধ্যে সবচেয়ে বড় bitrate. সহজ, কিন্তু গতি হঠাৎ নামলে মাপ পিছিয়ে থাকে।
  • Buffer-ভিত্তিক: buffer-এ কত সেকেন্ড জমা আছে সেটাই মূল সংকেত — buffer কম হলে নিচু মান, ভরা থাকলে উঁচু। ২০১৪ সালে Netflix-এর সাথে কাজ করা গবেষকেরা (BBA নামের পদ্ধতি) দেখিয়েছিলেন এতে stall কমে। BOLA-র মতো পরের পদ্ধতি আর আধুনিক player দুই সংকেত মিলিয়ে ব্যবহার করে।

নিচের stepper-এ একজন দর্শক ১০টি segment-এর একটি ভিডিও দেখছেন, প্রতি segment ৪ সেকেন্ডের। ৮ সেকেন্ড জমলে চালানো শুরু। নিয়ম throughput-ভিত্তিক: আগের segment-এ মাপা গতির ৮০%-এর মধ্যে সবচেয়ে বড় মান। মাঝপথে Wi-Fi থেকে বেরিয়ে দুর্বল মোবাইল সংকেতে গেলে গতি ৮ Mbps থেকে নেমে ৯০০ kbps হয়।

  1. MPD/m3u8240p…1080p৪ s segment
  2. ABR নিয়ম≤ 0.8 × মাপা গতিপ্রতি segment-এ
  3. CDNGET segকাছের server
  4. Bufferসেকেন্ডেখালি = stall
প্রতিটি segment-এর সিদ্ধান্ত
Segment
আগের মাপা গতি
বাজেট (৮০%)
এখনকার গতি
নামাতে সময়
Buffer (পরে)
  1. চালানো শুরু। প্রথম segment নিরাপদে ৪৮০p-তে এসেছিল (শুরুর অনুমান ১.৫ Mbps). দ্বিতীয়টি ৮ Mbps মেপে ১০৮০p-তে; t = ৩.০০ সেকেন্ডে buffer ৮ সেকেন্ড — ভিডিও চলতে শুরু করল।
  2. ভালো সময়। ৫,০০০ kbps-এর ১০৮০p segment ৮,০০০ kbps-এ নামতে ৫০০০ × ৪ ÷ ৮০০০ = ২.৫ সেকেন্ড। ওই সময়ে ২.৫ সেকেন্ড ভিডিও খরচ হলো, ৪ সেকেন্ড এল — buffer বেড়ে ৯.৫০.
  3. গতি নামল, কিন্তু player এখনো জানে না। সিদ্ধান্ত হয়েছে আগের মাপ (৮,০০০) দেখে, তাই আবার ১০৮০p. আসল গতি ৩,০০০ — নামতে ৬.৬৭ সেকেন্ড, buffer কমে ৯.৫০ − ৬.৬৭ + ৪ = ৬.৮৩. Throughput-ভিত্তিক নিয়মের দুর্বলতা এখানেই: মাপ পিছিয়ে থাকে।
  4. মান নামল। এবার মাপ ৩,০০০, বাজেট ২,৪০০ — ৭২০p (২,৫০০) চলে না, তাই ৪৮০p. গতি আরও নেমে ১,৫০০, তবু ১,০০০ kbps-এর segment ২.৬৭ সেকেন্ডে এল; buffer বেড়ে ৮.১৭.
  5. আরও খারাপ সংকেত। বাজেট ১,২০০ — ৪৮০p তখনো চলে। কিন্তু আসল গতি ৯০০, তাই ৪.৪৪ সেকেন্ড লাগল, এল মাত্র ৪ সেকেন্ডের ভিডিও — buffer সামান্য কমে ৭.৭২.
  6. সবচেয়ে নিচু মান, কিন্তু থামেনি। বাজেট ৭২০ — ২৪০p (৪০০ kbps), ১.৭৮ সেকেন্ডে নামল, buffer ৯.৯৪. ছবি ঝাপসা হলো, কিন্তু একবারও থামল না। একই গতিপথে সবসময় ১০৮০p চাইলে ৪ বার মোট প্রায় ৪৯ সেকেন্ড আটকে থাকত (নিচের simulator).
// DASH-style player: 4-second segments, 4 representations, throughput-based ABR.
// ABR rule: highest bitrate <= 0.8 x throughput measured on the previous segment.
const SEG = 4, START = 8;                        // s of video per segment; play after 8 s buffered
const reps = [["240p", 400], ["480p", 1000], ["720p", 2500], ["1080p", 5000]];   // kbps
const bw = [8000, 8000, 8000, 3000, 1500, 900, 900, 2000, 8000, 8000]; // kbps while fetching seg i

function play(fixed, show) {
  let t = 0, buf = 0, playing = false, est = 1500, stalls = 0, stallTime = 0;
  if (show) console.log("seg  bw    pick   dl(s)  t_end  buffer  event");
  bw.forEach((b, i) => {
    const [name, kbps] = fixed || [...reps].reverse().find(r => r[1] <= 0.8 * est) || reps[0];
    const dl = kbps * SEG / b;                   // seconds to download this segment
    let ev = "";
    if (playing) {                               // video keeps playing during the download
      if (buf >= dl) buf -= dl;
      else { stalls++; stallTime += dl - buf; ev = "STALL " + (dl - buf).toFixed(2) + " s"; buf = 0; }
    }
    t += dl; buf += SEG; est = b;                // segment arrives; remember its throughput
    if (!playing && buf >= START) { playing = true; ev = "playback starts"; }
    if (show) console.log(String(i + 1).padEnd(5) + String(b).padEnd(6) + name.padEnd(7) +
      dl.toFixed(2).padEnd(7) + t.toFixed(2).padEnd(7) + buf.toFixed(2).padEnd(8) + ev);
  });
  return `stalls ${stalls}, stall time ${stallTime.toFixed(2)} s`;
}
console.log("ABR       : " + play(null, true));
console.log("fixed 1080p: " + play(reps[3], false));
console.log("fixed 720p : " + play(reps[2], false));

আউটপুট:

seg  bw    pick   dl(s)  t_end  buffer  event
1    8000  480p   0.50   0.50   4.00
2    8000  1080p  2.50   3.00   8.00    playback starts
3    8000  1080p  2.50   5.50   9.50
4    3000  1080p  6.67   12.17  6.83
5    1500  480p   2.67   14.83  8.17
6    900   480p   4.44   19.28  7.72
7    900   240p   1.78   21.06  9.94
8    2000  240p   0.80   21.86  13.14
9    8000  480p   0.50   22.36  16.64
10   8000  1080p  2.50   24.86  18.14
ABR       : stalls 0, stall time 0.00 s
fixed 1080p: stalls 4, stall time 48.94 s
fixed 720p : stalls 3, stall time 10.47 s

ABR-এর টেবিলে মান ৪৮০p → ১০৮০p → ৪৮০p → ২৪০p → ৪৮০p → ১০৮০p ঘুরেছে, কিন্তু “stalls 0”. সবসময় ১০৮০p চাইলে ৪ বার, মোট ৪৮.৯৪ সেকেন্ড আটকে থাকত; ৭২০p-তেও ৩ বার, ১০.৪৭ সেকেন্ড। মডেলটি সরল: stall হলে পরের segment এলেই আবার চলে, আর গতি একটি segment জুড়ে স্থির; বাস্তবের player কয়েকটি মাপের গড় নেয় আর buffer-ও দেখে। bw বা 0.8 বদলে দেখুন কখন ABR-ও আটকে যায়।

CDN, live latency আর ছোট chunk

Segment যেহেতু সাধারণ HTTP ফাইল, সেগুলো CDN-এর edge server-এ cache হয় (পর্ব ৩৮) — হাজার দর্শক একই জনপ্রিয় নাটক দেখলে মূল সার্ভারে একবারই চাপ পড়ে, বাকিটা কাছের edge থেকে। HTTP/2 আর HTTP/3 (পর্ব ৩৭) একই সংযোগে পরপর segment আনা আরও সস্তা করেছে।

Live-এ একই কৌশল, কিন্তু segment তৈরি হয় চলতে চলতে। Encoder-কে একটি segment পুরো শেষ করতে হয়, তারপর CDN-এ যায়, আর player সাধারণত নিরাপত্তার জন্য ২–৩টি segment buffer-এ রাখে। ৬ সেকেন্ডের segment আর ৩টি buffer মানে শুধু এখানেই প্রায় ১৮ সেকেন্ড পিছিয়ে — তাই প্রচলিত HLS live প্রায়ই সম্প্রচারের চেয়ে বেশ কয়েক সেকেন্ড থেকে আধা মিনিট পিছিয়ে থাকে। ছোট segment দেরি কমায়, কিন্তু request-এর খরচ বাড়ায়। এর উত্তর Low-Latency HLS আর chunked CMAF: segment-কে ছোট “partial” টুকরোয় ভাগ করে তৈরি হতে হতেই পাঠানো — দেরি কয়েক সেকেন্ডে নামতে পারে, তবে প্রকৃত সংখ্যা CDN আর player-ভেদে আলাদা।

৫ · WebSocket — ব্রাউজার আর সার্ভারের দুই-দিকের স্থায়ী লাইন

এবার একটু ভিন্ন ধরনের “real-time”: ভিডিও নয়, ছোট ছোট বার্তা যা সঙ্গে সঙ্গে পৌঁছানো দরকার — চ্যাটের নতুন মেসেজ, ক্রিকেটের live স্কোর, শেয়ারবাজারের দাম, অনলাইন খেলায় প্রতিপক্ষের চাল। সাধারণ HTTP-তে সমস্যা হলো শুধু client প্রশ্ন করতে পারে; নতুন খবর এলে সার্ভার নিজে থেকে বলতে পারে না। পুরোনো সমাধানগুলো:

  • Polling: প্রতি কয়েক সেকেন্ডে “নতুন কিছু আছে?” — বেশিরভাগ উত্তর “না”, প্রতিবার পুরো HTTP header.
  • Long polling: সার্ভার উত্তর আটকে রাখে যতক্ষণ না খবর আসে; উত্তর পেলেই client আবার প্রশ্ন পাঠায় — প্রতিটি বার্তায় নতুন অনুরোধ।
  • Server-Sent Events (SSE): একটি দীর্ঘস্থায়ী HTTP উত্তর (text/event-stream), যাতে সার্ভার একের পর এক ঘটনা লিখতে থাকে; ব্রাউজারের EventSource সংযোগ ভাঙলে নিজেই আবার জোড়ে। তবে শুধু সার্ভার থেকে client-এর দিকে, আর লেখা-ভিত্তিক।

WebSocket (RFC 6455, ডিসেম্বর ২০১১) এর পূর্ণ উত্তর: একটি TCP সংযোগের ওপর দুই দিকেই, যেকোনো সময়, ছোট frame-এ বার্তা — প্রতি বার্তায় মাত্র ২–১৪ বাইটের header. ঠিকানা ws:// (port 80) বা TLS-এর ওপর wss:// (port 443, পর্ব ৪৮); বাস্তবে প্রায় সবসময় wss://, কারণ এনক্রিপ্ট না করা সংযোগ মাঝপথের proxy প্রায়ই ভেঙে দেয়।

Handshake — HTTP দিয়ে শুরু, তারপর অন্য protocol

WebSocket আলাদা port চায় না; এটি সাধারণ HTTP/1.1 অনুরোধ হিসেবে শুরু হয়ে “Upgrade” চায়। সার্ভার রাজি হলে 101 Switching Protocols দেয়, আর সেই একই TCP সংযোগ তখন থেকে WebSocket frame বহন করে। RFC 6455-এর নিজের উদাহরণ:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Key হলো client-এর ১৬টি এলোমেলো বাইট, base64-এ লেখা। সার্ভার এর সাথে একটি নির্দিষ্ট GUID (258EAFA5-E914-47DA-95CA-C5AB0DC85B11) জোড়ে, SHA-1 hash নেয়, তারপর base64 করে Sec-WebSocket-Accept-এ ফেরত দেয়। এটি নিরাপত্তার জন্য নয় (কোনো গোপন চাবি নেই) — শুধু প্রমাণ যে সার্ভারটি সত্যিই WebSocket বোঝে। আসল নিরাপত্তা আসে wss://-এর TLS আর সার্ভারের Origin যাচাই থেকে।

Frame-এর গঠন আর masking

বাইট 0 : FIN(1) RSV1-3(3) opcode(4)    0x1 text, 0x2 binary, 0x8 close, 0x9 ping, 0xA pong
বাইট 1 : MASK(1) payload len(7)        0–125 = সরাসরি দৈর্ঘ্য
                                       126 = পরের 2 বাইটে দৈর্ঘ্য, 127 = পরের 8 বাইটে
তারপর  : masking key (4 বাইট, MASK=1 হলে) → payload

FIN = ১ মানে বার্তার শেষ টুকরো; বড় বার্তা কয়েকটি frame-এ ভাগ হলে পরেরগুলোর opcode ০ (continuation). সবচেয়ে অদ্ভুত নিয়ম: client থেকে সার্ভারের প্রতিটি frame mask করা বাধ্যতামূলক, সার্ভার থেকে client-এরগুলো mask করা হয় না। Client প্রতিটি frame-এর জন্য ৪ বাইটের নতুন এলোমেলো key বাছে, আর payload-এর i-তম বাইট key-এর (i mod ৪)-তম বাইটের সাথে XOR হয়। কারণটি এনক্রিপশন নয় — key তো frame-এই লেখা! ২০১০–১১ সালে গবেষকেরা দেখিয়েছিলেন, WebSocket না বোঝা কিছু পুরোনো transparent proxy-কে ক্ষতিকর ওয়েবপাতার JavaScript দিয়ে এমন বাইট পাঠানো যায় যা proxy নতুন HTTP অনুরোধ ভেবে ভুল উত্তর cache করে ফেলে (cache poisoning). এলোমেলো mask থাকলে আক্রমণকারী তারের ওপর ঠিক কোন বাইট যাবে তা নিয়ন্ত্রণ করতে পারে না।

নিচের প্রোগ্রাম পুরো হিসাবটি নিজে করে — একটি ছোট SHA-1 লিখে RFC-র উদাহরণের accept মান বের করে, তারপর “Hello” লেখাটি RFC-র উদাহরণের mask দিয়ে একটি client frame বানায় আর আবার পড়ে।

// WebSocket (RFC 6455): Sec-WebSocket-Accept, then encode + decode one masked text frame.
function sha1(bytes) {                         // compact SHA-1 (FIPS 180-4), returns 20 bytes
  const m = [...bytes, 0x80]; while (m.length % 64 !== 56) m.push(0);
  const bits = bytes.length * 8; for (let s = 56; s >= 0; s -= 8) m.push(s >= 32 ? 0 : (bits >>> s) & 255);
  let h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
  const rol = (x, n) => (x << n) | (x >>> (32 - n));
  for (let o = 0; o < m.length; o += 64) {
    const w = []; for (let i = 0; i < 16; i++) w[i] = (m[o+4*i] << 24) | (m[o+4*i+1] << 16) | (m[o+4*i+2] << 8) | m[o+4*i+3];
    for (let i = 16; i < 80; i++) w[i] = rol(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
    let [a, b, c, d, e] = h;
    for (let i = 0; i < 80; i++) {
      const f = i < 20 ? (b & c) | (~b & d) : i < 40 ? b ^ c ^ d : i < 60 ? (b & c) | (b & d) | (c & d) : b ^ c ^ d;
      const k = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6][Math.floor(i / 20)];
      [e, d, c, b, a] = [d, c, rol(b, 30), a, (rol(a, 5) + f + e + k + w[i]) | 0];
    }
    h = h.map((x, i) => (x + [a, b, c, d, e][i]) | 0);
  }
  return h.flatMap(x => [x >>> 24, (x >>> 16) & 255, (x >>> 8) & 255, x & 255]);
}
const key = "dGhlIHNhbXBsZSBub25jZQ==", GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
const accept = btoa(String.fromCharCode(...sha1(new TextEncoder().encode(key + GUID))));
console.log("Sec-WebSocket-Accept: " + accept);

const hex = a => a.map(x => x.toString(16).padStart(2, "0")).join(" ");
const mask = [0x37, 0xfa, 0x21, 0x3d], text = [...new TextEncoder().encode("Hello")];
const frame = [0x80 | 0x1, 0x80 | text.length, ...mask, ...text.map((x, i) => x ^ mask[i % 4])];
console.log("client frame: " + hex(frame));        // FIN=1 opcode=1(text) MASK=1 len=5
const fin = frame[0] >> 7, op = frame[0] & 15, masked = frame[1] >> 7, len = frame[1] & 127;
const k = frame.slice(2, 6), data = frame.slice(6).map((x, i) => x ^ k[i % 4]);
console.log(`decoded: FIN=${fin} opcode=${op} MASK=${masked} len=${len} -> "${String.fromCharCode(...data)}"`);
console.log("server frame (no mask): " + hex([0x81, text.length, ...text]));

আউটপুট:

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
client frame: 81 85 37 fa 21 3d 7f 9f 4d 51 58
decoded: FIN=1 opcode=1 MASK=1 len=5 -> "Hello"
server frame (no mask): 81 05 48 65 6c 6c 6f

প্রথম লাইন হুবহু RFC 6455-এর উদাহরণের s3pPLMBiTxaQ9kYGzzhZRbK+xOo= — আমাদের ছোট SHA-1 ঠিক কাজ করছে। Client frame-এর 81 = FIN ১ আর opcode ১ (text); 85 = MASK bit ১ আর দৈর্ঘ্য ৫; তারপর ৪ বাইট key 37 fa 21 3d; তারপর mask করা “Hello”. যেমন প্রথম বাইট: ‘H’ = 0x48, 0x48 XOR 0x37 = 0x7f. একই key দিয়ে আবার XOR করলেই আসল লেখা — XOR নিজেই নিজের উল্টো। সার্ভারের frame 81 05 …-এ MASK bit ০, তাই লেখা সরাসরি দেখা যায়। দুটি frame-ই RFC-র §5.7-এর উদাহরণের সাথে মেলে।

Ping/pong, বন্ধ করা আর HTTP/2

Control frame (close, ping, pong) ১২৫ বাইটের বেশি হয় না আর ভাগ হয় না। যেকোনো পক্ষ ping পাঠালে অন্যপক্ষ একই ডেটা দিয়ে pong ফেরায় — সংযোগ বেঁচে আছে কি না দেখা, আর পথের NAT বা load balancer যেন নীরবতার কারণে সংযোগ মুছে না ফেলে (keepalive, পর্ব ১৯)। বন্ধ করতে close frame-এ একটি ২ বাইটের কোড: ১০০০ স্বাভাবিক, ১০০১ চলে যাচ্ছে (যেমন পাতা বন্ধ), ১০০২ protocol ভুল, ১০০৮ নীতি-লঙ্ঘন, ১০০৯ বার্তা খুব বড়, ১০১১ সার্ভারের ভেতরের ত্রুটি; ১০০৬ (অস্বাভাবিকভাবে ভাঙা) তারে কখনো পাঠানো হয় না — শুধু অ্যাপকে জানানো হয় যে close frame ছাড়াই সংযোগ গেছে। HTTP/2-এর একটি সংযোগের ভেতরে একটি stream হিসেবে WebSocket চালানোর পদ্ধতি এসেছে RFC 8441 (২০১৮)-এ, “extended CONNECT” দিয়ে; HTTP/3-এর জন্য একই ধারণার আলাদা মান আছে।

পদ্ধতিদিকTransportভালো যেখানে
Long pollingদুই দিক (ঘুরিয়ে)HTTPখুব পুরোনো পরিবেশে fallback
SSEশুধু সার্ভার → clientHTTP (একটি দীর্ঘ উত্তর)notification, live স্কোর, AI-এর উত্তর লাইন লাইন দেখানো
WebSocketদুই দিক, যেকোনো সময়TCP (+TLS)চ্যাট, সহযোগী editor, ট্রেডিং ড্যাশবোর্ড, ছোট খেলা
WebRTC (মিডিয়া ও data channel)দুই দিক, peer-to-peer সম্ভবUDP (+DTLS/SRTP)ভয়েস-ভিডিও কল, কম দেরির খেলা বা ফাইল-আদানপ্রদান

WebSocket TCP-র ওপর, তাই একটি packet হারালে পরের সব বার্তা অপেক্ষা করে (head-of-line blocking, পর্ব ৩৩) — চ্যাটে সমস্যা নয়, কিন্তু ভিডিও-কলের জন্য অনুপযুক্ত। QUIC-এর ওপর WebTransport এই ফাঁক পূরণ করতে চায় (পর্ব ৩৩-এ উল্লেখ)। ভিডিও-কলের জন্য এবার UDP-র জগতে যাওয়া যাক।

৬ · VoIP — packet বানানো, jitter buffer আর হারানো packet সামলানো

VoIP-এ প্রেরক কণ্ঠকে নির্দিষ্ট মাপের টুকরোয় কাটে — সাধারণত ২০ মিলিসেকেন্ড — আর প্রতিটি টুকরো একটি packet. এই কাটাকে বলে packetization. G.711-এ ২০ মিলিসেকেন্ডে কণ্ঠের বাইট = ৬৪,০০০ ÷ ৮ × ০.০২ = ১৬০ বাইট. প্রতিটি packet-এর সামনে বসে RTP header (১২ বাইট), UDP header (৮), IPv4 header (২০) — মোট ৪০ বাইট। অর্থাৎ ১৬০ বাইটের কণ্ঠের জন্য তারে যায় ২০০ বাইট, সেকেন্ডে ৫০ বার:

IP-স্তরের bitrate = (১৬০ + ৪০) × ৮ × ৫০ = ৮০,০০০ bps = ৮০ kbps (এক দিকে)
Ethernet-এর ১৮ বাইট (header + FCS) ধরলে ২১৮ × ৮ × ৫০ = ৮৭.২ kbps; দুই দিকে কথা চললে প্রতিটি দিকেই এতটা

Packet বড় করলে (যেমন ৩০ মিলিসেকেন্ড) header-এর ভাগ কমে, কিন্তু packet ভরা পর্যন্ত অপেক্ষায় delay বাড়ে, আর একটি packet হারালে বেশি কণ্ঠ হারায়। ২০ মিলিসেকেন্ড জনপ্রিয় সমঝোতা। নিচের ক্যালকুলেটর G.711 আর Opus-এর হিসাব করে, সাথে দলের ভিডিও কলের bandwidth (অংশ ৮)। Opus-এর frame ২.৫ থেকে ৬০ মিলিসেকেন্ডের কয়েকটি নির্দিষ্ট মাপে হয় (৩০ তাদের মধ্যে নেই), তাই Opus-এর জন্য ২০, ৪০ আর ৬০।

// (a) Bandwidth of one voice stream including RTP(12) + UDP(8) + IPv4(20) = 40 header bytes.
const HDR = 12 + 8 + 20;
const cases = [["G.711", 64, 10], ["G.711", 64, 20], ["G.711", 64, 30],
               ["Opus", 24, 20], ["Opus", 24, 40], ["Opus", 24, 60]];
console.log("codec   kbps  ms  payload(B)  packet(B)  pkts/s  IP-kbps  overhead");
for (const [c, kbps, ms] of cases) {
  const pay = kbps * 1000 / 8 * ms / 1000;            // bytes of voice per packet
  const pps = 1000 / ms, ip = (pay + HDR) * 8 * pps / 1000;
  console.log(c.padEnd(8) + String(kbps).padEnd(6) + String(ms).padEnd(4) + String(pay).padEnd(12) +
    String(pay + HDR).padEnd(11) + pps.toFixed(1).padEnd(8) + ip.toFixed(1).padEnd(9) +
    (100 * HDR / (pay + HDR)).toFixed(0) + "%");
}
// (b) Group video call, every participant sends one 1.5 Mbps stream.
const B = 1.5;
console.log("\nN   mesh up/down (Mbps)   SFU up/down   MCU up/down   SFU server in/out");
for (const N of [2, 3, 4, 6, 10]) {
  const mesh = (N - 1) * B, sfuDown = (N - 1) * B;
  console.log(String(N).padEnd(4) + `${mesh} / ${mesh}`.padEnd(22) + `${B} / ${sfuDown}`.padEnd(14) +
    `${B} / ${B}`.padEnd(14) + `${N * B} / ${N * (N - 1) * B}`);
}

আউটপুট:

codec   kbps  ms  payload(B)  packet(B)  pkts/s  IP-kbps  overhead
G.711   64    10  80          120        100.0   96.0     33%
G.711   64    20  160         200        50.0    80.0     20%
G.711   64    30  240         280        33.3    74.7     14%
Opus    24    20  60          100        50.0    40.0     40%
Opus    24    40  120         160        25.0    32.0     25%
Opus    24    60  180         220        16.7    29.3     18%

N   mesh up/down (Mbps)   SFU up/down   MCU up/down   SFU server in/out
2   1.5 / 1.5             1.5 / 1.5     1.5 / 1.5     3 / 3
3   3 / 3                 1.5 / 3       1.5 / 1.5     4.5 / 9
4   4.5 / 4.5             1.5 / 4.5     1.5 / 1.5     6 / 18
6   7.5 / 7.5             1.5 / 7.5     1.5 / 1.5     9 / 45
10  13.5 / 13.5           1.5 / 13.5    1.5 / 1.5     15 / 135

G.711-এ packet ১০ থেকে ৩০ মিলিসেকেন্ডে বাড়ালে তারের bitrate ৯৬ থেকে ৭৪.৭ kbps-এ নামে, header-এর ভাগ ৩৩% থেকে ১৪%. Opus ২৪ kbps-এ ২০ মিলিসেকেন্ডের packet-এ কণ্ঠ মাত্র ৬০ বাইট, header ৪০ — খরচের ৪০%-ই header! তাই কম-bitrate codec-এ header-এর বোঝা আনুপাতিক হারে বেশি, আর এজন্যই মোবাইল নেটওয়ার্কে header compression (যেমন ROHC) ব্যবহার হয়। নিচের অংশ (b) অংশ ৮-এ ব্যাখ্যা করা হয়েছে।

Jitter আর playout delay

প্রেরক প্রতি ২০ মিলিসেকেন্ডে নিখুঁত তালে packet পাঠায়, কিন্তু পথের queue-তে প্রতিটি আলাদা সময় অপেক্ষা করে — একটি ৫৫ মিলিসেকেন্ডে পৌঁছায়, পরেরটি ৬২-তে, আরেকটি ১৪০-এ। এই ওঠানামাই jitter. আসামাত্র বাজালে কণ্ঠ কাঁপবে আর ফাঁক পড়বে। তাই প্রাপক প্রতিটি packet একটি নির্দিষ্ট playout delay q পরে বাজায়: যে packet সময় t-তে তৈরি হয়েছিল (RTP timestamp থেকে জানা), সেটি বাজবে t + q-তে। তার আগে এলে buffer-এ অপেক্ষা করে; পরে এলে বাজানোর সময় পেরিয়ে গেছে — সেটি দেরির কারণে হারানো (late loss) হিসেবে ফেলে দেওয়া হয়। q বড় মানে কম ক্ষতি কিন্তু বেশি দেরি; q ছোট মানে উল্টো।

  1. প্রেরকপ্রতি 20 mst = 0, 20, 40…
  2. পথdelay 48–140 msjitter
  3. Jitter bufferবাজবে t + 100পরে এলে বাদ
  4. স্পিকার৮টি বাজল২টি বাদ
প্রতিটি সিদ্ধান্ত (ms)
Packet
তৈরি (t)
পৌঁছাল
বাজার সময় t + 100
সিদ্ধান্ত
  1. Packet 1 আগেভাগে। t = ০-তে তৈরি, ৫৫-তে পৌঁছাল, বাজার কথা ১০০-তে — buffer-এ ৪৫ মিলিসেকেন্ড অপেক্ষা করে ঠিক সময়ে বাজল।
  2. Packet 4 টানটান। ৬০-তে তৈরি, পথে ৯৫ মিলিসেকেন্ড লাগল, পৌঁছাল ১৫৫-তে; বাজার সময় ১৬০ — মাত্র ৫ মিলিসেকেন্ড হাতে রেখে বাঁচল।
  3. Packet 6 দেরিতে। ১০০-তে তৈরি, পথে ১৪০ মিলিসেকেন্ড, পৌঁছাল ২৪০-এ; কিন্তু তার বাজার সময় ২০০ পেরিয়ে গেছে। পরের packet-গুলো ততক্ষণে বাজছে, তাই এটি ফেলে দেওয়া হলো — সেই ২০ মিলিসেকেন্ড ঢাকতে হবে অন্য কৌশলে।
  4. Packet 9-ও অল্পের জন্য দেরি। ১৬০-তে তৈরি, ২৬৫-তে পৌঁছাল, সময়সীমা ২৬০ — ৫ মিলিসেকেন্ডের জন্য বাদ। q = ১১০ হলে বাঁচত।
  5. ফল: ১০টির ২টি বাদ — ২০% ক্ষতি। q = ৬০ হলে ৭টি বাদ পড়ত, q = ১৫০ হলে একটিও না — কিন্তু তখন মুখ থেকে কানে শুধু এখানেই ১৫০ মিলিসেকেন্ড, পুরো G.114 বাজেট শেষ। নিচের simulator তিনটি q একসাথে দেখায়।

Adaptive playout: একটি স্থির q সব নেটওয়ার্কে খাটে না। Kurose-Ross-এর পাঠ্যবইয়ের পদ্ধতিতে প্রাপক প্রতিটি packet-এর delay দেখে চলমান গড় (EWMA) রাখে — dᵢ = (১ − u)·dᵢ₋₁ + u·(rᵢ − tᵢ) — আর বিচ্যুতির গড় vᵢ = (১ − u)·vᵢ₋₁ + u·|rᵢ − tᵢ − dᵢ|, যেখানে rᵢ পৌঁছানোর সময়। কথার প্রতিটি নতুন অংশের (talk spurt, নীরবতার পরে) শুরুতে playout delay ঠিক হয় d + ৪v; নীরবতা একটু লম্বা বা ছোট হলে কেউ টের পায় না। বইয়ে u = ০.০১; এখানে বদল চোখে পড়ার জন্য u = ০.১. মিলটি TCP-র RTO হিসাবের (পর্ব ৩০) সাথে।

// VoIP receiver: one packet every 20 ms (timestamp t). Network delay varies (jitter).
// Fixed playout: packet i is played at t_i + q; if it arrives after that it is LATE (= lost).
const delay = [55, 62, 48, 95, 70, 140, 66, 58, 105, 72];   // one-way delay of each packet, ms
const pk = delay.map((d, i) => ({ seq: i + 1, t: 20 * i, arr: 20 * i + d }));
console.log("seq  sent  arrives  " + [60, 100, 150].map(q => ("q=" + q).padEnd(7)).join(""));
for (const p of pk)
  console.log(String(p.seq).padEnd(5) + String(p.t).padEnd(6) + String(p.arr).padEnd(9) +
    [60, 100, 150].map(q => (p.arr <= p.t + q ? "play" : "LATE").padEnd(7)).join(""));
for (const q of [60, 100, 150]) {
  const late = pk.filter(p => p.arr > p.t + q).length;
  console.log(`q=${q} ms: ${late} of ${pk.length} late (${(100 * late / pk.length).toFixed(0)}% loss)`);
}
// Adaptive playout (Kurose-Ross style): EWMA of delay d and of deviation v, u = 0.1 here.
// The delay used for the NEXT talk spurt = d + 4v.
const u = 0.1; let d = delay[0], v = 0;
console.log("\nseq  delay  d(avg)  v(dev)  d+4v");
pk.forEach((p, i) => {
  const r = p.arr - p.t;                          // measured network delay of this packet
  if (i > 0) { d = (1 - u) * d + u * r; v = (1 - u) * v + u * Math.abs(r - d); }
  console.log(String(p.seq).padEnd(5) + String(r).padEnd(7) + d.toFixed(1).padEnd(8) +
    v.toFixed(1).padEnd(8) + (d + 4 * v).toFixed(1));
});

আউটপুট:

seq  sent  arrives  q=60   q=100  q=150
1    0     55       play   play   play
2    20    82       LATE   play   play
3    40    88       play   play   play
4    60    155      LATE   play   play
5    80    150      LATE   play   play
6    100   240      LATE   LATE   play
7    120   186      LATE   play   play
8    140   198      play   play   play
9    160   265      LATE   LATE   play
10   180   252      LATE   play   play
q=60 ms: 7 of 10 late (70% loss)
q=100 ms: 2 of 10 late (20% loss)
q=150 ms: 0 of 10 late (0% loss)

seq  delay  d(avg)  v(dev)  d+4v
1    55     55.0    0.0     55.0
2    62     55.7    0.6     58.2
3    48     54.9    1.3     60.0
4    95     58.9    4.7     77.9
5    70     60.0    5.3     81.1
6    140    68.0    11.9    115.8
7    66     67.8    10.9    111.5
8    58     66.9    10.7    109.7
9    105    70.7    13.1    123.0
10   72     70.8    11.9    118.4

প্রথম টেবিল stepper-এর সাথে মেলে: q = ১০০-তে শুধু 6 আর 9 “LATE”. q = ৬০-তে ৭০% ক্ষতি — কণ্ঠ অচল; q = ১৫০-তে শূন্য। দ্বিতীয় টেবিলে d ধীরে ধীরে ৫৫ থেকে ৭০.৮-এ উঠেছে, আর ১৪০ মিলিসেকেন্ডের packet 6 আসার পর v লাফিয়ে ১১.৯ — ফলে পরের talk spurt-এর জন্য প্রস্তাবিত delay d + ৪v ≈ ১১৬, শেষে ১১৮.৪ মিলিসেকেন্ড। ভালো নেটওয়ার্কে v ছোট থাকে, তাই অপেক্ষাও কম।

হারানো packet সামলানো — FEC, interleaving আর আন্দাজ

দেরিতে আসা বা পথে হারানো packet আবার চাওয়ার সময় নেই — একটি RTT-ই হয়তো ১০০ মিলিসেকেন্ড। তাই তিনটি কৌশল:

  • FEC (আগেভাগে বাড়তি পাঠানো): (ক) প্রতি n টি packet-এর পর তাদের XOR-এর একটি বাড়তি packet — n+১টির যেকোনো একটি হারালে বাকিগুলো থেকে পুনর্গঠন; খরচ ১/n বাড়তি bandwidth আর n টি packet-এর অপেক্ষা। (খ) পিঠে চড়ানো কম-মানের কপি: packet n-এ থাকে টুকরো n পুরো মানে আর টুকরো n−১ খুব কম bitrate-এ (পাঠ্যবইয়ের উদাহরণ ৬৪ kbps PCM-এর সাথে ১৩ kbps GSM). n−১ হারালে প্রাপক কম-মানের কপিটি বাজায় — কণ্ঠ মুহূর্তের জন্য একটু ভোঁতা, কিন্তু ফাঁক নেই। Opus-এর ভেতরে এমন একটি in-band FEC আছে।
  • Interleaving: ২০ মিলিসেকেন্ডের টুকরোকে ৫ মিলিসেকেন্ডের চারটি ছোট অংশে ভাগ করে বিভিন্ন packet-এ ছড়িয়ে দেওয়া — packet ১-এ অংশ ১, ৫, ৯, ১৩; packet ২-এ ২, ৬, ১০, ১৪ ইত্যাদি। একটি packet হারালে ২০ মিলিসেকেন্ডের এক বড় ফাঁকের বদলে চারটি ৫ মিলিসেকেন্ডের ছোট ফাঁক, যা কান প্রায় ধরে না। দাম: পুরো দল আসা পর্যন্ত অপেক্ষা, অর্থাৎ বাড়তি delay.
  • Loss concealment (প্রাপকের আন্দাজ): আগের টুকরো আবার বাজানো বা আগে-পরের শব্দ থেকে মাঝখানটা বানিয়ে নেওয়া। কণ্ঠ ছোট সময়ে প্রায় একই থাকে বলে অল্প ক্ষতিতে ভালো কাজ করে।

৭ · RTP, RTCP আর SIP — কথার খাম, রিপোর্ট আর ঘণ্টা বাজানো

RTP (RFC 3550, ২০০৩; প্রথম সংস্করণ RFC 1889, ১৯৯৬) নিজে কোনো নিশ্চয়তা দেয় না — না পৌঁছানো, না সময়। এটি শুধু একটি মানসম্মত খাম, যাতে প্রাপক জানে কোন packet কোনটার পরে, কোন মুহূর্তের কণ্ঠ, কোন উৎসের আর কোন codec-এর। Header-এর প্রথম ১২ বাইট:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───┬─┬─┬───────┬─┬─────────────┬───────────────────────────────┐
│V=2│P│X│  CC   │M│     PT      │        sequence number        │
├───┴─┴─┴───────┴─┴─────────────┴───────────────────────────────┤
│                           timestamp                           │
├───────────────────────────────────────────────────────────────┤
│                 SSRC (synchronization source)                 │
└───────────────────────────────────────────────────────────────┘
  • Payload type (PT, ৭ bit): কোন codec — যেমন ০ মানে G.711 μ-law, ৮ মানে A-law; ৯৬–১২৭ “dynamic”, যার অর্থ SDP-তে ঠিক হয় (Opus সাধারণত এখানে)।
  • Sequence number (১৬ bit): প্রতি packet-এ ১ বাড়ে — হারানো বা ক্রমভঙ্গ ধরার জন্য।
  • Timestamp (৩২ bit): sampling-ঘড়ির একক, সময় নয়। G.711-এ ঘড়ি ৮,০০০ Hz, তাই ২০ মিলিসেকেন্ডের packet-এ timestamp ১৬০ করে বাড়ে; নীরবতায় packet না গেলেও ঘড়ি চলতে থাকে, তাই jitter buffer ঠিক জানে কখন বাজাতে হবে। ভিডিওতে সাধারণত ৯০,০০০ Hz ঘড়ি, আর একটি frame-এর সব packet-এর timestamp একই।
  • SSRC (৩২ bit): stream-এর এলোমেলো পরিচয় — একটি কলে কণ্ঠ আর ভিডিও আলাদা SSRC.
  • Marker (M): বিশেষ মুহূর্ত — অডিওতে নীরবতার পর নতুন talk spurt, ভিডিওতে একটি frame-এর শেষ packet.

সাথী protocol RTCP মাঝে মাঝে রিপোর্ট পাঠায় — মোট bandwidth-এর মোটামুটি ৫%-এর মধ্যে রাখার নিয়মে। Receiver report-এ থাকে কত শতাংশ packet হারাল, মোট হারানো, আর আগমনের jitter-এর হিসাব; sender report-এ RTP timestamp-এর সাথে প্রকৃত ঘড়ির সময় মেলানো, যা দিয়ে আলাদা SSRC-র কণ্ঠ আর ঠোঁট নড়া (lip-sync) মেলানো হয়। প্রেরক এই রিপোর্ট দেখে bitrate কমায়-বাড়ায়। RTP-র packet-কে আলাদা অগ্রাধিকার দেওয়া নেটওয়ার্কের কাজ — DSCP EF আর QoS (পর্ব ২৬)।

SIP — কল বাজানো আর কাটা

কণ্ঠ পাঠানোর আগে কাউকে খুঁজে পেতে হয়, রাজি করাতে হয়, আর codec মেলাতে হয়। এই signalling-এর প্রচলিত মান SIP (RFC 3261, ২০০২) — HTTP-র মতো লেখা-ভিত্তিক অনুরোধ-উত্তর, ঠিকানা দেখতে ইমেইলের মতো (sip:rina@example.com), সাধারণত port 5060 (UDP/TCP) আর TLS-এ 5061. ভেতরে codec আর ঠিকানার প্রস্তাব থাকে SDP-তে। একটি সাধারণ কল:

রিনা                     SIP proxy                    করিম
 │── INVITE (SDP offer) ──►│── INVITE ───────────────────►│
 │◄── 100 Trying ──────────│                              │
 │◄── 180 Ringing ─────────│◄── 180 Ringing ──────────────│  (ফোন বাজছে)
 │◄── 200 OK (SDP answer) ─│◄── 200 OK ───────────────────│  (করিম ধরলেন)
 │── ACK ────────────────────────────────────────────────►│
 │◄═════════════ RTP কণ্ঠ (সরাসরি, proxy ছাড়া) ═════════►│
 │── BYE ────────────────────────────────────────────────►│
 │◄── 200 OK ─────────────────────────────────────────────│

লক্ষ করুন, signalling proxy দিয়ে যায়, কিন্তু কণ্ঠ সরাসরি — রিসেপশন কল জুড়ে দেয়, তারপর কথা আর রিসেপশন দিয়ে যায় না। অফিসের IP-PBX আর মোবাইলের VoLTE-র signalling-এ SIP-এর বিভিন্ন রূপ চলে। SDP-র ভেতরে private ঠিকানা লেখা থাকে বলে NAT-এর পেছনে SIP-এর পুরোনো সমস্যা — পর্ব ১৯-এর NAT traversal দেখুন।

৮ · WebRTC — ব্রাউজারে ব্রাউজারে সরাসরি কল

WebRTC হলো W3C-র JavaScript API আর IETF-এর protocol-সমষ্টি, যা দিয়ে কোনো plugin ছাড়া ব্রাউজার বা অ্যাপ সরাসরি কণ্ঠ, ভিডিও আর ডেটা আদানপ্রদান করে। Google ২০১০ সালে GIPS নামের ভয়েস-প্রযুক্তি কোম্পানি কিনে ২০১১ সালে কোড উন্মুক্ত করে; W3C-র মূল স্পেসিফিকেশন আর IETF-এর মূল RFC-গুলো (RFC 8825 থেকে শুরু) ২০২১ সালে চূড়ান্ত হয়। তিনটি মূল API:

  • getUserMedia() — অনুমতি নিয়ে ক্যামেরা আর মাইক্রোফোন খোলা।
  • RTCPeerConnection — অন্য peer-এর সাথে সংযোগ: NAT পেরোনো, এনক্রিপশন, codec, jitter buffer, congestion control — সব ভেতরে।
  • RTCDataChannel — যেকোনো ডেটা (চ্যাট, ফাইল, খেলার অবস্থা); নির্ভরযোগ্য বা অনির্ভরযোগ্য, ক্রমসহ বা ছাড়া — SCTP-এর ওপর, যা আবার DTLS আর UDP-র ভেতরে।
মূল ধারণা

WebRTC signalling নির্ধারণ করে না। দুই ব্রাউজার একে অপরের ঠিকানা জানে না; প্রথম পরিচয় করিয়ে দিতে আপনার নিজের একটি সার্ভার লাগে — প্রায়ই WebSocket দিয়ে (অংশ ৫), চাইলে SIP বা সাধারণ HTTP. সেই সার্ভার শুধু দুটি লেখা আদানপ্রদান করে: SDP offer/answer (কোন codec, কোন এনক্রিপশন-চাবির fingerprint) আর ICE candidate (কোন কোন ঠিকানায় পৌঁছানো যেতে পারে)। তারপর মিডিয়া সম্ভব হলে সরাসরি peer থেকে peer-এ।

এনক্রিপশন WebRTC-তে ঐচ্ছিক নয়: মিডিয়া চলে SRTP-তে (RTP-র এনক্রিপ্টেড রূপ), যার চাবি আসে প্রতিটি সংযোগে একটি DTLS handshake থেকে (DTLS-SRTP, RFC 5764). DTLS হলো UDP-র জন্য TLS. প্রতিটি peer-এর certificate নিজের তৈরি — কোনো CA নেই; বিশ্বাস আসে SDP-তে লেখা certificate fingerprint থেকে, অর্থাৎ signalling সার্ভারের সততার ওপর। NAT পেরোতে ব্যবহার হয় ICE, STUN আর TURN — এগুলোর ভেতরের কাজ পর্ব ১৯-এ বিস্তারিত দেখেছেন; এখানে দেখি পুরো কলে তারা কোথায় বসে।

  1. রিনা192.168.0.105বাসার Wi-Fi, NAT
  2. Signalling সার্ভারwss://আপনার নিজের
  3. করিম10.64.12.9মোবাইল ডেটা, CGNAT
  4. STUN / TURN192.0.2.50ঠিকানা জানা / relay
কোথা দিয়ে কী যাচ্ছে
ধাপ
পথ
বার্তা
অবস্থা
  1. প্রস্তুতি। রিনার ব্রাউজার ক্যামেরা-মাইকের অনুমতি নিল, একটি RTCPeerConnection বানাল, আর createOffer() দিয়ে SDP লিখল: কোন codec পারে, কোন এনক্রিপশন-চাবির fingerprint, ICE-এর ছোট পরিচয়-শব্দ। এখনো নেটওয়ার্কে কিছু যায়নি।
  2. Offer যায় signalling সার্ভার দিয়ে। রিনা জানে না করিম কোথায়; দুজনেই আগে থেকে একই সার্ভারে WebSocket দিয়ে যুক্ত। সার্ভার offer-টি করিমকে পৌঁছে দিল — লেখাটি সে বোঝে না, শুধু বাহক।
  3. Answer ফেরে। করিমের ব্রাউজার দুজনের মিল থাকা codec বেছে answer লিখল, নিজের fingerprint-সহ, আর একই পথে ফেরত পাঠাল। দুই দিকের বর্ণনা এখন মিলেছে (signalling state “stable”).
  4. ঠিকানার তালিকা। প্রত্যেকে নিজের সম্ভাব্য ঠিকানা জোগাড় করে: নিজের যন্ত্রের (host), STUN-কে জিজ্ঞেস করে NAT-এর বাইরের ঠিকানা (server-reflexive, যেমন 203.0.113.7:61000), আর TURN সার্ভারে ভাড়া নেওয়া relay ঠিকানা। প্রতিটি candidate পাওয়ামাত্র signalling দিয়ে পাঠানো হয় (trickle ICE).
  5. কোন পথ কাজ করে? দুই পক্ষ candidate-জোড়াগুলোতে STUN Binding বার্তা পাঠিয়ে পরীক্ষা করে — UDP hole punching (পর্ব ১৯)। করিমের CGNAT সহজ ধরনের হলে সরাসরি পথ পাওয়া যায়; কঠোর হলে TURN relay-ই শেষ ভরসা, তখন সব মিডিয়া TURN সার্ভার দিয়ে যায় আর তার bandwidth-এর খরচ আপনার।
  6. এনক্রিপশন চালু। বাছাই করা পথেই DTLS handshake. প্রত্যেকে মিলিয়ে দেখে অন্যজনের certificate-এর fingerprint SDP-তে যা লেখা ছিল তার সাথে মেলে কি না; মিললে SRTP-র চাবি তৈরি হয়।
  7. কথা শুরু। কণ্ঠ আর ভিডিও SRTP-তে, ডেটা SCTP/DTLS-এ — সব একই UDP port-এ একসাথে (BUNDLE আর rtcp-mux). ঢাকা থেকে চট্টগ্রাম সরাসরি পথে গেলে delay কম; TURN সার্ভার বিদেশে হলে কণ্ঠ বিদেশ ঘুরে আসে — TURN কোথায় রাখবেন সেটি গুরুত্বপূর্ণ নকশা-সিদ্ধান্ত।

দলের কল — mesh, SFU না MCU

দুজনের কলে সরাসরি পথই সেরা। কিন্তু N জনের মিটিংয়ে? তিনটি নকশা — উপরের ক্যালকুলেটরের অংশ (b) দেখুন, প্রত্যেকে ১.৫ Mbps-এর একটি ভিডিও পাঠান:

  • Mesh: প্রত্যেকে প্রত্যেকের সাথে সরাসরি। প্রত্যেককে N − ১টি কপি upload করতে হয় — ৬ জনে ৭.৫ Mbps upload, ১০ জনে ১৩.৫. বাসার সংযোগে upload সাধারণত download-এর চেয়ে কম, আর প্রতিটি কপি আলাদা encode করলে CPU-ও শেষ। ৩–৪ জনের বেশি হলে অচল।
  • SFU (Selective Forwarding Unit): প্রত্যেকে একটিমাত্র stream সার্ভারে পাঠায় (upload ১.৫), সার্ভার decode না করে শুধু বেছে বেছে অন্যদের কাছে ফরোয়ার্ড করে (download N − ১ গুণ)। সার্ভারের দিকে ১০ জনে ঢোকে ১৫, বের হয় ১৩৫ Mbps. Simulcast-এ প্রত্যেকে একই ভিডিও ২–৩টি মানে পাঠায়, আর SFU যার সংযোগ দুর্বল তাকে নিচু মানটি দেয়; বাস্তবে শুধু যিনি কথা বলছেন বা পর্দায় দেখা যাচ্ছে তাদের ভিডিওই পাঠানো হয়।
  • MCU (Multipoint Control Unit): সার্ভার সব ভিডিও decode করে একটি মিশ্র ছবি বানিয়ে আবার encode করে প্রত্যেককে একটি stream দেয় — client-এর upload আর download দুটোই কম, কিন্তু সার্ভারের CPU-খরচ বিশাল, দেরি বাড়ে, আর end-to-end এনক্রিপশন কঠিন।

মিডিয়ার congestion control

TCP-র loss-ভিত্তিক congestion control (পর্ব ৩২) ভিডিও-কলের জন্য ধীর আর রূঢ় — packet হারানো পর্যন্ত অপেক্ষা করলে ততক্ষণে router-এর queue ভরে delay বেড়ে গেছে। তাই WebRTC-র বাস্তবায়নগুলো delay-ভিত্তিক পদ্ধতি ব্যবহার করে: packet-এর পৌঁছানোর ফাঁক ক্রমে বাড়তে থাকলে queue জমছে ধরে নিয়ে bitrate কমায়। Google-এর প্রস্তাবিত GCC (Google Congestion Control) সবচেয়ে পরিচিত; এটি IETF-এ খসড়া হিসেবে প্রকাশিত হয়েছিল, পূর্ণ মান হয়নি, আর Chrome-এর বর্তমান বাস্তবায়ন সময়ের সাথে বদলেছে। মূল ধারণা মনে রাখুন: মিডিয়ার জন্য queue ভরার আগেই পিছু হটা, আর bitrate কমাতে encoder-কেই বলা — ছবির মান বা frame rate কমিয়ে।

৯ · Live streaming-এর পথ, বাংলাদেশের বাস্তবতা আর গভীরে

একটি live সম্প্রচারের দুই প্রান্ত। Ingest — ক্যামেরা বা encoder থেকে streaming প্ল্যাটফর্মে পাঠানো; Delivery — প্ল্যাটফর্ম থেকে লক্ষ দর্শকের কাছে, সাধারণত HLS/DASH আর CDN দিয়ে (অংশ ৪)।

  • RTMP: Macromedia/Adobe-এর Flash যুগের TCP-ভিত্তিক protocol (সাধারণত port 1935). দর্শকের দিকে Flash বিদায় নিয়েছে, কিন্তু ingest-এ RTMP এখনো খুব প্রচলিত — অনেক প্ল্যাটফর্ম আর সম্প্রচার-সফটওয়্যার এটাই নেয়।
  • SRT (Secure Reliable Transport): Haivision-এর তৈরি, ২০১৭ সালে উন্মুক্ত; UDP-র ওপর নিজস্ব দ্রুত পুনঃপ্রেরণ, এনক্রিপশন, আর একটি নির্দিষ্ট latency-সীমা — সীমার মধ্যে যা ফেরত আনা যায় আনে, না গেলে ছেড়ে দেয়। অস্থির ইন্টারনেট দিয়ে পেশাদার সম্প্রচারে জনপ্রিয়।
  • WebRTC-ভিত্তিক live: নিলাম, অনলাইন খেলা বা দর্শকের সাথে কথোপকথনের অনুষ্ঠানে এক সেকেন্ডের কম দেরি দরকার হলে। Ingest-এর জন্য WHIP আর playback-এর জন্য WHEP নামে HTTP-ভিত্তিক সহজ signalling প্রমিত হয়েছে বা হচ্ছে। দাম: লক্ষ দর্শকের জন্য SFU-র শিকল বানাতে হয়, সাধারণ HTTP CDN-এর মতো সস্তা নয়।

বাংলাদেশের বাস্তবতা

বাংলাদেশে ইন্টারনেট ব্যবহারকারীর বড় অংশ মোবাইল ডেটায় — যেখানে গতি জায়গা ও সময়ভেদে অনেক ওঠানামা করে, আর ডেটা প্যাকের সীমা থাকে। তাই ABR এখানে বিলাসিতা নয়, মূল প্রয়োজন: বাসে চলতে চলতে নাটক দেখার সময় গতি বারবার নামলে নিচু মানে নেমে না থামাই ভালো অভিজ্ঞতা। অনেক অ্যাপ “ডেটা সাশ্রয়” বিকল্পে সর্বোচ্চ মান বেঁধে দেয় — ১০ মিনিট ১০৮০p (ধরুন ৫ Mbps) মানে প্রায় ৩৭৫ MB, আর ৪৮০p (১ Mbps) মানে প্রায় ৭৫ MB. ভয়েস-কলে Opus-এর মতো কম-bitrate codec আর FEC দুর্বল সংকেতে বড় পার্থক্য আনে। দেশের ভেতরের CDN cache আর BDIX-এর মতো স্থানীয় আদানপ্রদান (পর্ব ২৫) জনপ্রিয় ভিডিও কাছে আনতে সাহায্য করে; নির্দিষ্ট পরিসংখ্যান সময়ভেদে বদলায়।

আরও গভীরে: RTP-র timestamp ঘড়ি শুরু হয় এলোমেলো মান থেকে, আর RTCP sender report-এর NTP-সময় দিয়ে আলাদা stream-এর timestamp একটি সাধারণ ঘড়িতে আনা হয় — lip-sync এভাবেই। WebRTC-র ভেতরের jitter buffer (NetEQ) শব্দ-প্রক্রিয়াকরণ দিয়ে কথা সামান্য দ্রুত বা ধীর বাজিয়ে buffer বদলায়, স্বর না বদলে। আর end-to-end এনক্রিপশনের জন্য SFU-র ওপরে মিডিয়া-স্তরে আরেক স্তর এনক্রিপশন (যেমন SFrame নামের IETF মান) ব্যবহার হয়, যাতে SFU শুধু header দেখে ফরোয়ার্ড করে কিন্তু ছবি বা কণ্ঠ খুলতে পারে না।

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • ভয়েস কল কেন UDP-তে, ভিডিও streaming কেন HTTP/TCP-তে? — কলে ১৫০ মিলিসেকেন্ডের বাজেটে পুনঃপ্রেরণের সময় নেই; জমা ভিডিওতে buffer সময় দেয়, আর HTTP CDN ও firewall-বান্ধব।
  • G.711, ২০ মিলিসেকেন্ড, RTP/UDP/IPv4-এ bandwidth কত? — ১৬০ + ৪০ = ২০০ বাইট × ৫০ = ৮০ kbps প্রতি দিকে।
  • Jitter buffer কী আর তার মূল্য কী? — packet নির্দিষ্ট playout delay পরে বাজানো; বড় delay মানে কম late loss কিন্তু বেশি দেরি।
  • WebSocket handshake কীভাবে হয়? — HTTP/1.1 Upgrade, key + GUID-এর SHA-1-এর base64 = Sec-WebSocket-Accept, উত্তর 101; client-এর frame সবসময় mask করা।
  • WebRTC-তে signalling কে করে? — মান নির্ধারণ করে না; অ্যাপের নিজের সার্ভার SDP আর ICE candidate বহন করে; মিডিয়া DTLS-SRTP-তে।

১০ · AI-এর যুগে real-time আর streaming — শেখা আর যাচাই

“একটি ভিডিও-কল অ্যাপ বানিয়ে দিন” — AI কয়েক মিনিটে চলনসই WebRTC কোড দেয়। কিন্তু নেটওয়ার্কের খুঁটিনাটিতে চেনা ভুল আছে:

AI-এর ভুলআসল কথাকীভাবে যাচাই করবেন
“G.711 কল মানে ৬৪ kbps bandwidth”Header-সহ ২০ মিলিসেকেন্ডে ৮০ kbps (IP-স্তরে)অংশ ৬-এর ক্যালকুলেটরে নিজে হিসাব
“WebRTC সবসময় peer-to-peer, সার্ভার লাগে না”Signalling সার্ভার লাগেই, অনেক সময় TURN-ও; দলের কলে SFUব্রাউজারের chrome://webrtc-internals-এ বাছাই করা candidate দেখুন
Demo-তে শুধু STUN, কোনো TURN নেই, বা TURN-এর স্থায়ী পাসওয়ার্ড কোডে লেখাকঠোর NAT-এ কল ব্যর্থ হবে; TURN-এর জন্য স্বল্পমেয়াদি credentialআলাদা মোবাইল নেটওয়ার্ক থেকে নিজের দুই যন্ত্রে পরীক্ষা
“WebSocket mask এনক্রিপশন দেয়” বা ws:// দিয়ে লগইন-টোকেন পাঠানোMask শুধু proxy-সুরক্ষা; গোপনীয়তার জন্য wss:// আর Origin যাচাইRFC 6455 §10 পড়ুন, নিজের ল্যাবে Wireshark-এ দেখুন
ভুল RFC নম্বর বা পুরোনো তথ্য (যেমন “HLS-এ segment সবসময় ১০ সেকেন্ড”)RTP 3550, SIP 3261, WebSocket 6455, HLS 8216; segment দৈর্ঘ্য নকশাভেদেrfc-editor.org-এ নম্বর আর শিরোনাম মেলান
“কল কাটছে? firewall-এ সব UDP port খুলে দিন”শুধু দরকারি port-পরিসর, বা TURN-কে TCP/TLS 443-এ রাখানিরাপত্তা নীতি মিলিয়ে নিন, পর্ব ৪৯

AI-কে কাজে লাগান, তবে হিসাব আর উৎস চেয়ে নিন:

তুমি একজন real-time মিডিয়া প্রকৌশলীর মতো উত্তর দাও। ১. Opus 32 kbps, 20 ms packet, RTP/UDP/IPv6-এ এক দিকের bitrate কত? প্রতিটি header-এর বাইট আলাদা দেখাও। ২. ৮ জনের ভিডিও মিটিং, প্রত্যেকে 1.2 Mbps — mesh আর SFU-তে প্রত্যেকের upload/download আর SFU সার্ভারের মোট bandwidth হিসাব করো। ৩. আমার ল্যাবে একটি ছোট WebRTC demo (নিজের signalling সার্ভার, WebSocket দিয়ে) বানাতে চাই; TURN-এর credential কীভাবে নিরাপদে দেব? ৪. প্রতিটি দাবির পাশে RFC নম্বর আর section দাও; নিশ্চিত না হলে স্পষ্ট বলো। ৫. Firewall বা নিরাপত্তা-সংক্রান্ত পরামর্শে ঝুঁকি আলাদা করে লেখো।

AI-এর উত্তর বিশ্বাস করার আগে — চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১জমা ভিডিওর জন্য একসময় RTSP/RTP-র মতো বিশেষ streaming protocol ছিল। তবু আজ প্রায় সব প্ল্যাটফর্ম সাধারণ HTTP-র ওপর DASH/HLS চালায় কেন?

১৯৯০-এর দশকের শেষে আর ২০০০-এর দশকে streaming মানে ছিল বিশেষ সার্ভার: RealNetworks, Windows Media, Flash-এর RTMP, আর IETF-এর RTSP (নিয়ন্ত্রণ) ও RTP (মিডিয়া)। সার্ভার প্রতিটি দর্শকের অবস্থা মনে রাখত — কোথায় থেমেছে, কোন গতিতে পাঠাতে হবে। এতে তিনটি বড় সমস্যা ছিল। প্রথমত, অফিস আর বাসার firewall ও NAT প্রায়ই এই অচেনা port আর UDP আটকে দিত, অথচ HTTP সবখানে খোলা। দ্বিতীয়ত, বিশেষ সার্ভার মানে বিশেষ খরচ — সাধারণ ওয়েব-cache আর CDN-এর বিশাল অবকাঠামো কাজে লাগত না। তৃতীয়ত, প্রতিটি দর্শকের জন্য অবস্থা রাখা সার্ভারকে বড় করা কঠিন।

২০০০-এর দশকের শেষে Move Networks, Microsoft-এর Smooth Streaming আর ২০০৯ সালে Apple-এর HLS একটি সরল ধারণা জনপ্রিয় করল: ভিডিওকে ছোট ফাইলে কাটা, সাধারণ ওয়েব সার্ভারে রাখা, আর সব বুদ্ধি client-কে দেওয়া। প্রতিটি segment এখন একটি সাধারণ GET — যেকোনো CDN cache করতে পারে, যেকোনো firewall পার হতে দেয়, সার্ভারের কোনো অবস্থা মনে রাখার দরকার নেই। ২০১২ সালে MPEG-DASH একই ধারণাকে আন্তর্জাতিক মান বানাল।

দাম কী? TCP-র ওপর বলে হারানো packet-এ দেরি হয়, আর segment-ভিত্তিক বলে live-এ কয়েক সেকেন্ড থেকে আধা মিনিট পিছিয়ে থাকা স্বাভাবিক। জমা ভিডিওতে buffer সেই দাম ঢেকে দেয়, তাই লাভটা অনেক বড়। Live-এ কম দেরির চাহিদা থেকে এসেছে LL-HLS আর chunked CMAF — আবারও HTTP-র মধ্যেই সমাধান খোঁজা, কারণ CDN-এর অর্থনীতি ছাড়া কোটি দর্শক সামলানো কঠিন। আর যেখানে সত্যিই এক সেকেন্ডের কম দেরি লাগে, সেখানে আবার RTP-ভিত্তিক WebRTC ফিরে আসছে — পুরোনো ধারণা, নতুন মোড়কে।

মূল উপলব্ধি: প্রযুক্তিগতভাবে “সেরা” protocol নয়, যে protocol বিদ্যমান অবকাঠামো (cache, CDN, firewall) সবচেয়ে ভালো কাজে লাগায় — সেটাই জেতে। এটি ইন্টারনেটের নকশার একটি বারবার ফিরে আসা শিক্ষা।

প্র ০২WebRTC এনক্রিপশন বাধ্যতামূলক করল, অথচ signalling-কে একেবারে অনির্ধারিত রাখল। দুটি সিদ্ধান্তের পেছনের যুক্তি আর তাদের ফল কী?

WebRTC-র মান তৈরির কাজ শুরু হয় ২০১১ সালে, W3C আর IETF মিলে। এর আগে VoIP-এ এনক্রিপশন ছিল ঐচ্ছিক — অনেক SIP ফোন সাদা RTP পাঠাত, আর একই নেটওয়ার্কে থাকা কেউ কথা শুনে ফেলতে পারত। ২০১৩ সালের পর ব্যাপক নজরদারি নিয়ে আলোচনায় IETF-এর মধ্যে মত দৃঢ় হয় যে নতুন protocol-এ এনক্রিপশন ঐচ্ছিক রাখা চলবে না, কারণ ঐচ্ছিক জিনিস প্রায়ই বন্ধ থাকে। ব্রাউজার যেকোনো ওয়েবসাইট থেকে ক্যামেরা চালু করতে পারে — তাই WebRTC-তে সাদা মিডিয়ার কোনো পথই রাখা হয়নি: DTLS handshake আর SRTP ছাড়া মিডিয়া চলে না।

Signalling অনির্ধারিত রাখার যুক্তি ভিন্ন। প্রতিটি অ্যাপের পরিচয়-ব্যবস্থা আলাদা: কেউ ফোন নম্বর ব্যবহার করে, কেউ ইমেইল, কেউ গ্রাহক-সেবার টিকিট নম্বর। SIP-এর মতো একটি নির্দিষ্ট protocol চাপিয়ে দিলে ব্রাউজারকে পুরো ফোন-ব্যবস্থা বয়ে বেড়াতে হতো, আর ওয়েব-ডেভেলপাররা নিজের প্রয়োজনে সহজে বদলাতে পারতেন না। তাই মান শুধু বলে কী আদানপ্রদান করতে হবে (SDP আর ICE candidate), কীভাবে — তা আপনার ইচ্ছা: WebSocket, HTTP, এমনকি QR কোড।

ফল দুই রকম। ইতিবাচক: হাজারো অ্যাপ নিজের মতো করে কল যোগ করতে পেরেছে। নেতিবাচক: নিরাপত্তার শিকল signalling সার্ভারের ওপর নির্ভর করে। SDP-র fingerprint দিয়েই DTLS certificate যাচাই হয়; signalling সার্ভার অসৎ বা আক্রান্ত হলে নিজের fingerprint বসিয়ে মাঝখানে বসে পড়তে পারে। এজন্য পুরোপুরি end-to-end গোপনীয়তা চাইলে অতিরিক্ত পরিচয়-যাচাই লাগে — যেমন কিছু অ্যাপ দুই পক্ষকে নিরাপত্তা-কোড মিলিয়ে দেখতে বলে।

মূল উপলব্ধি: যা সবার জন্য একই হওয়া দরকার (এনক্রিপশন, NAT পেরোনো) তা মান বাধ্য করে; যা অ্যাপভেদে আলাদা (পরিচয়, ডাকার পদ্ধতি) তা খোলা রাখে। তবে খোলা অংশের নিরাপত্তার দায় তখন অ্যাপ-নির্মাতার।

প্র ০৩বড় ভিডিও-মিটিং সেবাগুলো কেন mesh বা MCU নয়, মূলত SFU-ধাঁচের নকশায় গেছে? Simulcast আর end-to-end এনক্রিপশন এই সিদ্ধান্তে কীভাবে জড়িত?

Mesh-এর সমস্যা গাণিতিক: N জনের কলে প্রত্যেকের upload N − ১ গুণ, মোট stream N(N − ১). ছয় জনে প্রত্যেককে পাঁচটি ভিডিও আলাদা encode করে পাঠাতে হয় — ল্যাপটপের পাখা ঘুরতে থাকে, আর বাসার সংযোগে upload প্রায়ই download-এর চেয়ে অনেক কম। তাই ২–৩ জনের বাইরে mesh টেকে না।

MCU সমস্যাটা উল্টো দিকে ঠেলে দেয়: client-এর কাজ সহজ, কিন্তু সার্ভারকে প্রতিটি ভিডিও decode, মিশ্রণ আর আবার encode করতে হয় — ভিডিও-প্রক্রিয়াকরণ সবচেয়ে দামি কাজগুলোর একটি, আর decode-encode চক্র কয়েক দশ মিলিসেকেন্ড দেরিও যোগ করে। তার ওপর সবার পর্দায় একই বিন্যাস — কেউ চাইলে নিজের মতো সাজাতে পারেন না।

SFU মাঝামাঝি: সার্ভার শুধু packet ফরোয়ার্ড করে, decode করে না — একটি সাধারণ সার্ভার বহু stream সামলাতে পারে, দেরি কম। Upload-এর সমস্যা মেটে (প্রত্যেকে একটি stream), আর download-এর সমস্যা মেটাতে আসে simulcast বা SVC (scalable video coding): প্রেরক একই ভিডিও কয়েক স্তরে পাঠায়, SFU প্রত্যেক দর্শকের সংযোগ আর পর্দার আকার দেখে উপযুক্ত স্তর বাছে — ছোট থাম্বনেইলে নিচু মান, বক্তার জন্য উঁচু মান।

End-to-end এনক্রিপশনের সাথেও SFU মানানসই: যেহেতু সার্ভারকে ছবি খুলতে হয় না, মিডিয়ার ভেতরে আরেক স্তর এনক্রিপশন বসিয়ে সার্ভারকে অন্ধ রাখা যায় (SFrame-এর মতো পদ্ধতি)। MCU-তে এটা মৌলিকভাবে অসম্ভব, কারণ মেশাতে হলে দেখতেই হবে। তবে বড় অনুষ্ঠানে লক্ষ দর্শক হলে SFU-ও যথেষ্ট নয় — তখন মূল বক্তাদের SFU-তে রেখে বাকিদের HLS/DASH দিয়ে দেখানো হয়।

মূল উপলব্ধি: কাজ কোথায় হবে — client, সার্ভার না নেটওয়ার্ক — তা বদলালে খরচ, দেরি আর গোপনীয়তা একসাথে বদলায়। SFU এই তিনটির ভারসাম্যে সবচেয়ে ভালো জায়গায় বসে।

প্র ০৪Jitter buffer-এর playout delay বাড়ালে late loss কমে, কমালে দেরি কমে। এই টানাপোড়েন কীভাবে সামলানো হয়, আর FEC বা interleaving কেন এটিকে আরও জটিল করে?

Playout delay হলো একটি বাজি: আপনি ধরে নিচ্ছেন বেশিরভাগ packet এর মধ্যেই আসবে। Delay-এর বণ্টন যদি জানা থাকত, তাহলে এমন q বাছা যেত যাতে ধরুন ৯৯% packet সময়মতো আসে। কিন্তু নেটওয়ার্ক বদলায় — সন্ধ্যায় বাসার Wi-Fi-তে সবাই ভিডিও দেখলে queue বড় হয়, মোবাইলে টাওয়ার বদলালে হঠাৎ এক ঝলক দেরি। তাই adaptive playout চলমান গড় আর বিচ্যুতি মাপে, আর প্রতিটি talk spurt-এর শুরুতে নতুন delay বসায় — নীরবতা একটু লম্বা বা ছোট হলে কান টের পায় না, কিন্তু কথার মাঝখানে হঠাৎ ফাঁক টের পায়।

d + ৪v সূত্রটি TCP-র RTO-র (পর্ব ৩০) মতো: গড়ের সাথে বিচ্যুতির কয়েক গুণ যোগ করে নিরাপত্তার জায়গা রাখা। সূক্ষ্ম পার্থক্য হলো লক্ষ্য। TCP-তে timeout বেশি হলে শুধু পুনঃপ্রেরণ দেরিতে হয়; jitter buffer-এ delay বেশি হলে প্রতিটি কথা দেরিতে শোনা যায়, তাই G.114-এর বাজেটই উপরের সীমা টেনে দেয়।

FEC আর interleaving দুটোই এই বাজেট থেকে সময় নেয়। XOR-ভিত্তিক FEC-এ n টি packet-এর একটি হারালে বাড়তি packet আসা পর্যন্ত অপেক্ষা করতে হয় — playout delay অন্তত ততটা বাড়াতে হয়। Interleaving-এ পুরো দল আসার আগে প্রথম টুকরোও বাজানো যায় না। পিঠে-চড়ানো কম-মানের কপিতে অপেক্ষা মাত্র এক packet, তাই VoIP-এ সেটি জনপ্রিয়। আধুনিক ব্যবস্থা অবস্থা বুঝে বদলায়: RTCP বা অন্য feedback-এ loss বেশি দেখলে FEC চালু, কম দেখলে বন্ধ — কারণ FEC-এর বাড়তি bit নিজেই congestion বাড়াতে পারে।

মূল উপলব্ধি: Real-time মিডিয়ার প্রতিটি কৌশল একই মুদ্রায় দাম দেয় — সময়। ভালো নকশা মানে মোট বাজেট (প্রায় ১৫০ মিলিসেকেন্ড) codec, packet, নেটওয়ার্ক, buffer আর ক্ষতি-পুনরুদ্ধারের মধ্যে ভাগ করে দেওয়া।

প্র ০৫WebSocket আসার আগে ওয়েবে “push” কীভাবে হতো, আর হাজার হাজার WebSocket সংযোগ চালানো সার্ভারের নকশায় কী কী চ্যালেঞ্জ আসে?

২০০০-এর দশকের মাঝামাঝি ওয়েব-চ্যাট আর live আপডেটের জন্য নানা কৌশল ছিল, যাদের একসাথে “Comet” বলা হতো: long polling, লুকানো iframe-এ অসমাপ্ত HTTP উত্তর, Flash-এর socket. সবই HTTP-র মূল নকশার (অনুরোধ-উত্তর) বিরুদ্ধে টানাটানি — প্রতিটি বার্তায় কয়েকশো বাইটের header, আর proxy-র timeout-এ সংযোগ ভাঙা। HTML5-এর অংশ হিসেবে WebSocket-এর প্রস্তাব আসে, কয়েকটি খসড়া পেরিয়ে ২০১১ সালে RFC 6455. মাঝপথে নিরাপত্তা-গবেষণায় proxy cache poisoning-এর ঝুঁকি দেখা দেওয়ায় client-এর masking যোগ হয় — একটি protocol কীভাবে পুরোনো middlebox-এর অভ্যাসের কারণে বদলায়, তার উদাহরণ।

সার্ভারের দিকে চ্যালেঞ্জ ভিন্ন। প্রথমত, সংযোগ দীর্ঘস্থায়ী, তাই প্রতি সংযোগে একটি thread চালানো ব্যয়বহুল; event-driven নকশা (epoll, পর্ব ৪৪) দরকার, যাতে একটি প্রক্রিয়া হাজারো নিষ্ক্রিয় সংযোগ রাখতে পারে। দ্বিতীয়ত, load balancer-কে বুঝতে হয় সংযোগটি Upgrade হয়েছে আর দীর্ঘক্ষণ থাকবে; একাধিক সার্ভার থাকলে একজন ব্যবহারকারীর বার্তা অন্য সার্ভারে থাকা বন্ধুর কাছে পৌঁছাতে একটি বার্তা-বাহক (pub/sub) লাগে। তৃতীয়ত, NAT আর proxy নীরব সংযোগ মুছে দেয়, তাই ping/pong দিয়ে keepalive; মোবাইলে আবার ঘন ঘন ping ব্যাটারি খায় — টানাপোড়েন। চতুর্থত, সার্ভার আপডেটের সময় লক্ষ সংযোগ একসাথে ভাঙলে সবাই একই মুহূর্তে আবার যুক্ত হতে চায়; এলোমেলো অপেক্ষা (jitter-সহ backoff) না রাখলে সার্ভার ভেঙে পড়ে।

অনেক ক্ষেত্রে SSE-ই যথেষ্ট আর সহজ — শুধু সার্ভার থেকে খবর গেলে সাধারণ HTTP-র সব সুবিধা (HTTP/2 multiplexing, CDN, সহজ authentication) পাওয়া যায়। আজকের অনেক AI-চ্যাট সেবা উত্তর লাইন লাইন দেখাতে ঠিক এই SSE-ধাঁচের streaming ব্যবহার করে।

মূল উপলব্ধি: WebSocket প্রোটোকল হিসেবে সরল, কিন্তু দীর্ঘস্থায়ী সংযোগ সার্ভার, load balancer আর NAT — সবার অনুমান বদলে দেয়। প্রয়োজন সত্যিই দুই-দিকের কি না, আগে সেটা ভাবুন।

অনুশীলন

খাতা-কলম নিন — বাইট, মিলিসেকেন্ড আর Mbps ধরে ধরে হিসাব করুন।

  1. হিসাব (buffer মডেল): একটি ভিডিওর playback rate ৩ Mbps, নেটওয়ার্কের স্থির গতি ২.৪ Mbps, আর player ৯ Mb জমলে চালানো শুরু করে। (ক) শুরুর দেরি কত? (খ) কখন প্রথম stall হবে? (গ) ৫ মিনিটের ভিডিও একবারও না থামিয়ে চালাতে কত জমিয়ে শুরু করতে হতো, আর তাতে কত অপেক্ষা?

    (ক) tp = Q / x = ৯ ÷ ২.৪ = ৩.৭৫ সেকেন্ড. (খ) r − x = ০.৬ Mbps, তাই buffer খালি হয় চালানো শুরুর ৯ ÷ ০.৬ = ১৫ সেকেন্ড পরে, অর্থাৎ অনুরোধের ১৮.৭৫ সেকেন্ড পরে। যাচাই: ১৮.৭৫ × ২.৪ = ৪৫ Mb নামানো, ১৫ × ৩ = ৪৫ Mb চালানো। (গ) দরকার Q ≥ ৩০০ × ০.৬ = ১৮০ Mb, অপেক্ষা ১৮০ ÷ ২.৪ = ৭৫ সেকেন্ড — অগ্রহণযোগ্য। বাস্তব সমাধান: ২ Mbps-এর মতো নিচু একটি representation বেছে নেওয়া, যাতে x > r.

  2. হাতে trace (jitter buffer): প্রতি ২০ মিলিসেকেন্ডে একটি packet, তৈরি হয় t = ০, ২০, ৪০, ৬০, ৮০-তে; পথের delay যথাক্রমে ৪০, ৯০, ৭০, ১৩০, ৬০ মিলিসেকেন্ড। (ক) q = ৮০ আর q = ১২০-তে কোন কোন packet দেরিতে? সবাইকে বাঁচাতে সবচেয়ে ছোট q কত? (খ) u = ০.১, d₁ = ৪০, v₁ = ০ ধরে দ্বিতীয় packet-এর পর d আর v কত?

    (ক) পৌঁছানো: ৪০, ১১০, ১১০, ১৯০, ১৪০. q = ৮০-তে সময়সীমা ৮০, ১০০, ১২০, ১৪০, ১৬০ — packet ২ (১১০ > ১০০) আর ৪ (১৯০ > ১৪০) দেরিতে. q = ১২০-তে সীমা ১২০, ১৪০, ১৬০, ১৮০, ২০০ — শুধু packet ৪ (১৯০ > ১৮০)। সবাইকে বাঁচাতে q ≥ সর্বোচ্চ delay = ১৩০ মিলিসেকেন্ড. (খ) d₂ = ০.৯ × ৪০ + ০.১ × ৯০ = ৪৫; v₂ = ০.৯ × ০ + ০.১ × |৯০ − ৪৫| = ৪.৫; প্রস্তাবিত delay d + ৪v = ৬৩ মিলিসেকেন্ড।

  3. আউটপুট অনুমান (RTP): একটি G.711 stream, ২০ মিলিসেকেন্ডের packet. প্রথম packet-এর sequence number 1000 আর timestamp 48000. (ক) চতুর্থ packet-এর মান দুটি কী? (খ) চতুর্থের পর ঠিক ২০০ মিলিসেকেন্ড নীরবতা (packet যায়নি), তারপর কথা আবার শুরু। পরের packet-এর sequence number, timestamp আর marker bit কী হবে?

    (ক) প্রতি packet-এ sequence ১ আর timestamp ১৬০ (৮,০০০ × ০.০২) বাড়ে: চতুর্থটি seq 1003, timestamp 48480. (খ) Sequence number শুধু পাঠানো packet গোনে, তাই 1004. Timestamp ঘড়ির সাথে চলে: নীরবতায় ১০টি packet-এর সময় (২০০ ÷ ২০) পার হয়েছে, তাই পরের packet আসলে ১৫তম সময়-ঘর — 48000 + 160 × 14 = 50240. নতুন talk spurt বলে marker bit = 1. Sequence-এ ফাঁক না থাকায় প্রাপক বোঝে কিছু হারায়নি, আর timestamp-এর লাফ থেকে বোঝে কতক্ষণ নীরবতা ছিল।

  4. কোড লিখুন: অংশ ৬-এর bandwidth ক্যালকুলেটরে G.729 (৮ kbps) যোগ করুন, আর একটি বিকল্প রাখুন যাতে IPv4-এর বদলে IPv6 (৪০ বাইট header) ধরা যায়। ২০ মিলিসেকেন্ডের packet-এ দুই ক্ষেত্রে bitrate আর header-এর ভাগ কত?

    মূল পরিবর্তন শুধু header-এর যোগফল আর একটি নতুন সারি:

    for (const ipHdr of [20, 40]) {                 // IPv4, IPv6
      const HDR = 12 + 8 + ipHdr;
      const pay = 8 * 1000 / 8 * 20 / 1000;         // G.729: 8 kbps, 20 ms -> 20 bytes
      const kbps = (pay + HDR) * 8 * 50 / 1000;
      console.log(`IP header ${ipHdr}: ${pay + HDR} B/packet, ${kbps} kbps, overhead ${(100 * HDR / (pay + HDR)).toFixed(0)}%`);
    }
    // IP header 20: 60 B/packet, 24 kbps, overhead 67%
    // IP header 40: 80 B/packet, 32 kbps, overhead 75%

    G.729-এর কণ্ঠ মাত্র ২০ বাইট, অথচ header ৪০ (IPv4) বা ৬০ (IPv6) — তারে ৮ kbps-এর কণ্ঠ হয়ে যায় ২৪ বা ৩২ kbps. কম-bitrate codec-এ header compression বা বড় packet কেন জরুরি, এটাই তার প্রমাণ।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি SIP ভয়েস-কলের ঘটনাগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. কলকারী SDP offer-সহ INVITE পাঠান
  2. অন্যপক্ষের ফোন বাজে, 180 Ringing ফেরে
  3. অন্যপক্ষ ধরেন, SDP answer-সহ 200 OK ফেরে
  4. কলকারী ACK পাঠান
  5. দুই দিকে RTP-তে কণ্ঠ চলে
  6. একজন BYE পাঠান, অন্যজন 200 OK দেন

একটি VoIP কলে G.711 (৬৪ kbps) codec, প্রতি packet-এ ২০ মিলিসেকেন্ডের কণ্ঠ, আর RTP (১২ বাইট), UDP (৮) ও IPv4 (২০) header. IP-স্তরে এক দিকের bitrate কত?

  • ৬৪ kbps
  • ৭৪.৭ kbps
  • ৮০ kbps
  • ৯৬ kbps

ভয়েস packet প্রতি ২০ মিলিসেকেন্ডে তৈরি হয়। চারটি packet তৈরি হয়েছিল t = ৬০, ১০০, ১৬০ আর ১৮০ মিলিসেকেন্ডে, আর প্রাপকের কাছে পৌঁছাল যথাক্রমে ১৫৫, ২৪০, ২৬৫ আর ২৫২-তে। Fixed playout delay q = ১০০ মিলিসেকেন্ড হলে কোনগুলো দেরির কারণে বাদ পড়বে?

  • ৬০ আর ১৮০-তে তৈরি packet
  • ১০০ আর ১৬০-তে তৈরি packet
  • শুধু ১৬০-তে তৈরি packet
  • কোনোটিই নয়

WebSocket-এ client থেকে সার্ভারের প্রতিটি frame ৪ বাইটের এলোমেলো key দিয়ে mask করা বাধ্যতামূলক। এর মূল উদ্দেশ্য কী?

  • ডেটা গোপন রাখা, যাতে পথে কেউ পড়তে না পারে
  • পথে bit বদলে গেলে ধরা
  • ডেটা সংকুচিত করে bandwidth বাঁচানো
  • মাঝপথের পুরোনো proxy-র cache poisoning ঠেকানো

একটি ভিডিওর playback rate ২ Mbps, নেটওয়ার্ক স্থির ১.৫ Mbps হারে আনে, আর player ৬ Mb জমলে চালানো শুরু করে। অনুরোধের কত সেকেন্ড পরে প্রথম stall হবে?

  • ১৬ সেকেন্ড
  • ১২ সেকেন্ড
  • ৪ সেকেন্ড
  • কখনো হবে না

৫ জনের একটি ভিডিও মিটিং mesh নকশায় চলছে, প্রত্যেকে ২ Mbps-এর একটি ভিডিও পাঠান (প্রতিটি অন্যজনের জন্য আলাদা কপি)। প্রত্যেক অংশগ্রহণকারীর upload কত?

  • ২ Mbps
  • ১০ Mbps
  • ৮ Mbps
  • ৪০ Mbps

MPEG-DASH বা HLS-এ adaptive bitrate streaming সম্পর্কে কোন কথাটি ঠিক?

  • সার্ভার প্রতিটি দর্শকের গতি মেপে নিজেই bitrate বদলে পাঠায়
  • Client manifest পড়ে প্রতিটি segment-এর আগে উপযুক্ত মান বেছে সাধারণ HTTP দিয়ে আনে
  • মিডিয়া RTP/UDP-তে আসে, তাই কোনো buffer লাগে না
  • একবার মান বাছা হলে পুরো ভিডিও সেই মানেই চলে

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. তিন ধরনের মাল্টিমিডিয়া: জমা ভিডিও (কয়েক সেকেন্ড সয়), কথোপকথন (একদিকে ~১৫০ মিলিসেকেন্ড, G.114-এর নির্দেশিকা), live (কয়েক সেকেন্ড)। G.711 = ৮,০০০ × ৮ = ৬৪ kbps; Opus কম bitrate-এ ভালো; ভিডিওতে I/P/B frame.
  2. Buffer মডেল: শুরুর দেরি Q / x; x < r হলে stall tp + Q / (r − x)-এ। DASH/HLS: কয়েক মানের ২–১০ সেকেন্ডের segment, manifest (MPD/m3u8), client-এর ABR (throughput বা buffer-ভিত্তিক), CDN থেকে।
  3. WebSocket: HTTP Upgrade → 101; Accept = base64(SHA-1(key + GUID)); frame-এ FIN, opcode, MASK, ৭/১৬/৬৪ bit দৈর্ঘ্য; client-এর frame mask করা; ping/pong আর close code; বাস্তবে wss.
  4. VoIP: ২০ মিলিসেকেন্ডের G.711 = ১৬০ + ৪০ বাইট = ৮০ kbps; jitter buffer-এ t + q-তে বাজানো, পরে এলে বাদ; adaptive playout d + ৪v; FEC, interleaving, concealment. RTP: seq, timestamp, SSRC, PT, M; RTCP রিপোর্ট; SIP: INVITE/180/200/ACK/BYE, port 5060/5061.
  5. WebRTC: getUserMedia, RTCPeerConnection, data channel; signalling আপনার নিজের; SDP offer/answer, ICE/STUN/TURN, বাধ্যতামূলক DTLS-SRTP. দলের কলে mesh-এ upload N − ১ গুণ, তাই SFU; congestion control delay-ভিত্তিক।

পরের পর্বে: application স্তরের protocol অনেক দেখলেন — এবার নিজে বানানোর পালা। মডিউল ৭ শুরু হচ্ছে TCP socket প্রোগ্রামিং দিয়ে: C-তে একটি client আর server, socket(), bind(), listen(), accept() আর connect() ধাপে ধাপে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান