سیگنالینگ چیست؟
سیگنالینگ فرآیند هماهنگی ارتباطات است. برای اینکه یک برنامه WebRTC تماس برقرار کند، مشتریان آن باید اطلاعات زیر را مبادله کنند:
- پیامهای کنترل جلسه که برای باز کردن یا بستن ارتباطات استفاده میشوند
- پیام های خطا
- فراداده رسانه، مانند کدک ها، تنظیمات کدک، پهنای باند و انواع رسانه
- داده های کلیدی مورد استفاده برای ایجاد اتصالات ایمن
- دادههای شبکه، مانند آدرس IP و پورت میزبان که توسط دنیای خارج مشاهده میشود
این فرآیند سیگنالینگ به روشی نیاز دارد تا مشتریان بتوانند پیام ها را به عقب و جلو منتقل کنند. این مکانیسم توسط WebRTC API ها اجرا نمی شود. شما باید خودتان آن را بسازید. در ادامه این مقاله، راه های ساخت یک سرویس سیگنالینگ را یاد می گیرید. با این حال، ابتدا به یک زمینه کوچک نیاز دارید.
چرا سیگنالینگ توسط WebRTC تعریف نشده است؟
برای جلوگیری از افزونگی و به حداکثر رساندن سازگاری با فناوری های موجود، روش ها و پروتکل های سیگنالینگ توسط استانداردهای WebRTC مشخص نشده اند. این رویکرد توسط پروتکل استقرار جلسه جاوا اسکریپت (JSEP) مشخص شده است:
معماری JSEP همچنین از نیاز مرورگر به ذخیره حالت، یعنی عملکرد به عنوان یک ماشین حالت سیگنالینگ جلوگیری می کند. برای مثال، اگر هر بار که صفحه ای بارگذاری مجدد می شود، داده های سیگنالینگ از بین می رفت، مشکل ساز خواهد بود. در عوض، وضعیت سیگنالینگ را می توان در یک سرور ذخیره کرد.

JSEP نیاز به تبادل بین همتایان پیشنهاد و پاسخ ، فراداده رسانه ای ذکر شده در بالا دارد. پیشنهادات و پاسخها در قالب پروتکل شرح جلسه (SDP) ارسال میشوند که به شکل زیر است:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
آیا می خواهید بدانید که این همه SDP gobbledygook واقعاً به چه معناست؟ نگاهی به نمونه های کارگروه مهندسی اینترنت (IETF) بیندازید.
به خاطر داشته باشید که WebRTC طوری طراحی شده است که پیشنهاد یا پاسخ را می توان قبل از تنظیم به عنوان توضیحات محلی یا راه دور با ویرایش مقادیر در متن SDP تغییر داد. به عنوان مثال، تابع preferAudioCodec()
در appr.tc می تواند برای تنظیم کدک و میزان بیت پیش فرض استفاده شود. دستکاری SDP با جاوا اسکریپت تا حدودی دردناک است و در مورد اینکه آیا نسخه های آینده WebRTC باید به جای آن از JSON استفاده کنند یا خیر، بحث وجود دارد، اما استفاده از SDP مزایایی دارد.
RTCPeerConnection
API و سیگنالینگ: پیشنهاد، پاسخ و نامزد
RTCPeerConnection
API است که توسط برنامه های WebRTC برای ایجاد ارتباط بین همتایان و برقراری ارتباط صوتی و تصویری استفاده می شود.
برای مقداردهی اولیه این فرآیند، RTCPeerConnection
دو وظیفه دارد:
- شرایط رسانه محلی، مانند قابلیت وضوح و کدک را بررسی کنید. این ابرداده مورد استفاده برای مکانیسم پیشنهاد و پاسخ است.
- آدرسهای شبکه احتمالی را برای میزبان برنامه، که به عنوان نامزد شناخته میشود، دریافت کنید.
هنگامی که این داده محلی مشخص شد، باید از طریق یک مکانیسم سیگنالینگ با همتای راه دور مبادله شود.
تصور کنید آلیس سعی می کند حوا را صدا کند . در اینجا مکانیسم پیشنهاد/پاسخ کامل با تمام جزییات وحشتناک آن آمده است:
- آلیس یک شی
RTCPeerConnection
ایجاد می کند. - آلیس یک پیشنهاد (توضیح جلسه SDP) با متد
RTCPeerConnection
createOffer()
ایجاد می کند. - آلیس با پیشنهاد خود،
setLocalDescription()
را فراخوانی می کند. - آلیس پیشنهاد را محدود می کند و از مکانیزم سیگنالینگ برای ارسال آن به حوا استفاده می کند.
- ایو با پیشنهاد آلیس،
setRemoteDescription()
را فراخوانی می کند تاRTCPeerConnection
او از تنظیمات آلیس مطلع شود. - Eve
createAnswer()
فراخوانی میکند و پاسخ موفقیت آمیز برای این، یک توضیح جلسه محلی است - پاسخ حوا. - ایو با فراخوانی
setLocalDescription()
پاسخ خود را به عنوان توضیحات محلی تنظیم می کند. - ایو سپس از مکانیسم سیگنالینگ استفاده می کند تا پاسخ دقیق خود را برای آلیس ارسال کند.
- آلیس با استفاده از
setRemoteDescription()
پاسخ حوا را به عنوان توضیحات جلسه راه دور تنظیم می کند.
آلیس و حوا نیز نیاز به تبادل اطلاعات شبکه دارند. عبارت "پیدا کردن نامزدها" به فرآیند یافتن رابط ها و پورت های شبکه با استفاده از چارچوب ICE اشاره دارد.
- آلیس یک شی
RTCPeerConnection
با یک کنترل کنندهonicecandidate
ایجاد می کند. - هنگامی که نامزدهای شبکه در دسترس قرار می گیرند، کنترل کننده فراخوانی می شود.
- در کنترل کننده، آلیس داده های نامزد رشته ای را از طریق کانال سیگنالینگ آنها به حوا ارسال می کند.
- هنگامی که ایو یک پیام نامزد از آلیس دریافت می کند، او
addIceCandidate()
فرا می خواند تا نامزد را به توضیحات همتا از راه دور اضافه کند.
JSEP از ICE Candidate Trickling پشتیبانی میکند، که به تماسگیرنده اجازه میدهد تا پس از پیشنهاد اولیه، بهصورت تدریجی نامزدها را در اختیار مخاطب قرار دهد و تماسگیرنده شروع به انجام تماس و برقراری ارتباط بدون انتظار برای رسیدن همه نامزدها کند.
کد WebRTC برای سیگنالینگ
قطعه کد زیر یک نمونه کد W3C است که فرآیند سیگنال دهی کامل را خلاصه می کند. کد وجود مکانیزم سیگنالینگ را فرض می کند، SignalingChannel
. بعداً در مورد سیگنالینگ با جزئیات بیشتر بحث می شود.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
برای مشاهده فرآیندهای پیشنهاد/پاسخ و تبادل نامزد در عمل، به simpl.info RTCPeerConnection مراجعه کنید و برای نمونه چت ویدیویی تک صفحه ای، به گزارش کنسول نگاه کنید. اگر بیشتر میخواهید، یک نمونه کامل از سیگنالها و آمار WebRTC را از صفحه about://webrtc-internals در Google Chrome یا صفحه opera://webrtc-internals در Opera دانلود کنید.
کشف همتایان
این یک روش فانتزی برای پرسیدن است: "چگونه کسی را پیدا کنم که با او صحبت کنم؟"
برای تماس های تلفنی، شماره تلفن و دایرکتوری دارید. برای چت ویدیویی و پیامرسانی آنلاین، به سیستمهای مدیریت هویت و حضور، و ابزاری برای شروع جلسات برای کاربران نیاز دارید. برنامههای WebRTC به روشی نیاز دارند تا مشتریان به یکدیگر سیگنال دهند که میخواهند تماسی را شروع کنند یا به آن بپیوندند.
مکانیسمهای کشف همتا توسط WebRTC تعریف نشدهاند و در اینجا وارد گزینهها نمیشوید. این فرآیند می تواند به سادگی ارسال ایمیل یا ارسال یک URL باشد. برای برنامههای چت ویدیویی، مانند Talky ، tawk.to و Browser Meeting ، با اشتراکگذاری یک پیوند سفارشی، افراد را به تماس دعوت میکنید. توسعهدهنده کریس بال یک آزمایش بدون سرور-webrtc را ساخت که شرکتکنندگان در تماس WebRTC را قادر میسازد تا ابردادهها را با هر سرویس پیامرسانی که دوست دارند، مانند IM، ایمیل، یا کبوتر خانگی مبادله کنند.
چگونه می توانید یک سرویس سیگنالینگ بسازید؟
برای تکرار، پروتکل ها و مکانیسم های سیگنالینگ توسط استانداردهای WebRTC تعریف نشده اند. هر آنچه را که انتخاب می کنید، به یک سرور واسطه برای تبادل پیام های سیگنالینگ و داده های برنامه بین مشتریان نیاز دارید. متأسفانه، یک برنامه وب نمی تواند به سادگی در اینترنت فریاد بزند: "مرا به دوستم وصل کن!"
خوشبختانه پیامهای سیگنالینگ کوچک هستند و بیشتر در شروع تماس رد و بدل میشوند. در آزمایش با appr.tc برای یک جلسه چت ویدیویی، در مجموع حدود 30-45 پیام توسط سرویس سیگنالینگ با حجم کلی برای همه پیامها حدود 10 کیلوبایت مدیریت شد.
خدمات سیگنالینگ WebRTC علاوه بر اینکه از نظر پهنای باند نسبتاً بی نیاز هستند، پردازش یا حافظه زیادی مصرف نمی کنند، زیرا آنها فقط باید پیام ها را ارسال کنند و مقدار کمی از داده های حالت جلسه را حفظ کنند، مانند اینکه کدام کلاینت ها متصل هستند.
ارسال پیام از سرور به مشتری
یک سرویس پیام برای سیگنالینگ باید دو جهته باشد: مشتری به سرور و سرور به مشتری. ارتباط دوطرفه برخلاف مدل درخواست/پاسخ مشتری/سرور HTTP است، اما هکهای مختلفی مانند نظرسنجی طولانی طی سالها به منظور انتقال دادهها از سرویسی که روی سرور وب به یک برنامه وب در حال اجرا در مرورگر اجرا میشود، ایجاد شدهاند.
اخیراً، EventSource
API به طور گسترده پیاده سازی شده است. این رویداد رویدادهای ارسال شده توسط سرور را فعال می کند - داده هایی که از یک سرور وب به مشتری مرورگر از طریق HTTP ارسال می شوند. EventSource
برای پیام رسانی یک طرفه طراحی شده است، اما می توان از آن در ترکیب با XHR برای ایجاد سرویسی برای تبادل پیام های سیگنالینگ استفاده کرد. یک سرویس سیگنالینگ، پیامی را از تماس گیرنده ارسال می کند، که توسط درخواست XHR تحویل داده می شود، با فشار دادن آن از طریق EventSource
به تماس گیرنده.
WebSocket یک راه حل طبیعی تر است که برای ارتباط کلاینت و سرور دوطرفه طراحی شده است - پیام هایی که می توانند همزمان در هر دو جهت جریان داشته باشند. یکی از مزیتهای یک سرویس سیگنالینگ که با WebSocket خالص یا رویدادهای ارسال شده از سرور ( EventSource
) ساخته شده است، این است که پشتیبان این APIها را میتوان بر روی انواع چارچوبهای وب رایج در اکثر بستههای میزبانی وب برای زبانهایی مانند PHP، Python و Ruby پیادهسازی کرد.
همه مرورگرهای مدرن به جز Opera Mini از WebSocket پشتیبانی می کنند و مهمتر از آن، همه مرورگرهایی که از WebRTC پشتیبانی می کنند، از WebSocket هم در دسکتاپ و هم در موبایل پشتیبانی می کنند. TLS باید برای همه اتصالات استفاده شود تا اطمینان حاصل شود که پیام ها نمی توانند بدون رمز رهگیری شوند و همچنین برای کاهش مشکلات پیمایش پراکسی . (برای اطلاعات بیشتر در مورد WebSocket و پیمایش پراکسی به فصل WebRTC در شبکهسازی مرورگر با کارایی بالا ایلیا گریگوریک مراجعه کنید.)
همچنین میتوان با واداشتن مشتریان WebRTC به نظرسنجی مکرر از سرور پیامرسان از طریق Ajax، سیگنالها را مدیریت کرد، اما این امر منجر به درخواستهای اضافی شبکه میشود که به ویژه برای دستگاههای تلفن همراه مشکلساز است. حتی پس از ایجاد یک جلسه، همتایان باید برای ارسال پیام در صورت تغییر یا خاتمه جلسه توسط سایر همتایان نظرسنجی کنند. مثال برنامه WebRTC Book این گزینه را با برخی بهینهسازیها برای فرکانس نظرسنجی انجام میدهد.
سیگنالینگ مقیاس
اگرچه یک سرویس سیگنالینگ پهنای باند و CPU نسبتا کمی را به ازای هر کلاینت مصرف می کند، سرورهای سیگنالینگ برای یک برنامه محبوب ممکن است مجبور شوند پیام های زیادی را از مکان های مختلف با سطح همزمانی بالا مدیریت کنند. برنامه های WebRTC که ترافیک زیادی دریافت می کنند به سرورهای سیگنالینگ نیاز دارند که بتوانند بار قابل توجهی را مدیریت کنند. در اینجا وارد جزئیات نمیشوید، اما تعدادی گزینه برای پیامرسانی با حجم بالا و عملکرد بالا وجود دارد، از جمله موارد زیر:
پروتکل پیامرسانی و حضور eXtensible (XMPP)، که در ابتدا با نام Jabber شناخته میشد، یک پروتکل توسعهیافته برای پیامرسانی فوری که میتوان از آن برای سیگنالدهی استفاده کرد (پیادهسازیهای سرور شامل ejabberd و Openfire میشوند. مشتریان جاوا اسکریپت، مانند Strophe.js ، از BOSHS برای تقلید از BOSH به دلایل مختلف استفاده میکنند که ممکن است به دلایل مختلف دو طرفه باشد، اما به دلیل BOSH ممکن است کارآمد باشد. همین دلایل، ممکن است به خوبی مقیاس نشوند.) (در یک مماس، Jingle یک پسوند XMPP برای فعال کردن صدا و تصویر است. پروژه WebRTC از اجزای شبکه و انتقال از کتابخانه libjingle استفاده می کند - یک پیاده سازی C++ از Jingle.)
کتابخانههای منبع باز، مانند ZeroMQ (همانطور که TokBox برای سرویس Rumor خود استفاده میکند) و OpenMQ ( NullMQ مفاهیم ZeroMQ را با استفاده از پروتکل STOMP روی WebSocket به پلتفرمهای وب اعمال میکند.)
پلتفرمهای پیامرسان ابری تجاری که از WebSocket استفاده میکنند (اگرچه ممکن است به نظرسنجی طولانی بازگردند)، مانند Pusher ، Kaazing ، و PubNub (PubNub یک API برای WebRTC نیز دارد.)
پلتفرم های تجاری WebRTC مانند vLine
( راهنمای فناوریهای وب بلادرنگ توسعهدهنده فیل لگتر فهرستی جامع از خدمات و کتابخانههای پیامرسانی را ارائه میکند.)
یک سرویس سیگنالینگ با Socket.io در Node بسازید
کد زیر برای یک برنامه وب ساده است که از یک سرویس سیگنالینگ ساخته شده با Socket.io در Node استفاده می کند. طراحی Socket.io ساخت سرویسی برای تبادل پیام ها را ساده می کند و Socket.io به دلیل مفهوم داخلی اتاق ها برای سیگنالینگ WebRTC مناسب است. این مثال برای مقیاس بندی به عنوان یک سرویس سیگنالینگ درجه تولید طراحی نشده است، اما برای تعداد نسبتا کمی از کاربران قابل درک است.
Socket.io از WebSocket به همراه موارد جایگزین استفاده می کند: نظرسنجی طولانی AJAX، جریان چند قسمتی AJAX، Forever Iframe و نظرسنجی JSONP. به باطن های مختلف منتقل شده است، اما شاید بیشتر به خاطر نسخه Node استفاده شده در این مثال شناخته شده است.
هیچ WebRTC در این مثال وجود ندارد. این فقط برای نشان دادن نحوه ایجاد سیگنال در یک برنامه وب طراحی شده است. گزارش کنسول را مشاهده کنید تا ببینید هنگام پیوستن مشتریان به اتاق و تبادل پیام، چه اتفاقی میافتد. این کد WebRTC دستورالعمل های گام به گام را برای نحوه ادغام آن در یک برنامه کامل چت ویدیویی WebRTC ارائه می دهد.
در اینجا مشتری index.html
است:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
فایل جاوا اسکریپت main.js
که در کلاینت ارجاع داده شده است:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
در اینجا برنامه سرور کامل است:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(برای این کار نیازی به یادگیری node-static ندارید. اتفاقاً در این مثال استفاده می شود.)
برای اجرای این برنامه در لوکال هاست، باید Node، Socket.IO و Node-static را نصب کرده باشید. Node را می توان از Node.js دانلود کرد (نصب ساده و سریع است). برای نصب Socket.IO و Node-static، Node Package Manager را از ترمینال موجود در فهرست برنامه خود اجرا کنید:
npm install socket.io
npm install node-static
برای راه اندازی سرور، دستور زیر را از یک ترمینال در فهرست برنامه خود اجرا کنید:
node server.js
از مرورگر خود، localhost:2013
باز کنید. یک تب یا پنجره جدید در هر مرورگری باز کنید و localhost:2013
دوباره باز کنید. برای اینکه ببینید چه اتفاقی می افتد، کنسول را بررسی کنید. در کروم و اپرا، میتوانید از طریق ابزارهای توسعهدهنده Google Chrome با Ctrl+Shift+J
(یا Command+Option+J
در مک) به کنسول دسترسی داشته باشید.
هر رویکردی را که برای سیگنالینگ انتخاب کنید، برنامه باطن و مشتری شما - حداقل - نیاز به ارائه خدمات مشابه این مثال دارد.
سیگنالینگ گوچاها
- تا زمانی که
setLocalDescription()
فراخوانی نشود،RTCPeerConnection
جمع آوری نامزدها را شروع نمی کند. این در پیش نویس JSEP IETF الزامی شده است. - از Trickle ICE بهره ببرید. به محض ورود نامزدها
addIceCandidate()
تماس بگیرید.
سرورهای سیگنالینگ آماده
اگر نمیخواهید سرورهای خود را رول کنید، چندین سرور سیگنالینگ WebRTC در دسترس هستند که مانند مثال قبلی از Socket.IO استفاده میکنند و با کتابخانههای JavaScript کلاینت WebRTC یکپارچه شدهاند:
- webRTC.io یکی از اولین کتابخانه های انتزاعی برای WebRTC است.
- Signalmaster یک سرور سیگنالینگ است که برای استفاده با کتابخانه مشتری جاوا اسکریپت SimpleWebRTC ایجاد شده است.
اگر اصلاً نمیخواهید هیچ کدی بنویسید، پلتفرمهای تجاری WebRTC کامل از شرکتهایی مانند vLine ، OpenTok و Asterisk در دسترس هستند.
برای ثبت، اریکسون یک سرور سیگنالینگ با استفاده از PHP در آپاچی در روزهای اولیه WebRTC ساخت. این اکنون تا حدودی منسوخ شده است، اما اگر چیزی مشابه را در نظر دارید، ارزش دیدن کد را دارد.
امنیت سیگنالینگ
"امنیت هنر ایجاد چیزی است."
سلمان رشدی
رمزگذاری برای تمام اجزای WebRTC اجباری است.
با این حال، مکانیسمهای سیگنالینگ با استانداردهای WebRTC تعریف نشدهاند، بنابراین این شما هستید که باید سیگنالدهی را ایمن کنید. اگر مهاجم موفق به ربودن سیگنالها شود، میتواند جلسات را متوقف کند، اتصالات را تغییر مسیر دهد و محتوا را ضبط، تغییر دهد یا تزریق کند.
مهمترین عامل در ایمن سازی سیگنالینگ استفاده از پروتکل های امن - HTTPS و WSS (به عنوان مثال، TLS) - است که تضمین می کند که پیام ها نمی توانند بدون رمز رهگیری شوند. همچنین مراقب باشید پیام های سیگنالینگ را به گونه ای پخش نکنید که تماس گیرندگان دیگر با استفاده از همان سرور سیگنال به آنها دسترسی داشته باشند.
پس از سیگنال دهی: از ICE برای مقابله با NAT ها و فایروال ها استفاده کنید
برای سیگنالدهی ابرداده، برنامههای WebRTC از یک سرور واسطه استفاده میکنند، اما برای پخش رسانهها و دادههای واقعی پس از ایجاد یک جلسه، RTCPeerConnection
تلاش میکند تا مشتریان را مستقیماً یا همتا به همتا متصل کند.
در دنیای سادهتر، هر نقطه پایانی WebRTC یک آدرس منحصر به فرد دارد که میتواند برای برقراری ارتباط مستقیم با سایر همتایان مبادله کند.

در واقعیت، بیشتر دستگاهها در پشت یک یا چند لایه NAT زندگی میکنند، برخی دارای نرمافزار آنتیویروس هستند که پورتها و پروتکلهای خاصی را مسدود میکنند، و بسیاری از آنها پشت پراکسیها و فایروالهای شرکتی هستند. فایروال و NAT ممکن است در واقع توسط یک دستگاه مانند روتر WIFI خانگی پیاده سازی شوند.

برنامه های WebRTC می توانند از چارچوب ICE برای غلبه بر پیچیدگی های شبکه های دنیای واقعی استفاده کنند. برای فعال کردن این امر، برنامه شما باید URL های سرور ICE را به RTCPeerConnection
ارسال کند، همانطور که در این مقاله توضیح داده شده است.
ICE سعی می کند بهترین مسیر را برای اتصال همتایان پیدا کند. تمام احتمالات را به صورت موازی امتحان می کند و کارآمدترین گزینه را انتخاب می کند. ICE ابتدا سعی می کند با استفاده از آدرس میزبان به دست آمده از سیستم عامل و کارت شبکه دستگاه، اتصال برقرار کند. اگر این مشکل (که برای دستگاههای پشت NAT انجام میشود)، ICE با استفاده از یک سرور STUN یک آدرس خارجی دریافت میکند و در صورت عدم موفقیت، ترافیک از طریق سرور رله TURN هدایت میشود.
به عبارت دیگر، از سرور STUN برای دریافت آدرس شبکه خارجی و سرورهای TURN برای انتقال ترافیک در صورت عدم موفقیت در اتصال مستقیم (همتا به همتا) استفاده می شود.
هر سرور TURN از STUN پشتیبانی می کند. سرور TURN یک سرور STUN با قابلیت رله داخلی اضافی است. ICE همچنین با پیچیدگی های تنظیمات NAT کنار می آید. در واقعیت، سوراخ کردن NAT ممکن است به چیزی بیش از یک آدرس IP عمومی: پورت نیاز داشته باشد.
نشانیهای وب برای سرورهای STUN و/یا TURN (اختیاری) توسط یک برنامه WebRTC در شی پیکربندی iceServers
که اولین آرگومان سازنده RTCPeerConnection
است، مشخص میشود. برای appr.tc ، این مقدار به صورت زیر است:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
هنگامی که RTCPeerConnection
آن اطلاعات را داشته باشد، جادوی ICE به طور خودکار اتفاق می افتد. RTCPeerConnection
از چارچوب ICE برای تعیین بهترین مسیر بین همتایان استفاده می کند و در صورت لزوم با سرورهای STUN و TURN کار می کند.
STUN
NAT ها دستگاهی با یک آدرس IP برای استفاده در یک شبکه محلی خصوصی ارائه می دهند، اما این آدرس نمی تواند به صورت خارجی استفاده شود. بدون آدرس عمومی، هیچ راهی برای همتایان WebRTC برای ارتباط وجود ندارد. برای حل این مشکل، WebRTC از STUN استفاده می کند.
سرورهای STUN در اینترنت عمومی زندگی می کنند و یک کار ساده دارند - آدرس IP:پورت درخواست ورودی (از برنامه ای که پشت NAT اجرا می شود) را بررسی کنید و آن آدرس را به عنوان پاسخ ارسال کنید. به عبارت دیگر، برنامه از یک سرور STUN برای کشف IP:پورت خود از دیدگاه عمومی استفاده می کند. این فرآیند یک همتای WebRTC را قادر میسازد تا یک آدرس در دسترس عموم را برای خود دریافت کند و سپس آن را از طریق مکانیزم سیگنالینگ به همتای دیگر ارسال کند تا یک پیوند مستقیم را تنظیم کند. (در عمل، NAT های مختلف به روش های مختلف کار می کنند و ممکن است چندین لایه NAT وجود داشته باشد، اما اصل همچنان یکسان است.)
سرورهای STUN مجبور نیستند کارهای زیادی انجام دهند یا چیزهای زیادی را به خاطر بسپارند، بنابراین سرورهای STUN با مشخصات نسبتاً پایین می توانند تعداد زیادی از درخواست ها را انجام دهند.
طبق Webrtcstats.com ، اکثر تماسهای WebRTC با استفاده از STUN - 86% با موفقیت ارتباط برقرار میکنند، اگرچه این ممکن است برای تماسهای بین همتایان پشت فایروال و پیکربندیهای پیچیده NAT کمتر باشد.

بچرخانید
RTCPeerConnection
سعی می کند ارتباط مستقیم بین همتایان را از طریق UDP برقرار کند. اگر این کار انجام نشد، RTCPeerConnection
به TCP متوسل می شود. اگر این کار انجام نشد، سرورهای TURN را میتوان بهعنوان یک بک گراند استفاده کرد و دادهها را بین نقاط پایانی انتقال میدهد.
فقط برای تکرار، TURN برای انتقال صدا، ویدئو، و جریان داده بین همتایان استفاده می شود، نه سیگنال دادن به داده ها!
سرورهای TURN دارای آدرسهای عمومی هستند، بنابراین همتایان میتوانند با آنها تماس بگیرند، حتی اگر همتایان پشت فایروال یا پراکسی باشند. سرورهای TURN از نظر مفهومی یک کار ساده دارند - انتقال یک جریان. با این حال، بر خلاف سرورهای STUN، آنها ذاتاً پهنای باند زیادی مصرف می کنند. به عبارت دیگر، سرورهای TURN باید قوی تر باشند.

این نمودار چرخش را در عمل نشان می دهد. Pure STUN موفق نشد، بنابراین هر همتا به استفاده از سرور TURN متوسل می شود.
استقرار سرورهای STUN و TURN
برای آزمایش، Google یک سرور STUN عمومی، stun.l.google.com:19302 را اجرا می کند که توسط appr.tc استفاده می شود. برای سرویس STUN/TURN تولیدی، از سرور rfc5766-turn-server استفاده کنید. کد منبع برای سرورهای STUN و TURN در GitHub موجود است، جایی که میتوانید پیوندهایی به چندین منبع اطلاعاتی درباره نصب سرور پیدا کنید. یک تصویر VM برای خدمات وب آمازون نیز موجود است.
یک سرور جایگزین TURN restund است که به عنوان کد منبع و همچنین برای AWS موجود است. در اینجا دستورالعمل هایی برای نحوه تنظیم restund در Compute Engine آورده شده است.
- فایروال را در صورت لزوم برای tcp=443، udp/tcp=3478 باز کنید.
- چهار نمونه، یکی برای هر IP عمومی، تصویر استاندارد اوبونتو 12.06 ایجاد کنید.
- پیکربندی فایروال محلی را تنظیم کنید (به ANY از ANY اجازه دهید).
- ابزارهای نصب:
shell sudo apt-get install make sudo apt-get install gcc
- Libre را از creytiv.com/re.html نصب کنید.
- restund را از creytiv.com/restund.html واکشی کنید و بسته را باز کنید./
-
wget
hancke.name/restund-auth.patch و باpatch -p1 < restund-auth.patch
اعمال کنید. -
make
,sudo make install
برای libre و restund اجرا کنید. -
restund.conf
با نیازهای خود تطبیق دهید (آدرس های IP را جایگزین کنید و مطمئن شوید که حاوی همان راز مشترک است) و در/etc
کپی کنید. -
restund/etc/restund
در/etc/init.d/
کپی کنید. - پیکربندی restund:
-
LD_LIBRARY_PATH
را تنظیم کنید. -
restund.conf
در/etc/restund.conf
کپی کنید. -
restund.conf
برای استفاده از آدرس IP مناسب تنظیم کنید.
-
- restund را اجرا کنید
- تست با استفاده از Stand Client از دستگاه راه دور:
./client IP:port
فراتر از یک به یک: WebRTC چند حزبی
همچنین ممکن است بخواهید نگاهی به استاندارد IETF پیشنهادی جاستین اوبرتی برای REST API برای دسترسی به خدمات TURN بیندازید.
تصور موارد استفاده برای پخش رسانه ای که فراتر از یک تماس ساده یک به یک است، آسان است. برای مثال، کنفرانس ویدیویی بین گروهی از همکاران یا یک رویداد عمومی با یک سخنران و صدها یا میلیون ها بیننده.
یک برنامه WebRTC می تواند از چندین RTCPeerConnection استفاده کند تا هر نقطه پایانی در یک پیکربندی مش به هر نقطه پایانی دیگری متصل شود. این رویکردی است که توسط برنامه هایی مانند talky.io اتخاذ می شود و برای تعداد کمی از همتایان به خوبی کار می کند. فراتر از آن، پردازش و مصرف پهنای باند بیش از حد می شود، به ویژه برای مشتریان تلفن همراه.

از طرف دیگر، یک برنامه WebRTC میتواند یک نقطه پایانی را برای توزیع جریانها به بقیه در یک پیکربندی ستاره انتخاب کند. همچنین میتوان یک نقطه پایانی WebRTC را روی سرور اجرا کرد و مکانیزم توزیع مجدد خود را ساخت ( نمونه برنامه مشتری توسط webrtc.org ارائه شده است).
از Chrome 31 و Opera 18، MediaStream
از یک RTCPeerConnection
می تواند به عنوان ورودی برای دیگری استفاده شود. این میتواند معماریهای انعطافپذیرتری را فعال کند، زیرا یک برنامه وب را قادر میسازد تا با انتخاب همتای دیگری که باید به آن متصل شود، مسیریابی تماس را مدیریت کند. برای مشاهده عملی این، به نمونههای WebRTC رله اتصال همتا و نمونههای WebRTC اتصالات چندگانه همتا را ببینید.
واحد کنترل چند نقطه
یک گزینه بهتر برای تعداد زیادی از نقاط پایانی استفاده از واحد کنترل چند نقطه ای (MCU) است. این سروری است که به عنوان پلی برای توزیع رسانه بین تعداد زیادی از شرکت کنندگان عمل می کند. MCU ها می توانند با رزولوشن ها، کدک ها و نرخ فریم های مختلف در یک کنفرانس ویدئویی کنار بیایند. پردازش رمزگذاری ارسال انتخابی جریان را انجام دهید. و میکس یا ضبط صدا و تصویر. برای تماسهای چند طرفه، مسائلی وجود دارد که باید در نظر گرفته شوند، بهویژه نحوه نمایش ورودیهای ویدیوی متعدد و ترکیب صدا از چندین منبع. پلتفرمهای ابری مانند vLine نیز تلاش میکنند تا مسیریابی ترافیک را بهینه کنند.
این امکان وجود دارد که یک بسته سخت افزاری کامل MCU بخرید یا خودتان بسازید.

چندین گزینه نرم افزار منبع باز MCU در دسترس هستند. به عنوان مثال، Licode (که قبلا با نام Lynckia شناخته می شد) یک MCU منبع باز برای WebRTC تولید می کند. OpenTok دارای Mantis است.
فراتر از مرورگرها: VoIP، تلفن و پیام رسانی
ماهیت استاندارد WebRTC امکان برقراری ارتباط بین یک برنامه WebRTC در حال اجرا در یک مرورگر و یک دستگاه یا پلتفرم در حال اجرا بر روی یک پلت فرم ارتباطی دیگر، مانند تلفن یا یک سیستم ویدئو کنفرانس را ممکن می سازد.
SIP یک پروتکل سیگنالینگ است که توسط VoIP و سیستم های ویدئو کنفرانس استفاده می شود. برای فعال کردن ارتباط بین یک برنامه وب WebRTC و یک سرویس گیرنده SIP، مانند یک سیستم کنفرانس ویدیویی، WebRTC به یک سرور پروکسی برای واسطه سیگنالینگ نیاز دارد. سیگنالینگ باید از طریق دروازه جریان یابد، اما پس از برقراری ارتباط، ترافیک SRTP (تصویری و صوتی) می تواند مستقیماً نظیر به نظیر جریان یابد.
شبکه تلفن سوئیچ شده عمومی (PSTN) شبکه سوئیچ مدار تمام تلفن های آنالوگ قدیمی است. برای تماس بین برنامه های وب WebRTC و تلفن ها، ترافیک باید از طریق دروازه PSTN انجام شود. به همین ترتیب، برنامه های وب WebRTC به یک سرور XMPP واسطه برای ارتباط با نقاط پایانی Jingle مانند کلاینت های IM نیاز دارند. Jingle توسط گوگل به عنوان یک افزونه برای XMPP برای فعال کردن صدا و ویدئو برای خدمات پیامرسانی توسعه داده شد. پیادهسازیهای کنونی WebRTC بر اساس کتابخانه C++ libjingle ، یک پیادهسازی از Jingle است که در ابتدا برای Talk توسعه داده شد.
تعدادی از برنامه ها، کتابخانه ها و پلتفرم ها از توانایی WebRTC برای برقراری ارتباط با دنیای خارج استفاده می کنند:
- sipML5 : یک سرویس گیرنده SIP جاوا اسکریپت منبع باز
- jsSIP : کتابخانه SIP جاوا اسکریپت
- Phono : API تلفن منبع باز جاوا اسکریپت که به عنوان یک افزونه ساخته شده است
- Zingaya : یک ویجت تلفن قابل جاسازی
- Twilio : صدا و پیام
- Uberconference : کنفرانس
توسعه دهندگان sipML5 دروازه webrtc2sip را نیز ساخته اند. Tethr و Tropo چارچوبی را برای ارتباطات فاجعه آمیز "در یک کیف" با استفاده از سلول OpenBTS برای فعال کردن ارتباطات بین تلفن های ویژه و رایانه ها از طریق WebRTC نشان داده اند. یعنی ارتباط تلفنی بدون اپراتور!
بیشتر بدانید
کد لبه WebRTC دستورالعمل های گام به گام را برای نحوه ساخت یک برنامه چت ویدیویی و متنی با استفاده از یک سرویس سیگنالینگ Socket.io که در Node اجرا می شود ارائه می دهد.
ارائه Google I/O WebRTC از سال 2013 با مدیر فناوری WebRTC، جاستین اوبرتی
ارائه SFHTML5 کریس ویلسون - مقدمه ای بر برنامه های WebRTC
کتاب 350 صفحه ای WebRTC: APIs و RTCWEB Protocols of the HTML5 Real-Time Web جزئیات زیادی در مورد داده ها و مسیرهای سیگنالینگ ارائه می دهد و شامل تعدادی نمودار توپولوژی شبکه دقیق است.
WebRTC و سیگنالینگ: آنچه دو سال به ما آموخت - پست وبلاگ TokBox در مورد اینکه چرا سیگنالینگ را خارج از مشخصات فنی گذاشتیم ایده خوبی بود
راهنمای عملی ساخت برنامه های WebRTC از بن استرانگ اطلاعات زیادی در مورد توپولوژی ها و زیرساخت های WebRTC ارائه می دهد.
فصل WebRTC در شبکهسازی مرورگر با کارایی بالا ایلیا گریگوریک به عمق معماری WebRTC، موارد استفاده و عملکرد میپردازد.
،سیگنالینگ چیست؟
سیگنالینگ فرآیند هماهنگی ارتباطات است. برای اینکه یک برنامه WebRTC تماس برقرار کند، مشتریان آن باید اطلاعات زیر را مبادله کنند:
- پیامهای کنترل جلسه که برای باز کردن یا بستن ارتباطات استفاده میشوند
- پیام های خطا
- فراداده رسانه، مانند کدک ها، تنظیمات کدک، پهنای باند و انواع رسانه
- داده های کلیدی مورد استفاده برای ایجاد اتصالات ایمن
- دادههای شبکه، مانند آدرس IP و پورت میزبان که توسط دنیای خارج مشاهده میشود
این فرآیند سیگنالینگ به روشی نیاز دارد تا مشتریان بتوانند پیام ها را به عقب و جلو منتقل کنند. این مکانیسم توسط WebRTC API ها اجرا نمی شود. شما باید خودتان آن را بسازید. در ادامه این مقاله، راه های ساخت یک سرویس سیگنالینگ را یاد می گیرید. با این حال، ابتدا به یک زمینه کوچک نیاز دارید.
چرا سیگنالینگ توسط WebRTC تعریف نشده است؟
برای جلوگیری از افزونگی و به حداکثر رساندن سازگاری با فناوری های موجود، روش ها و پروتکل های سیگنالینگ توسط استانداردهای WebRTC مشخص نشده اند. این رویکرد توسط پروتکل استقرار جلسه جاوا اسکریپت (JSEP) مشخص شده است:
معماری JSEP همچنین از نیاز مرورگر به ذخیره حالت، یعنی عملکرد به عنوان یک ماشین حالت سیگنالینگ جلوگیری می کند. برای مثال، اگر هر بار که صفحه ای بارگذاری مجدد می شود، داده های سیگنالینگ از بین می رفت، مشکل ساز خواهد بود. در عوض، وضعیت سیگنالینگ را می توان در یک سرور ذخیره کرد.

JSEP نیاز به تبادل بین همتایان پیشنهاد و پاسخ ، فراداده رسانه ای ذکر شده در بالا دارد. پیشنهادات و پاسخها در قالب پروتکل شرح جلسه (SDP) ارسال میشوند که به شکل زیر است:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
آیا می خواهید بدانید که این همه SDP gobbledygook واقعاً به چه معناست؟ نگاهی به نمونه های کارگروه مهندسی اینترنت (IETF) بیندازید.
به خاطر داشته باشید که WebRTC طوری طراحی شده است که پیشنهاد یا پاسخ را می توان قبل از تنظیم به عنوان توضیحات محلی یا راه دور با ویرایش مقادیر در متن SDP تغییر داد. به عنوان مثال، تابع preferAudioCodec()
در appr.tc می تواند برای تنظیم کدک و میزان بیت پیش فرض استفاده شود. دستکاری SDP با جاوا اسکریپت تا حدودی دردناک است و در مورد اینکه آیا نسخه های آینده WebRTC باید به جای آن از JSON استفاده کنند یا خیر، بحث وجود دارد، اما استفاده از SDP مزایایی دارد.
RTCPeerConnection
API و سیگنالینگ: پیشنهاد، پاسخ و نامزد
RTCPeerConnection
API است که توسط برنامه های WebRTC برای ایجاد ارتباط بین همتایان و برقراری ارتباط صوتی و تصویری استفاده می شود.
برای مقداردهی اولیه این فرآیند، RTCPeerConnection
دو وظیفه دارد:
- شرایط رسانه محلی، مانند قابلیت وضوح و کدک را بررسی کنید. این ابرداده مورد استفاده برای مکانیسم پیشنهاد و پاسخ است.
- آدرسهای شبکه احتمالی را برای میزبان برنامه، که به عنوان نامزد شناخته میشود، دریافت کنید.
هنگامی که این داده محلی مشخص شد، باید از طریق یک مکانیسم سیگنالینگ با همتای راه دور مبادله شود.
تصور کنید آلیس سعی می کند حوا را صدا کند . در اینجا مکانیسم پیشنهاد/پاسخ کامل با تمام جزییات وحشتناک آن آمده است:
- آلیس یک شی
RTCPeerConnection
ایجاد می کند. - آلیس یک پیشنهاد (توضیح جلسه SDP) با متد
RTCPeerConnection
createOffer()
ایجاد می کند. - آلیس با پیشنهاد خود،
setLocalDescription()
را فراخوانی می کند. - آلیس پیشنهاد را محدود می کند و از مکانیزم سیگنالینگ برای ارسال آن به حوا استفاده می کند.
- حوا با پیشنهاد آلیس ،
setRemoteDescription()
فراخوانی می کند ، به طوری کهRTCPeerConnection
او از تنظیم آلیس اطلاع دارد. - حوا با
createAnswer()
تماس می گیرد و پاسخ به تماس با موفقیت در این مورد توضیحات جلسه محلی - پاسخ حوا. - حوا با فراخوانی
setLocalDescription()
پاسخ خود را به عنوان توضیحات محلی تعیین می کند. - EVE سپس از مکانیسم سیگنالینگ برای ارسال پاسخ رشته ای خود به آلیس استفاده می کند.
- آلیس پاسخ حوا را به عنوان توضیحات جلسه از راه دور با استفاده از
setRemoteDescription()
تنظیم می کند.
آلیس و حوا نیز نیاز به تبادل اطلاعات شبکه دارند. عبارت "یافتن نامزدها" به فرآیند یافتن رابط های شبکه و بنادر با استفاده از چارچوب یخ اشاره دارد.
- آلیس یک شیء
RTCPeerConnection
را با یک کنترل کنندهonicecandidate
ایجاد می کند. - هنگامی که نامزدهای شبکه در دسترس قرار می گیرند ، کنترل کننده فراخوانی می شود.
- در کنترل کننده ، آلیس داده های کاندیدای رشته ای را از طریق کانال سیگنالینگ خود به حوا ارسال می کند.
- هنگامی که حوا از آلیس پیام کاندیدایی دریافت می کند ، او
addIceCandidate()
تماس می گیرد تا نامزد را به توضیحات همکار از راه دور اضافه کند.
JSEP از نامزد ICE پشتیبانی می کند ، که به تماس گیرنده اجازه می دهد تا پس از پیشنهاد اولیه ، نامزدها را به طور تدریجی کاندیداها را به Callee ارائه دهد ، و برای اینکه کاللی شروع به کار در تماس کند و بدون انتظار برای رسیدن همه نامزدها ، ارتباطی برقرار کند.
کد webrtc برای سیگنالینگ
قطعه کد زیر نمونه کد W3C است که فرایند کامل سیگنالینگ را خلاصه می کند. کد فرض وجود برخی مکانیسم سیگنالینگ ، SignalingChannel
است. سیگنالینگ بعداً با جزئیات بیشتری مورد بحث قرار می گیرد.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
برای دیدن پیشنهادات/پاسخ و فرآیندهای تبادل نامزد در عمل ، به Simple.info rtcpeerConnection مراجعه کنید و به یک گزارش کنسول برای یک مثال چت ویدیویی تک صفحه ای مراجعه کنید. اگر می خواهید بیشتر ، یک صفحه کامل از سیگنالینگ و آمار Webrtc را از صفحه درباره: // صفحه Webrtc-Internals در Google Chrome یا Opera: // Webrtc-Internals در Opera بارگیری کنید.
کشف همسایه
این یک روش جالب برای پرسیدن است ، "چگونه می توانم کسی را پیدا کنم که با او صحبت کند؟"
برای تماس تلفنی ، شماره تلفن و دایرکتوری دارید. برای چت و پیام های آنلاین ، به سیستم های مدیریت هویت و حضور نیاز دارید و وسیله ای برای شروع جلسات کاربران است. برنامه های WEBRTC به روشی نیاز دارند تا مشتری ها به یکدیگر سیگنال دهند که می خواهند شروع کنند یا به یک تماس بپیوندند.
مکانیسم های کشف همسالان توسط WEBRTC تعریف نشده اند و شما در اینجا به گزینه های خود نمی روید. این روند می تواند به سادگی از طریق ایمیل یا پیام رسانی به URL باشد. برای برنامه های چت ویدیویی ، مانند جلسه Talky ، Tawk.to و مرورگر ، شما با به اشتراک گذاشتن یک لینک سفارشی ، مردم را به تماس دعوت می کنید. توسعه دهنده Chris Ball یک آزمایش جذاب بدون WEBRTC سرور ایجاد کرد که شرکت کنندگان در تماس با WEBRTC را قادر می سازد تا ابرداده را با هر سرویس پیام رسانی که دوست دارند ، از جمله IM ، ایمیل یا کبوتر خانگی مبادله کنند.
چگونه می توانید یک سرویس سیگنالینگ بسازید؟
برای تکرار مجدد ، پروتکل ها و مکانیسم های سیگنالینگ مطابق با استانداردهای WEBRTC تعریف نمی شوند. هرچه را انتخاب کنید ، برای تبادل پیام های سیگنالینگ و داده های برنامه بین مشتری به یک سرور واسطه نیاز دارید. متأسفانه ، یک برنامه وب به سادگی نمی تواند به اینترنت فریاد بزند ، "من را به دوست من وصل کنید!"
خوشبختانه پیام های سیگنالینگ در ابتدای تماس کوچک هستند و بیشتر رد و بدل می شوند. در آزمایش با Appr.TC برای یک جلسه چت ویدیویی ، در مجموع حدود 30-45 پیام توسط سرویس سیگنالینگ با اندازه کل برای همه پیام های حدود 10 کیلوبایت انجام شد.
و همچنین از نظر پهنای باند نسبتاً نامشخص است ، خدمات سیگنالینگ WEBRTC پردازش یا حافظه زیادی را مصرف نمی کنند ، زیرا آنها فقط نیاز به انتقال پیام دارند و مقدار کمی از داده های حالت جلسه را حفظ می کنند ، مانند اینکه مشتری ها به هم وصل می شوند.
پیام ها را از سرور به مشتری فشار دهید
یک سرویس پیام برای سیگنالینگ باید دو طرفه باشد: مشتری به سرور و سرور به مشتری. ارتباطات دو طرفه در برابر مدل درخواست/پاسخ مشتری HTTP/سرور HTTP انجام می شود ، اما هک های مختلفی مانند نظرسنجی طولانی در طی سالهای متمادی ایجاد شده است تا داده ها را از یک سرویس در حال اجرا بر روی سرور وب به یک برنامه وب که در یک مرورگر اجرا می شود ، فشار دهید.
اخیراً ، API EventSource
به طور گسترده ای اجرا شده است. این امر رویدادهای سرور را قادر می سازد - داده های ارسال شده از یک سرور وب به یک مشتری مرورگر از طریق HTTP. EventSource
برای پیام رسانی یک طرفه طراحی شده است ، اما می توان از آن در ترکیب با XHR برای ساخت سرویس برای تبادل پیام های سیگنالینگ استفاده کرد. یک سرویس سیگنالینگ با فشار دادن آن از طریق EventSource
به Callee ، پیامی را از یک تماس گیرنده ، که توسط درخواست XHR تحویل داده می شود ، منتقل می کند.
WebSocket یک راه حل طبیعی تر است که برای ارتباط کامل مشتری و مشتری - پیام هایی که می توانند به طور همزمان از هر دو جهت جریان پیدا کنند ، طراحی شده است. یکی از مزایای سرویس سیگنالینگ ساخته شده با برنامه های خالص WebSocket یا Server-Sent ( EventSource
) این است که می توان با پس زمینه این API ها را در انواع چارچوب های وب مشترک برای اکثر بسته های میزبان وب برای زبانهایی مانند PHP ، Python و Ruby اجرا کرد.
همه مرورگرهای مدرن به جز Opera Mini از WebSocket پشتیبانی می کنند و مهمتر از همه ، همه مرورگرهایی که از WebRTC پشتیبانی می کنند ، از WebSocket نیز پشتیبانی می کنند ، چه در دسک تاپ و هم در موبایل. TLS باید برای همه اتصالات مورد استفاده قرار گیرد تا اطمینان حاصل شود که پیام ها نمی توانند بدون رمزگذاری رهگیری شوند و همچنین برای کاهش مشکلات مربوط به پروکسی عبور . (برای کسب اطلاعات بیشتر در مورد WebSocket و Proxy Traversal ، فصل WEBRTC را در شبکه مرورگر با کارایی بالا ایلیا گریگوریک مشاهده کنید.)
همچنین می توان با دریافت مشتری های WebRTC به طور مکرر از طریق AJAX ، به سیگنالینگ رسیدگی کرد ، اما این امر منجر به درخواست های شبکه اضافی می شود ، که مخصوصاً برای دستگاه های تلفن همراه مشکل ساز است. حتی پس از ایجاد یک جلسه ، همسالان در صورت بروز تغییرات یا خاتمه جلسه توسط سایر همسالان باید برای پیام های سیگنالینگ نظرسنجی کنند. مثال برنامه کتاب WEBRTC این گزینه را با برخی بهینه سازی ها برای فرکانس نظرسنجی در نظر می گیرد.
سیگنالینگ مقیاس
اگرچه یک سرویس سیگنالینگ از پهنای باند و پردازنده نسبتاً کمی برای هر مشتری استفاده می کند ، اما سرورهای سیگنالینگ برای یک برنامه محبوب ممکن است مجبور شوند پیام های زیادی را از مکانهای مختلف با سطح بالای همزمانی کنترل کنند. برنامه های WEBRTC که ترافیک زیادی دارند ، به سرورهای سیگنالینگ نیاز دارند که بتوانند بار قابل توجهی را تحمل کنند. شما در اینجا به جزئیات نمی پردازید ، اما تعدادی گزینه برای پیام رسانی با حجم بالا و با کارایی بالا وجود دارد ، از جمله موارد زیر:
پروتکل پیام رسانی و حضور گسترده (XMPP) ، که در ابتدا به عنوان پروتکل JABBER-A شناخته می شود برای پیام رسانی فوری که می تواند برای سیگنالینگ استفاده شود (اجرای سرور شامل Ejabberd و OpenFire است. مشتری های Javascript ، مانند strophe.js ، استفاده از Bosh برای تقلید از جریان دو طرفه ، اما به دلایل مختلف ، ممکن است Bosh به همان اندازه کارآمد باشد. همین دلایل ، ممکن است به خوبی مقیاس نباشد.) (در یک مماس ، جینگل یک پسوند XMPP برای فعال کردن صدا و فیلم است. پروژه WebRTC از اجزای شبکه و حمل و نقل از کتابخانه Libjingle استفاده می کند - اجرای C ++ از Jingle.)
کتابخانه های منبع باز ، مانند ZEROMQ (همانطور که توسط Tokbox برای سرویس شایعه آنها استفاده می شود) و OpenMQ ( NullMQ مفاهیم ZerOMQ را با استفاده از پروتکل Stomp از طریق WebSocket ، در سیستم عامل های وب اعمال می کند.)
سیستم عامل های پیام رسان ابری که از WebSocket استفاده می کنند (اگرچه ممکن است به نظرسنجی طولانی برگردند) ، مانند Pusher ، Kaazing و PubNub (PubNub همچنین دارای API برای Webrtc است.)
سیستم عامل های تجاری WEBRTC ، مانند Vline
( راهنمای فن آوری های وب در زمان واقعی Phil Leggetter ، لیست کاملی از خدمات پیام رسانی و کتابخانه ها را ارائه می دهد.)
یک سرویس سیگنالینگ با Socket.io روی گره بسازید
در زیر کد برای یک برنامه وب ساده است که از یک سرویس سیگنالینگ ساخته شده با Socket.io در گره استفاده می کند. طراحی Socket.io ساختن یک سرویس برای تبادل پیام و سوکت را ساده می کند. به دلیل مفهوم داخلی اتاق ها ، به ویژه برای سیگنالینگ Webrtc مناسب است. این مثال برای مقیاس به عنوان یک سرویس سیگنالینگ درجه تولید طراحی نشده است ، اما درک آن برای تعداد نسبتاً کمی از کاربران ساده است.
Socket.io از WebSocket با Fallbacks استفاده می کند: نظرسنجی طولانی AJAX ، جریان چندتایی AJAX ، Forever Iframe و نظرسنجی JSONP. آن را به پشتیبان های مختلف منتقل کرده است ، اما شاید به خاطر نسخه گره ای که در این مثال استفاده شده است شناخته شده باشد.
در این مثال هیچ Webrtc وجود ندارد. این فقط برای نشان دادن نحوه ساخت سیگنالینگ در یک برنامه وب طراحی شده است. ورود به سیستم کنسول را مشاهده کنید تا ببینید وقتی مشتری به یک اتاق می پیوندد و پیام های تبادل می کند چه اتفاقی می افتد. این CodeLab Webrtc دستورالعمل های گام به گام برای نحوه ادغام این برنامه در یک برنامه چت ویدیویی WebRTC کامل ارائه می دهد.
در اینجا index.html
مشتری است:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
در اینجا پرونده JavaScript main.js
در مشتری ارجاع شده است:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
در اینجا برنامه کامل سرور وجود دارد:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(برای این کار نیازی به یادگیری Node-Static ندارید. فقط اتفاق می افتد که در این مثال استفاده می شود.)
برای اجرای این برنامه در LocalHost ، باید Node ، Socket.io و Node-Static نصب کنید. گره را می توان از node.js بارگیری کرد (نصب ساده و سریع است). برای نصب Socket.io و Node-Static ، مدیر بسته گره را از یک ترمینال در فهرست برنامه خود اجرا کنید:
npm install socket.io
npm install node-static
برای شروع سرور ، دستور زیر را از یک ترمینال در فهرست برنامه خود اجرا کنید:
node server.js
از مرورگر خود ، localhost:2013
. یک برگه یا پنجره جدید را در هر مرورگر باز کنید و localhost:2013
دوباره. برای دیدن آنچه اتفاق می افتد ، کنسول را بررسی کنید. در Chrome و Opera می توانید از طریق Ctrl+Shift+J
(یا Command+Option+J
در Mac) به کنسول دسترسی پیدا کنید.
هر رویکردی که برای سیگنالینگ انتخاب می کنید ، حداقل پس زمینه و برنامه مشتری خود - حداقل - نیاز به ارائه خدمات مشابه با این مثال دارید.
سیگنالینگ Gotchas
-
RTCPeerConnection
تا زمان فراخوانیsetLocalDescription()
، شروع به جمع آوری نامزدها نمی کند. این در پیش نویس JSEP IETF اجباری است. - از یخ ترفند استفاده کنید. به محض ورود نامزدها
addIceCandidate()
تماس بگیرید.
سرورهای سیگنالینگ آماده
اگر نمی خواهید خود را بچرخانید ، چندین سرور سیگنالینگ WEBRTC در دسترس است که از Socket.io مانند مثال قبلی استفاده می کنند و با کتابخانه های JavaScript Client WebRTC یکپارچه شده اند:
- Webrtc.io یکی از اولین کتابخانه های انتزاع برای Webrtc است.
- Signalmaster یک سرور سیگنالینگ است که برای استفاده با کتابخانه مشتری SimpleWebrtc JavaScript ایجاد شده است.
اگر نمی خواهید به هیچ وجه کد بنویسید ، سیستم عامل های کامل تجاری Webrtc از شرکت هایی مانند Vline ، Opentok و Asterisk در دسترس هستند.
برای ضبط ، اریکسون در اوایل WeBRTC یک سرور سیگنالینگ با استفاده از PHP در Apache ساخت. این اکنون تا حدودی منسوخ است ، اما اگر در نظر دارید چیزی مشابه را در نظر بگیرید ، ارزش دیدن کد را دارد.
امنیت سیگنالینگ
"امنیت هنر ایجاد هیچ اتفاقی است."
سلمان رشدی
رمزگذاری برای همه مؤلفه های Webrtc الزامی است.
با این حال ، مکانیسم های سیگنالینگ مطابق با استانداردهای WEBRTC تعریف نمی شوند ، بنابراین ایمن سازی سیگنالینگ به عهده شماست. اگر یک مهاجم موفق به ربودن سیگنالینگ شود ، می تواند جلسات را متوقف کند ، اتصالات را هدایت کند و محتوا را ضبط کند ، تغییر دهد یا تزریق کند.
مهمترین عامل در تأمین سیگنالینگ استفاده از پروتکل های ایمن - HTTPS و WSS (به عنوان مثال TL) است - که اطمینان حاصل می کنند که پیام ها نمی توانند بدون رمزگذاری رهگیری شوند. همچنین ، مراقب باشید که پیام های سیگنالینگ را به گونه ای پخش نکنید که با استفاده از همان سرور سیگنالینگ توسط سایر تماس گیرندگان قابل دسترسی باشد.
بعد از سیگنالینگ: از یخ برای مقابله با NAT ها و فایروال ها استفاده کنید
برای سیگنالینگ ابرداده ، برنامه های WEBRTC از سرور واسطه ای استفاده می کنند ، اما برای ایجاد یک جلسه واقعی رسانه ها و داده ها پس از ایجاد جلسه ، RTCPeerConnection
تلاش می کند تا مشتری ها را مستقیماً یا همتا به همسالان متصل کند.
در دنیای ساده تر ، هر نقطه پایانی WEBRTC دارای یک آدرس منحصر به فرد است که می تواند با سایر همسالان مبادله کند تا بتواند مستقیماً ارتباط برقرار کند.

در واقعیت ، بیشتر دستگاه ها در پشت یک یا چند لایه NAT زندگی می کنند ، برخی از آنها دارای نرم افزار آنتی ویروس هستند که پورت ها و پروتکل های خاصی را مسدود می کنند و بسیاری از آنها در پشت پراکسی و فایروال های شرکت هستند. یک فایروال و نات در واقع ممکن است توسط همان دستگاه مانند روتر WiFi خانگی اجرا شوند.

برنامه های WEBRTC می توانند از چارچوب یخ برای غلبه بر پیچیدگی های شبکه های واقعی استفاده کنند. برای اینکه این اتفاق بیفتد ، برنامه شما باید URL های سرور ICE را به RTCPeerConnection
منتقل کند ، همانطور که در این مقاله توضیح داده شده است.
ICE سعی می کند بهترین مسیر را برای اتصال همسالان پیدا کند. این همه امکانات را به صورت موازی امتحان می کند و کارآمدترین گزینه ای را که کار می کند انتخاب می کند. ICE ابتدا سعی می کند با استفاده از آدرس میزبان به دست آمده از سیستم عامل دستگاه و کارت شبکه ، اتصال برقرار کند. در صورت عدم موفقیت (که برای دستگاه های پشت NATS) ، ICE با استفاده از سرور Stun یک آدرس خارجی را بدست می آورد و در صورت عدم موفقیت ، ترافیک از طریق سرور رله چرخشی مسیریابی می شود.
به عبارت دیگر ، از سرور Stun برای به دست آوردن آدرس شبکه خارجی استفاده می شود و در صورت عدم موفقیت اتصال مستقیم (همتا به همتا) از سرورهای چرخشی برای انتقال ترافیک استفاده می شود.
هر سرور چرخش از خیره کننده پشتیبانی می کند. سرور Turn یک سرور خیره کننده با قابلیت رله داخلی اضافی است. ICE همچنین با پیچیدگی های تنظیمات NAT مقابله می کند. در واقعیت ، پانچ شدن سوراخ Nat ممکن است فقط به یک IP عمومی نیاز داشته باشد: آدرس پورت.
URL برای سرورهای Stun و/یا Turn (به صورت اختیاری) توسط یک برنامه WEBRTC در شیء پیکربندی iceServers
مشخص شده است که اولین آرگومان برای سازنده RTCPeerConnection
است. برای Appr.tc ، این مقدار به این شکل است:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
هنگامی که RTCPeerConnection
این اطلاعات را داشته باشد ، Magic Magic به طور خودکار اتفاق می افتد. RTCPeerConnection
از چارچوب یخ برای استفاده بهترین مسیر بین همسالان استفاده می کند ، در صورت لزوم با سرورهای خیره کننده و تبدیل می شود.
STUN
NATS دستگاهی را با آدرس IP برای استفاده در یک شبکه محلی خصوصی فراهم می کند ، اما از این آدرس نمی توان از خارج استفاده کرد. بدون آدرس عمومی ، هیچ راهی برای برقراری ارتباط همسالان Webrtc وجود ندارد. برای حل این مشکل ، Webrtc از Stun استفاده می کند.
سرورهای Stun در اینترنت عمومی زندگی می کنند و یک کار ساده دارند - IP را بررسی کنید: آدرس پورت درخواست دریافتی (از برنامه ای که در پشت NAT اجرا می شود) و آن آدرس را به عنوان پاسخ ارسال کنید. به عبارت دیگر ، برنامه از سرور Stun برای کشف IP خود استفاده می کند: پورت از منظر عمومی. این فرآیند یک همکار WebRTC را قادر می سازد تا یک آدرس در دسترس عموم برای خود دریافت کند و سپس آن را از طریق مکانیسم سیگنالینگ به یک همکار دیگر منتقل کند تا بتواند یک پیوند مستقیم ایجاد کند. (در عمل ، NAT های مختلف به روش های مختلف کار می کنند و ممکن است چندین لایه NAT وجود داشته باشد ، اما اصل هنوز یکسان است.)
سرورهای Stun مجبور نیستند کارهای زیادی انجام دهند یا خیلی به یاد داشته باشند ، بنابراین سرورهای نسبتاً کم رنگ می توانند تعداد زیادی درخواست را کنترل کنند.
بیشتر تماس های WEBRTC با موفقیت با استفاده از Stun - 86 ٪ طبق Webrtcstats.com ارتباط برقرار می کنند ، اگرچه این می تواند کمتر برای تماس های بین همسالان پشت فایروال ها و تنظیمات پیچیده NAT باشد.

بچرخانید
RTCPeerConnection
سعی می کند ارتباط مستقیمی بین همسالان از طریق UDP برقرار کند. در صورت عدم موفقیت ، RTCPeerConnection
به TCP استراحت می دهد. در صورت عدم موفقیت ، سرورهای چرخش می توانند به عنوان یک بازپرداخت استفاده شوند و داده های بین نقاط پایانی را منتقل می کنند.
فقط برای تکرار ، از چرخش برای رله صوتی ، فیلم و پخش داده ها بین همسالان استفاده می شود ، نه داده های سیگنالینگ!
سرورهای چرخش آدرس های عمومی دارند ، بنابراین حتی اگر همسالان در پشت فایروال یا پروکسی باشند ، می توانند با همسالان تماس بگیرند. سرورهای چرخش یک کار ساده از نظر مفهومی دارند - برای انتقال یک جریان. با این حال ، بر خلاف سرورهای خیره کننده ، آنها ذاتاً پهنای باند زیادی را مصرف می کنند. به عبارت دیگر ، سرورهای چرخش نیاز به گوشتخوار دارند.

این نمودار به نوبه خود عمل نشان می دهد. Stun Pure موفق نشد ، بنابراین هر یک از همسالان به استفاده از سرور چرخش متوسل می شوند.
استقرار سرورهای خیره کننده و چرخش
برای آزمایش ، Google یک سرور Stun عمومی ، stun.l.google.com:19302 را اجرا می کند ، همانطور که توسط Appr.tc استفاده می شود. برای یک سرویس STUN/TURN تولید ، از سرور RFC5766-Turn استفاده کنید. کد منبع برای سرورهای Stun and Turn در GitHub موجود است ، جایی که می توانید پیوندهایی به چندین منبع اطلاعات در مورد نصب سرور پیدا کنید. یک تصویر VM برای خدمات وب آمازون نیز موجود است.
یک سرور چرخش جایگزین ، Restund است ، به عنوان کد منبع و همچنین برای AWS موجود است. در اینجا دستورالعمل هایی برای نحوه تنظیم Restund در Compute Engine آورده شده است.
- فایروال را در صورت لزوم برای TCP = 443 ، UDP/TCP = 3478 باز کنید.
- چهار مورد ایجاد کنید ، یکی برای هر IP عمومی ، تصویر استاندارد Ubuntu 12.06.
- پیکربندی فایروال محلی را تنظیم کنید (از هر کاری اجازه دهید).
- نصب ابزارها:
shell sudo apt-get install make sudo apt-get install gcc
- Libre را از creytiv.com/re.html نصب کنید.
- Fetch Restund از creytiv.com/restund.html و Unpack./
-
wget
Hanck.name/restund-auth.patch و باpatch -p1 < restund-auth.patch
اعمال کنید. - Run
make
،sudo make install
. -
restund.conf
با نیازهای خود سازگار کنید (آدرس های IP را جایگزین کنید و مطمئن شوید که حاوی همان راز مشترک است) و روی/etc
کپی کنید. - کپی
restund/etc/restund
به/etc/init.d/
. - تنظیم مجدد:
-
LD_LIBRARY_PATH
را تنظیم کنید. -
restund.conf
به/etc/restund.conf
کپی کنید. -
restund.conf
تنظیم کنید تا از آدرس IP 10 سمت راست استفاده کنید.
-
- بازگرداندن
- تست با استفاده از مشتری stund از دستگاه از راه دور:
./client IP:port
فراتر از یک به یک: Webrtc چند منظوره
همچنین ممکن است بخواهید برای دسترسی به خدمات به نوبه خود ، به استاندارد IETF پیشنهادی Justin Uberti برای یک API REST نگاهی بیندازید.
تصور موارد استفاده برای پخش رسانه ای که فراتر از یک تماس ساده یک به یک است ، آسان است. به عنوان مثال ، کنفرانس ویدیویی بین گروهی از همکاران یا یک رویداد عمومی با یک سخنران و صدها یا میلیون ها بیننده.
یک برنامه WEBRTC می تواند از چندین RTCPeerConnections استفاده کند تا هر نقطه پایانی در پیکربندی مش به هر نقطه پایانی دیگر متصل شود. این رویکردی است که توسط برنامه ها مانند Talky.io انجام شده است و برای تعداد انگشت شماری از همسالان بسیار خوب کار می کند. فراتر از آن ، پردازش و مصرف پهنای باند بیش از حد می شود ، به خصوص برای مشتری های تلفن همراه.

از طرف دیگر ، یک برنامه WEBRTC می تواند یک نقطه پایانی را برای توزیع جریان به همه دیگران در پیکربندی ستاره انتخاب کند. همچنین می توان یک نقطه پایانی WEBRTC را بر روی یک سرور اجرا کرد و مکانیسم توزیع مجدد خود را ایجاد کرد (یک برنامه مشتری نمونه توسط webrtc.org ارائه شده است).
از آنجا که Chrome 31 و Opera 18 ، از یک MediaStream
از یک RTCPeerConnection
می توان به عنوان ورودی دیگری استفاده کرد. این می تواند معماری های انعطاف پذیر تری را فعال کند زیرا یک برنامه وب را قادر می سازد تا با انتخاب کدام یک از همسالان دیگر به آن بپردازد. برای دیدن این کار در عمل ، به نمونه های Webrtc Relay Connection Connection و نمونه های WeBRTC چندین اتصالات همسالان مراجعه کنید.
واحد کنترل چند منظوره
گزینه بهتری برای تعداد زیادی از نقاط پایانی استفاده از یک واحد کنترل چند منظوره (MCU) است. این سرور است که به عنوان پلی برای توزیع رسانه بین تعداد زیادی از شرکت کنندگان کار می کند. MCU می تواند در یک کنفرانس ویدیویی با وضوح مختلف ، کدک ها و نرخ فریم مقابله کند. کنترل کدگذاری ؛ حمل و نقل جریان انتخابی را انجام دهید. و صدا و فیلم را مخلوط یا ضبط کنید. برای تماس های چند حزبی ، تعدادی از موارد در نظر گرفته شده است ، به ویژه نحوه نمایش چندین ورودی ویدیویی و مخلوط کردن صدا از چندین منبع. سیستم عامل های ابری ، مانند Vline ، همچنین سعی در بهینه سازی مسیریابی ترافیک دارند.
خرید یک بسته سخت افزاری کامل MCU یا ساخت خود ممکن است.

چندین گزینه نرم افزار MCU منبع باز در دسترس است. به عنوان مثال ، Licode (که قبلاً با عنوان Lynckia شناخته می شد) یک منبع باز MCU برای WeBRTC تولید می کند. Opentok دارای مانتیس است.
فراتر از مرورگرها: VoIP ، تلفن و پیام رسانی
ماهیت استاندارد WEBRTC امکان ایجاد ارتباط بین یک برنامه WEBRTC را که در یک مرورگر و یک دستگاه یا سکوی در حال اجرا بر روی یک بستر ارتباطی دیگر ، مانند تلفن یا سیستم کنفرانس ویدیویی است ، امکان پذیر می کند.
SIP یک پروتکل سیگنالینگ است که توسط سیستم های VoIP و کنفرانس ویدیویی استفاده می شود. برای فعال کردن ارتباط بین یک برنامه وب Webrtc و یک مشتری SIP ، مانند سیستم کنفرانس ویدیویی ، WeBRTC برای واسطه سیگنالینگ به یک سرور پروکسی نیاز دارد. سیگنالینگ باید از طریق دروازه جریان یابد ، اما پس از برقراری ارتباط ، ترافیک SRTP (فیلم و صوتی) می تواند مستقیماً به همسالان منتقل شود.
شبکه تلفن روشن شده عمومی (PSTN) شبکه مداربست مدار از تمام تلفن های آنالوگ "قدیمی قدیمی" است. برای تماس بین برنامه های وب WEBRTC و تلفن ، ترافیک باید از طریق یک دروازه PSTN عبور کند. به همین ترتیب ، برنامه های وب Webrtc برای برقراری ارتباط با نقاط پایانی Jingle مانند IM Clients به یک سرور XMPP واسطه نیاز دارند. Jingle توسط Google به عنوان پسوند به XMPP ساخته شد تا صدا و فیلم را برای خدمات پیام رسانی فعال کند. اجرای فعلی WEBRTC بر اساس کتابخانه C ++ Libjingle است که اجرای Jingle در ابتدا برای گفتگو ساخته شده است.
تعدادی از برنامه ها ، کتابخانه ها و سیستم عامل ها از توانایی WeBRTC در برقراری ارتباط با دنیای خارج استفاده می کنند:
- SIPML5 : مشتری SIP SIP منبع باز JavaScript
- JSSIP : کتابخانه SIP JavaScript
- Phono : API تلفن JavaScript منبع باز ساخته شده به عنوان افزونه
- Zingaya : یک ویجت تلفن قابل تعبیه
- Twilio : صدا و پیام رسانی
- UberConference : کنفرانس
توسعه دهندگان SIPML5 همچنین دروازه Webrtc2Sip را ساخته اند. Tethr و Tropo چارچوبی را برای ارتباطات فاجعه "در یک کیف" با استفاده از یک سلول OpenBTS نشان داده اند تا ارتباطات بین تلفن های ویژگی و رایانه ها را از طریق WEBRTC فعال کنند. این ارتباط تلفنی بدون حامل است!
بیشتر بدانید
WEBRTC CodeLab دستورالعمل های گام به گام برای نحوه ساخت یک برنامه گپ ویدیویی و متنی با استفاده از یک سرویس سیگنالینگ Socket.io که روی گره اجرا می شود ، ارائه می دهد.
Google I/O Webrtc ارائه از سال 2013 با رهبری Tech Webrtc ، جاستین اوبرتی
ارائه SFHTML5 کریس ویلسون - مقدمه ای برای برنامه های Webrtc
کتاب 350 صفحه ای WEBRTC: API و پروتکل های RTCWEB از وب واقعی HTML5 جزئیات زیادی در مورد داده ها و مسیرهای سیگنالینگ ارائه می دهد و شامل تعدادی از نمودارهای توپولوژی دقیق شبکه است.
Webrtc و سیگنالینگ: چه دو سال به ما آموخته است - پست وبلاگ Tokbox در مورد اینکه چرا خروج از سیگنالینگ از مشخصات ایده خوبی بود
BEN Strong یک راهنمای عملی برای ساخت برنامه های Webrtc اطلاعات زیادی در مورد توپولوژی و زیرساخت های WEBRTC ارائه می دهد.
فصل WEBRTC در شبکه مرورگر با کارایی بالا ایلیا گریگوریک به معماری Webrtc ، موارد استفاده و عملکرد عمیق می رود.
،سیگنالینگ چیست؟
سیگنالینگ فرایند هماهنگی ارتباطات است. برای اینکه یک برنامه WEBRTC یک تماس برقرار کند ، مشتریان آن باید اطلاعات زیر را مبادله کنند:
- پیام های کنترل جلسه برای باز یا بسته شدن ارتباطات استفاده می شود
- پیام های خطا
- ابرداده رسانه ای ، مانند کدک ها ، تنظیمات کدک ، پهنای باند و انواع رسانه ها
- داده های کلیدی مورد استفاده برای ایجاد اتصالات امن
- داده های شبکه ، مانند آدرس IP و درگاه میزبان همانطور که توسط دنیای خارج مشاهده می شود
این فرایند سیگنالینگ به روشی نیاز دارد تا مشتری ها پیام های خود را به جلو و عقب منتقل کنند. این مکانیسم توسط API های WEBRTC اجرا نمی شود. شما باید خودتان آن را بسازید. بعداً در این مقاله ، راه هایی برای ایجاد یک سرویس سیگنالینگ یاد می گیرید. با این حال ، اول ، شما به یک زمینه کوچک نیاز دارید.
چرا سیگنالینگ توسط Webrtc تعریف نشده است؟
برای جلوگیری از افزونگی و به حداکثر رساندن سازگاری با فن آوری های تعیین شده ، روش های سیگنالینگ و پروتکل ها طبق استانداردهای WEBRTC مشخص نشده است. این رویکرد توسط پروتکل تأسیس جلسه JavaScript (JSEP) بیان شده است:
معماری JSEP همچنین از مرورگر جلوگیری می کند تا حالت را نجات دهد ، یعنی به عنوان یک دستگاه حالت سیگنالینگ عمل کند. این مسئله مشکل ساز خواهد بود اگر به عنوان مثال ، داده های سیگنالینگ هر بار که یک صفحه بارگیری می شود از بین می رود. در عوض ، حالت سیگنالینگ را می توان در یک سرور ذخیره کرد.

JSEP نیاز به مبادله بین همسالان پیشنهاد و پاسخ ، ابرداده رسانه ای که در بالا ذکر شد. پیشنهادات و پاسخ ها در فرمت پروتکل توضیحات جلسه (SDP) ، که شبیه این است ، ابلاغ می شوند:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
آیا می خواهید بدانید که این همه SDP GobbledyGook به چه معنی است؟ به نمونه های کارگروه مهندسی اینترنت (IETF) نگاهی بیندازید.
در نظر داشته باشید که WeBRTC به گونه ای طراحی شده است که می توان پیشنهاد یا پاسخ را قبل از تنظیم به عنوان توضیحات محلی یا از راه دور با ویرایش مقادیر در متن SDP تنظیم کرد. به عنوان مثال ، عملکرد preferAudioCodec()
در Appr.tc می تواند برای تنظیم کدک و بیت پیش فرض استفاده شود. SDP برای دستکاری با JavaScript تا حدودی دردناک است و بحث در مورد اینکه آیا نسخه های آینده Webrtc باید به جای آن از JSON استفاده کند ، وجود دارد ، اما برخی از مزایا برای چسبیدن به SDP وجود دارد.
API RTCPeerConnection
و سیگنالینگ: پیشنهاد ، پاسخ و نامزد
RTCPeerConnection
API است که توسط برنامه های WEBRTC برای ایجاد ارتباط بین همسالان و ارتباط صوتی و تصویری استفاده می شود.
برای اولیه سازی این فرآیند ، RTCPeerConnection
دو کار دارد:
- شرایط رسانه محلی مانند وضوح و قابلیت کدک را مشخص کنید. این ابرداده ای است که برای مکانیسم پیشنهاد و پاسخ استفاده می شود.
- آدرس های بالقوه شبکه را برای میزبان برنامه ، معروف به نامزدها دریافت کنید.
پس از مشخص شدن این داده های محلی ، باید از طریق مکانیسم سیگنالینگ با همسالان از راه دور رد و بدل شود.
تصور کنید آلیس در تلاش است تا حوا را صدا کند . در اینجا مکانیسم ارائه/پاسخ کامل در تمام جزئیات جالب آن آورده شده است:
- آلیس یک شیء
RTCPeerConnection
ایجاد می کند. - آلیس با روش
RTCPeerConnection
createOffer()
یک پیشنهاد (توضیحات جلسه SDP) ایجاد می کند. - آلیس با پیشنهاد خود
setLocalDescription()
را صدا می کند. - آلیس پیشنهاد را رشته می کند و از یک مکانیسم سیگنالینگ برای ارسال آن به حوا استفاده می کند.
- حوا با پیشنهاد آلیس ،
setRemoteDescription()
فراخوانی می کند ، به طوری کهRTCPeerConnection
او از تنظیم آلیس اطلاع دارد. - حوا با
createAnswer()
تماس می گیرد و پاسخ به تماس با موفقیت در این مورد توضیحات جلسه محلی - پاسخ حوا. - حوا با فراخوانی
setLocalDescription()
پاسخ خود را به عنوان توضیحات محلی تعیین می کند. - EVE سپس از مکانیسم سیگنالینگ برای ارسال پاسخ رشته ای خود به آلیس استفاده می کند.
- آلیس پاسخ حوا را به عنوان توضیحات جلسه از راه دور با استفاده از
setRemoteDescription()
تنظیم می کند.
آلیس و حوا نیز نیاز به تبادل اطلاعات شبکه دارند. عبارت "یافتن نامزدها" به فرآیند یافتن رابط های شبکه و بنادر با استفاده از چارچوب یخ اشاره دارد.
- آلیس یک شیء
RTCPeerConnection
را با یک کنترل کنندهonicecandidate
ایجاد می کند. - هنگامی که نامزدهای شبکه در دسترس قرار می گیرند ، کنترل کننده فراخوانی می شود.
- در کنترل کننده ، آلیس داده های کاندیدای رشته ای را از طریق کانال سیگنالینگ خود به حوا ارسال می کند.
- هنگامی که حوا از آلیس پیام کاندیدایی دریافت می کند ، او
addIceCandidate()
تماس می گیرد تا نامزد را به توضیحات همکار از راه دور اضافه کند.
JSEP از نامزد ICE پشتیبانی می کند ، که به تماس گیرنده اجازه می دهد تا پس از پیشنهاد اولیه ، نامزدها را به طور تدریجی کاندیداها را به Callee ارائه دهد ، و برای اینکه کاللی شروع به کار در تماس کند و بدون انتظار برای رسیدن همه نامزدها ، ارتباطی برقرار کند.
کد webrtc برای سیگنالینگ
قطعه کد زیر نمونه کد W3C است که فرایند کامل سیگنالینگ را خلاصه می کند. کد فرض وجود برخی مکانیسم سیگنالینگ ، SignalingChannel
است. سیگنالینگ بعداً با جزئیات بیشتری مورد بحث قرار می گیرد.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
برای دیدن پیشنهادات/پاسخ و فرآیندهای تبادل نامزد در عمل ، به Simple.info rtcpeerConnection مراجعه کنید و به یک گزارش کنسول برای یک مثال چت ویدیویی تک صفحه ای مراجعه کنید. اگر می خواهید بیشتر ، یک صفحه کامل از سیگنالینگ و آمار Webrtc را از صفحه درباره: // صفحه Webrtc-Internals در Google Chrome یا Opera: // Webrtc-Internals در Opera بارگیری کنید.
کشف همسایه
این یک روش جالب برای پرسیدن است ، "چگونه می توانم کسی را پیدا کنم که با او صحبت کند؟"
برای تماس تلفنی ، شماره تلفن و دایرکتوری دارید. برای چت و پیام های آنلاین ، به سیستم های مدیریت هویت و حضور نیاز دارید و وسیله ای برای شروع جلسات کاربران است. برنامه های WEBRTC به روشی نیاز دارند تا مشتری ها به یکدیگر سیگنال دهند که می خواهند شروع کنند یا به یک تماس بپیوندند.
مکانیسم های کشف همسالان توسط WEBRTC تعریف نشده اند و شما در اینجا به گزینه های خود نمی روید. این روند می تواند به سادگی از طریق ایمیل یا پیام رسانی به URL باشد. برای برنامه های چت ویدیویی ، مانند جلسه Talky ، Tawk.to و مرورگر ، شما با به اشتراک گذاشتن یک لینک سفارشی ، مردم را به تماس دعوت می کنید. توسعه دهنده Chris Ball یک آزمایش جذاب بدون WEBRTC سرور ایجاد کرد که شرکت کنندگان در تماس با WEBRTC را قادر می سازد تا ابرداده را با هر سرویس پیام رسانی که دوست دارند ، از جمله IM ، ایمیل یا کبوتر خانگی مبادله کنند.
چگونه می توانید یک سرویس سیگنالینگ بسازید؟
برای تکرار مجدد ، پروتکل ها و مکانیسم های سیگنالینگ مطابق با استانداردهای WEBRTC تعریف نمی شوند. هرچه را انتخاب کنید ، برای تبادل پیام های سیگنالینگ و داده های برنامه بین مشتری به یک سرور واسطه نیاز دارید. متأسفانه ، یک برنامه وب به سادگی نمی تواند به اینترنت فریاد بزند ، "من را به دوست من وصل کنید!"
خوشبختانه پیام های سیگنالینگ در ابتدای تماس کوچک هستند و بیشتر رد و بدل می شوند. در آزمایش با Appr.TC برای یک جلسه چت ویدیویی ، در مجموع حدود 30-45 پیام توسط سرویس سیگنالینگ با اندازه کل برای همه پیام های حدود 10 کیلوبایت انجام شد.
و همچنین از نظر پهنای باند نسبتاً نامشخص است ، خدمات سیگنالینگ WEBRTC پردازش یا حافظه زیادی را مصرف نمی کنند ، زیرا آنها فقط نیاز به انتقال پیام دارند و مقدار کمی از داده های حالت جلسه را حفظ می کنند ، مانند اینکه مشتری ها به هم وصل می شوند.
پیام ها را از سرور به مشتری فشار دهید
یک سرویس پیام برای سیگنالینگ باید دو طرفه باشد: مشتری به سرور و سرور به مشتری. ارتباطات دو طرفه در برابر مدل درخواست/پاسخ مشتری HTTP/سرور HTTP انجام می شود ، اما هک های مختلفی مانند نظرسنجی طولانی در طی سالهای متمادی ایجاد شده است تا داده ها را از یک سرویس در حال اجرا بر روی سرور وب به یک برنامه وب که در یک مرورگر اجرا می شود ، فشار دهید.
اخیراً ، API EventSource
به طور گسترده ای اجرا شده است. این امر رویدادهای سرور را قادر می سازد - داده های ارسال شده از یک سرور وب به یک مشتری مرورگر از طریق HTTP. EventSource
is designed for one-way messaging, but it can be used in combination with XHR to build a service for exchanging signaling messages. A signaling service passes a message from a caller, delivered by XHR request, by pushing it through EventSource
to the callee.
WebSocket is a more-natural solution, designed for full duplex client–server communication - messages that can flow in both directions at the same time. One advantage of a signaling service built with pure WebSocket or server-sent events ( EventSource
) is that the backend for these APIs can be implemented on a variety of web frameworks common to most web-hosting packages for languages such as PHP, Python, and Ruby.
All modern browsers except Opera Mini support WebSocket and, more importantly, all browsers that support WebRTC also support WebSocket, both on desktop and mobile. TLS should be used for all connections to ensure messages cannot be intercepted unencrypted and also to reduce problems with proxy traversal . (For more information about WebSocket and proxy traversal see the WebRTC chapter in Ilya Grigorik's High Performance Browser Networking .)
It is also possible to handle signaling by getting WebRTC clients to poll a messaging server repeatedly through Ajax, but that leads to a lot of redundant network requests, which is especially problematic for mobile devices. Even after a session has been established, peers need to poll for signaling messages in case of changes or session termination by other peers. The WebRTC Book app example takes this option with some optimizations for polling frequency.
Scale signaling
Although a signaling service consumes relatively little bandwidth and CPU per client, signaling servers for a popular app may have to handle a lot of messages from different locations with high levels of concurrency. WebRTC apps that get a lot of traffic need signaling servers able to handle considerable load. You don't go into detail here, but there are a number of options for high-volume, high-performance messaging, including the following:
eXtensible Messaging and Presence Protocol (XMPP), originally known as Jabber-a protocol developed for instant messaging that can be used for signaling (Server implementations include ejabberd and Openfire . JavaScript clients, such as Strophe.js , use BOSH to emulate bidirectional streaming, but for various reasons , BOSH may not be as efficient as WebSocket and, for the same reasons, may not scale well.) (On a tangent, Jingle is an XMPP extension to enable voice and video. The WebRTC project uses network and transport components from the libjingle library - a C++ implementation of Jingle.)
Open source libraries, such as ZeroMQ (as used by TokBox for their Rumour service) and OpenMQ ( NullMQ applies ZeroMQ concepts to web platforms using the STOMP protocol over WebSocket.)
Commercial cloud-messaging platforms that use WebSocket (though they may fall back to long polling), such as Pusher , Kaazing , and PubNub (PubNub also has an API for WebRTC .)
Commercial WebRTC platforms, such as vLine
(Developer Phil Leggetter's Real-Time Web Technologies Guide provides a comprehensive list of messaging services and libraries.)
Build a signaling service with Socket.io on Node
The following is code for a simple web app that uses a signaling service built with Socket.io on Node . The design of Socket.io makes it simple to build a service to exchange messages and Socket.io is particularly suited to WebRTC signaling because of its built-in concept of rooms. This example is not designed to scale as a production-grade signaling service, but is simple to understand for a relatively small number of users.
Socket.io uses WebSocket with fallbacks: AJAX long polling, AJAX multipart streaming, Forever Iframe, and JSONP polling. It has been ported to various backends, but is perhaps best known for its Node version used in this example.
There's no WebRTC in this example. It's designed only to show how to build signaling into a web app. View the console log to see what's happening as clients join a room and exchange messages. This WebRTC codelab gives step-by-step instructions for how to integrate this into a complete WebRTC video chat app.
Here is the client index.html
:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
Here's the JavaScript file main.js
referenced in the client:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
Here's the complete server app:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(You don't need to learn about node-static for this. It just happens to be used in this example.)
To run this app on localhost, you need to have Node, Socket.IO, and node-static installed. Node can be downloaded from Node.js (installation is straightforward and quick). To install Socket.IO and node-static, run Node Package Manager from a terminal in your app directory:
npm install socket.io
npm install node-static
To start the server, run the following command from a terminal in your app directory:
node server.js
From your browser, open localhost:2013
. Open a new tab or window in any browser and open localhost:2013
again. To see what's happening, check the console. In Chrome and Opera, you can access the console through Google Chrome Developer Tools with Ctrl+Shift+J
(or Command+Option+J
on Mac).
Whatever approach you choose for signaling, your backend and client app - at the very least - need to provide services similar to this example.
Signaling gotchas
-
RTCPeerConnection
won't start gathering candidates untilsetLocalDescription()
is called. This is mandated in the JSEP IETF draft . - Take advantage of Trickle ICE. Call
addIceCandidate()
as soon as candidates arrive.
Readymade signaling servers
If you don't want to roll your own, there are several WebRTC signaling servers available, which use Socket.IO like the previous example and are integrated with WebRTC client JavaScript libraries:
- webRTC.io is one of the first abstraction libraries for WebRTC.
- Signalmaster is a signaling server created for use with the SimpleWebRTC JavaScript client library.
If you don't want to write any code at all, complete commercial WebRTC platforms are available from companies, such as vLine , OpenTok , and Asterisk .
For the record, Ericsson built a signaling server using PHP on Apache in the early days of WebRTC. This is now somewhat obsolete, but it's worth looking at the code if you're considering something similar.
امنیت سیگنالینگ
"Security is the art of making nothing happen."
سلمان رشدی
Encryption is mandatory for all WebRTC components.
However, signaling mechanisms aren't defined by WebRTC standards, so it's up to you to make signaling secure. If an attacker manages to hijack signaling, they can stop sessions, redirect connections, and record, alter, or inject content.
The most important factor in securing signaling is to use secure protocols - HTTPS and WSS (for example, TLS) - which ensure that messages cannot be intercepted unencrypted. Also, be careful not to broadcast signaling messages in a way that they can be accessed by other callers using the same signaling server.
After signaling: Use ICE to cope with NATs and firewalls
For metadata signaling, WebRTC apps use an intermediary server, but for actual media and data streaming once a session is established, RTCPeerConnection
attempts to connect clients directly or peer-to-peer.
In a simpler world, every WebRTC endpoint would have a unique address that it could exchange with other peers in order to communicate directly.

In reality, most devices live behind one or more layers of NAT , some have antivirus software that blocks certain ports and protocols, and many are behind proxies and corporate firewalls. A firewall and NAT may in fact be implemented by the same device, such as a home WIFI router.

WebRTC apps can use the ICE framework to overcome the complexities of real-world networking. To enable this to happen, your app must pass ICE server URLs to RTCPeerConnection
, as described in this article.
ICE tries to find the best path to connect peers. It tries all possibilities in parallel and chooses the most efficient option that works. ICE first tries to make a connection using the host address obtained from a device's operating system and network card. If that fails (which it will for devices behind NATs), ICE obtains an external address using a STUN server and, if that fails, traffic is routed through a TURN relay server.
In other words, a STUN server is used to get an external network address and TURN servers are used to relay traffic if direct (peer-to-peer) connection fails.
Every TURN server supports STUN. A TURN server is a STUN server with additional built-in relaying functionality. ICE also copes with the complexities of NAT setups. In reality, NAT hole-punching may require more than just a public IP:port address.
URLs for STUN and/or TURN servers are (optionally) specified by a WebRTC app in the iceServers
configuration object that is the first argument to the RTCPeerConnection
constructor. For appr.tc , that value looks like this:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
Once RTCPeerConnection
has that information, the ICE magic happens automatically. RTCPeerConnection
uses the ICE framework to work out the best path between peers, working with STUN and TURN servers as necessary.
STUN
NATs provide a device with an IP address for use within a private local network, but this address can't be used externally. Without a public address, there's no way for WebRTC peers to communicate. To get around this problem, WebRTC uses STUN .
STUN servers live on the public internet and have one simple task - check the IP:port address of an incoming request (from an app running behind a NAT) and send that address back as a response. In other words, the app uses a STUN server to discover its IP:port from a public perspective. This process enables a WebRTC peer to get a publicly accessible address for itself and then pass it to another peer through a signaling mechanism in order to set up a direct link. (In practice, different NATs work in different ways and there may be multiple NAT layers, but the principle is still the same.)
STUN servers don't have to do much or remember much, so relatively low-spec STUN servers can handle a large number of requests.
Most WebRTC calls successfully make a connection using STUN - 86% according to Webrtcstats.com , though this can be less for calls between peers behind firewalls and complex NAT configurations.

بچرخانید
RTCPeerConnection
tries to set up direct communication between peers over UDP. If that fails, RTCPeerConnection
resorts to TCP. If that fails, TURN servers can be used as a fallback, relaying data between endpoints.
Just to reiterate, TURN is used to relay audio, video, and data streaming between peers, not signaling data!
TURN servers have public addresses, so they can be contacted by peers even if the peers are behind firewalls or proxies. TURN servers have a conceptually simple task - to relay a stream. However, unlike STUN servers, they inherently consume a lot of bandwidth. In other words, TURN servers need to be beefier.

This diagram shows TURN in action. Pure STUN didn't succeed, so each peer resorts to using a TURN server.
Deploying STUN and TURN servers
For testing, Google runs a public STUN server, stun.l.google.com:19302, as used by appr.tc . For a production STUN/TURN service, use the rfc5766-turn-server. Source code for STUN and TURN servers is available on GitHub , where you can also find links to several sources of information about server installation. A VM image for Amazon Web Services is also available.
An alternative TURN server is restund, available as source code and also for AWS. Here are instructions for how to set up restund on Compute Engine.
- Open firewall as necessary for tcp=443, udp/tcp=3478.
- Create four instances, one for each public IP, Standard Ubuntu 12.06 image.
- Set up local firewall config (allow ANY from ANY).
- Install tools:
shell sudo apt-get install make sudo apt-get install gcc
- Install libre from creytiv.com/re.html .
- Fetch restund from creytiv.com/restund.html and unpack./
-
wget
hancke.name/restund-auth.patch and apply withpatch -p1 < restund-auth.patch
. - Run
make
,sudo make install
for libre and restund. - Adapt
restund.conf
to your needs (replace IP addresses and make sure it contains the same shared secret) and copy to/etc
. - Copy
restund/etc/restund
to/etc/init.d/
. - Configure restund:
- Set
LD_LIBRARY_PATH
. - Copy
restund.conf
to/etc/restund.conf
. - Set
restund.conf
to use the right 10. IP address.
- Set
- Run restund
- Test using stund client from remote machine:
./client IP:port
Beyond one-to-one: Multiparty WebRTC
You may also want to take a look at Justin Uberti's proposed IETF standard for a REST API for access to TURN Services .
It's easy to imagine use cases for media streaming that go beyond a simple one-to-one call. For example, video conferencing between a group of colleagues or a public event with one speaker and hundreds or millions of viewers.
A WebRTC app can use multiple RTCPeerConnections so that every endpoint connects to every other endpoint in a mesh configuration. This is the approach taken by apps, such as talky.io , and works remarkably well for a small handful of peers. Beyond that, processing and bandwidth consumption becomes excessive, especially for mobile clients.

Alternatively, a WebRTC app could choose one endpoint to distribute streams to all others in a star configuration. It would also be possible to run a WebRTC endpoint on a server and construct your own redistribution mechanism (a sample client app is provided by webrtc.org).
Since Chrome 31 and Opera 18, a MediaStream
from one RTCPeerConnection
can be used as the input for another. This can enable more flexible architectures because it enables a web app to handle call-routing by choosing which other peer to connect to. To see this in action, see WebRTC samples Peer connection relay and WebRTC samples Multiple peer connections .
Multipoint Control Unit
A better option for a large number of endpoints is to use a Multipoint Control Unit (MCU). This is a server that works as a bridge to distribute media between a large number of participants. MCUs can cope with different resolutions, codecs, and frame rates in a video conference; handle transcoding; do selective stream forwarding; and mix or record audio and video. For multiparty calls, there are a number of issues to consider, particularly how to display multiple video inputs and mix audio from multiple sources. Cloud platforms, such as vLine , also attempt to optimize traffic routing.
It's possible to buy a complete MCU hardware package or build your own.

Several open source MCU software options are available. For example, Licode (previously known as Lynckia) produces an open source MCU for WebRTC. OpenTok has Mantis .
Beyond browsers: VoIP, telephones, and messaging
The standardized nature of WebRTC makes it possible to establish communication between a WebRTC app running in a browser and a device or platform running on another communication platform, such as a telephone or a video-conferencing system.
SIP is a signaling protocol used by VoIP and video-conferencing systems. To enable communication between a WebRTC web app and a SIP client, such as a video-conferencing system, WebRTC needs a proxy server to mediate signaling. Signaling must flow through the gateway but, once communication has been established, SRTP traffic (video and audio) can flow directly peer to peer.
The Public Switched Telephone Network (PSTN) is the circuit-switched network of all "plain old" analog telephones. For calls between WebRTC web apps and telephones, traffic must go through a PSTN gateway. Likewise, WebRTC web apps need an intermediary XMPP server to communicate with Jingle endpoints such as IM clients. Jingle was developed by Google as an extension to XMPP to enable voice and video for messaging services. Current WebRTC implementations are based on the C++ libjingle library, an implementation of Jingle initially developed for Talk.
A number of apps, libraries, and platforms make use of WebRTC's ability to communicate with the outside world:
- sipML5 : an open source JavaScript SIP client
- jsSIP : JavaScript SIP library
- Phono : open source JavaScript phone API built as a plugin
- Zingaya : an embeddable phone widget
- Twilio : voice and messaging
- Uberconference : conferencing
The sipML5 developers have also built the webrtc2sip gateway. Tethr and Tropo have demonstrated a framework for disaster communications "in a briefcase" using an OpenBTS cell to enable communications between feature phones and computers through WebRTC. That's telephone communication without a carrier!
بیشتر بدانید
The WebRTC codelab provides step-by-step instructions for how to build a video and text chat app using a Socket.io signaling service running on Node.
Google I/O WebRTC presentation from 2013 with WebRTC tech lead, Justin Uberti
Chris Wilson's SFHTML5 presentation - Introduction to WebRTC Apps
The 350-page book WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web provides a lot of detail about data and signaling pathways, and includes a number of detailed network topology diagrams.
WebRTC and Signaling: What Two Years Has Taught Us - TokBox blog post about why leaving signaling out of the spec was a good idea
Ben Strong's A Practical Guide to Building WebRTC Apps provides a lot of information about WebRTC topologies and infrastructure.
The WebRTC chapter in Ilya Grigorik's High Performance Browser Networking goes deep into WebRTC architecture, use cases, and performance.
،What is signaling?
Signaling is the process of coordinating communication. In order for a WebRTC app to set up a call, its clients need to exchange the following information:
- Session-control messages used to open or close communication
- پیام های خطا
- Media metadata, such as codecs, codec settings, bandwidth, and media types
- Key data used to establish secure connections
- Network data, such as a host's IP address and port as seen by the outside world
This signaling process needs a way for clients to pass messages back and forth. That mechanism is not implemented by the WebRTC APIs. You need to build it yourself. Later in this article, you learn ways to build a signaling service. First, however, you need a little context.
Why is signaling not defined by WebRTC?
To avoid redundancy and to maximize compatibility with established technologies, signaling methods and protocols are not specified by WebRTC standards. This approach is outlined by the JavaScript Session Establishment Protocol (JSEP) :
JSEP's architecture also avoids a browser having to save state, that is, to function as a signaling state machine. This would be problematic if, for example, signaling data was lost each time a page was reloaded. Instead, signaling state can be saved on a server.

JSEP requires the exchange between peers of offer and answer , the media metadata mentioned above. Offers and answers are communicated in Session Description Protocol (SDP) format, which look like this:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
Want to know what all this SDP gobbledygook actually means? Take a look at the Internet Engineering Task Force (IETF) examples .
Bear in mind that WebRTC is designed so that the offer or answer can be tweaked before being set as the local or remote description by editing the values in the SDP text. For example, the preferAudioCodec()
function in appr.tc can be used to set the default codec and bitrate. SDP is somewhat painful to manipulate with JavaScript and there is discussion about whether future versions of WebRTC should use JSON instead, but there are some advantages to sticking with SDP.
RTCPeerConnection
API and signaling: Offer, answer, and candidate
RTCPeerConnection
is the API used by WebRTC apps to create a connection between peers, and communicate audio and video.
To initialize this process, RTCPeerConnection
has two tasks:
- Ascertain local media conditions, such as resolution and codec capabilities. This is the metadata used for the offer-and-answer mechanism.
- Get potential network addresses for the app's host, known as candidates .
Once this local data has been ascertained, it must be exchanged through a signaling mechanism with the remote peer.
Imagine Alice is trying to call Eve . Here's the full offer/answer mechanism in all its gory detail:
- Alice creates an
RTCPeerConnection
object. - Alice creates an offer (an SDP session description) with the
RTCPeerConnection
createOffer()
method. - Alice calls
setLocalDescription()
with her offer. - Alice stringifies the offer and uses a signaling mechanism to send it to Eve.
- Eve calls
setRemoteDescription()
with Alice's offer, so that herRTCPeerConnection
knows about Alice's setup. - Eve calls
createAnswer()
and the success callback for this is passed a local session description - Eve's answer. - Eve sets her answer as the local description by calling
setLocalDescription()
. - Eve then uses the signaling mechanism to send her stringified answer to Alice.
- Alice sets Eve's answer as the remote session description using
setRemoteDescription()
.
Alice and Eve also need to exchange network information. The expression "finding candidates" refers to the process of finding network interfaces and ports using the ICE framework .
- Alice creates an
RTCPeerConnection
object with anonicecandidate
handler. - The handler is called when network candidates become available.
- In the handler, Alice sends stringified candidate data to Eve through their signaling channel.
- When Eve gets a candidate message from Alice, she calls
addIceCandidate()
to add the candidate to the remote peer description.
JSEP supports ICE Candidate Trickling , which allows the caller to incrementally provide candidates to the callee after the initial offer, and for the callee to begin acting on the call and set up a connection without waiting for all candidates to arrive.
Code WebRTC for signaling
The following code snippet is a W3C code example that summarizes the complete signaling process. The code assumes the existence of some signaling mechanism, SignalingChannel
. Signaling is discussed in greater detail later.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
To see the offer/answer and candidate-exchange processes in action, see simpl.info RTCPeerConnection and look at the console log for a single-page video chat example. If you want more, download a complete dump of WebRTC signaling and stats from the about://webrtc-internals page in Google Chrome or the opera://webrtc-internals page in Opera.
Peer discovery
This is a fancy way of asking, "How do I find someone to talk to?"
For telephone calls, you have telephone numbers and directories. For online video chat and messaging, you need identity and presence management systems, and a means for users to initiate sessions. WebRTC apps need a way for clients to signal to each other that they want to start or join a call.
Peer discovery mechanisms are not defined by WebRTC and you don't go into the options here. The process can be as simple as emailing or messaging a URL. For video chat apps, such as Talky , tawk.to and Browser Meeting , you invite people to a call by sharing a custom link. Developer Chris Ball built an intriguing serverless-webrtc experiment that enables WebRTC call participants to exchange metadata by any messaging service they like, such as IM, email, or homing pigeon.
How can you build a signaling service?
To reiterate, signaling protocols and mechanisms are not defined by WebRTC standards. Whatever you choose, you need an intermediary server to exchange signaling messages and app data between clients. Sadly, a web app cannot simply shout into the internet, "Connect me to my friend!"
Thankfully signaling messages are small and mostly exchanged at the start of a call. In testing with appr.tc for a video chat session, a total of around 30-45 messages were handled by the signaling service with a total size for all messages of around 10KB.
As well as being relatively undemanding in terms of bandwidth, WebRTC signaling services don't consume much processing or memory because they only need to relay messages and retain a small amount of session state data, such as which clients are connected.
Push messages from the server to the client
A message service for signaling needs to be bidirectional: client to server and server to client. Bidirectional communication goes against the HTTP client/server request/response model, but various hacks such as long polling have been developed over many years in order to push data from a service running on a web server to a web app running in a browser.
More recently, the EventSource
API has been widely implemented . This enables server-sent events - data sent from a web server to a browser client through HTTP. EventSource
is designed for one-way messaging, but it can be used in combination with XHR to build a service for exchanging signaling messages. A signaling service passes a message from a caller, delivered by XHR request, by pushing it through EventSource
to the callee.
WebSocket is a more-natural solution, designed for full duplex client–server communication - messages that can flow in both directions at the same time. One advantage of a signaling service built with pure WebSocket or server-sent events ( EventSource
) is that the backend for these APIs can be implemented on a variety of web frameworks common to most web-hosting packages for languages such as PHP, Python, and Ruby.
All modern browsers except Opera Mini support WebSocket and, more importantly, all browsers that support WebRTC also support WebSocket, both on desktop and mobile. TLS should be used for all connections to ensure messages cannot be intercepted unencrypted and also to reduce problems with proxy traversal . (For more information about WebSocket and proxy traversal see the WebRTC chapter in Ilya Grigorik's High Performance Browser Networking .)
It is also possible to handle signaling by getting WebRTC clients to poll a messaging server repeatedly through Ajax, but that leads to a lot of redundant network requests, which is especially problematic for mobile devices. Even after a session has been established, peers need to poll for signaling messages in case of changes or session termination by other peers. The WebRTC Book app example takes this option with some optimizations for polling frequency.
Scale signaling
Although a signaling service consumes relatively little bandwidth and CPU per client, signaling servers for a popular app may have to handle a lot of messages from different locations with high levels of concurrency. WebRTC apps that get a lot of traffic need signaling servers able to handle considerable load. You don't go into detail here, but there are a number of options for high-volume, high-performance messaging, including the following:
eXtensible Messaging and Presence Protocol (XMPP), originally known as Jabber-a protocol developed for instant messaging that can be used for signaling (Server implementations include ejabberd and Openfire . JavaScript clients, such as Strophe.js , use BOSH to emulate bidirectional streaming, but for various reasons , BOSH may not be as efficient as WebSocket and, for the same reasons, may not scale well.) (On a tangent, Jingle is an XMPP extension to enable voice and video. The WebRTC project uses network and transport components from the libjingle library - a C++ implementation of Jingle.)
Open source libraries, such as ZeroMQ (as used by TokBox for their Rumour service) and OpenMQ ( NullMQ applies ZeroMQ concepts to web platforms using the STOMP protocol over WebSocket.)
Commercial cloud-messaging platforms that use WebSocket (though they may fall back to long polling), such as Pusher , Kaazing , and PubNub (PubNub also has an API for WebRTC .)
Commercial WebRTC platforms, such as vLine
(Developer Phil Leggetter's Real-Time Web Technologies Guide provides a comprehensive list of messaging services and libraries.)
Build a signaling service with Socket.io on Node
The following is code for a simple web app that uses a signaling service built with Socket.io on Node . The design of Socket.io makes it simple to build a service to exchange messages and Socket.io is particularly suited to WebRTC signaling because of its built-in concept of rooms. This example is not designed to scale as a production-grade signaling service, but is simple to understand for a relatively small number of users.
Socket.io uses WebSocket with fallbacks: AJAX long polling, AJAX multipart streaming, Forever Iframe, and JSONP polling. It has been ported to various backends, but is perhaps best known for its Node version used in this example.
There's no WebRTC in this example. It's designed only to show how to build signaling into a web app. View the console log to see what's happening as clients join a room and exchange messages. This WebRTC codelab gives step-by-step instructions for how to integrate this into a complete WebRTC video chat app.
Here is the client index.html
:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
Here's the JavaScript file main.js
referenced in the client:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
Here's the complete server app:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(You don't need to learn about node-static for this. It just happens to be used in this example.)
To run this app on localhost, you need to have Node, Socket.IO, and node-static installed. Node can be downloaded from Node.js (installation is straightforward and quick). To install Socket.IO and node-static, run Node Package Manager from a terminal in your app directory:
npm install socket.io
npm install node-static
To start the server, run the following command from a terminal in your app directory:
node server.js
From your browser, open localhost:2013
. Open a new tab or window in any browser and open localhost:2013
again. To see what's happening, check the console. In Chrome and Opera, you can access the console through Google Chrome Developer Tools with Ctrl+Shift+J
(or Command+Option+J
on Mac).
Whatever approach you choose for signaling, your backend and client app - at the very least - need to provide services similar to this example.
Signaling gotchas
-
RTCPeerConnection
won't start gathering candidates untilsetLocalDescription()
is called. This is mandated in the JSEP IETF draft . - Take advantage of Trickle ICE. Call
addIceCandidate()
as soon as candidates arrive.
Readymade signaling servers
If you don't want to roll your own, there are several WebRTC signaling servers available, which use Socket.IO like the previous example and are integrated with WebRTC client JavaScript libraries:
- webRTC.io is one of the first abstraction libraries for WebRTC.
- Signalmaster is a signaling server created for use with the SimpleWebRTC JavaScript client library.
If you don't want to write any code at all, complete commercial WebRTC platforms are available from companies, such as vLine , OpenTok , and Asterisk .
For the record, Ericsson built a signaling server using PHP on Apache in the early days of WebRTC. This is now somewhat obsolete, but it's worth looking at the code if you're considering something similar.
امنیت سیگنالینگ
"Security is the art of making nothing happen."
سلمان رشدی
Encryption is mandatory for all WebRTC components.
However, signaling mechanisms aren't defined by WebRTC standards, so it's up to you to make signaling secure. If an attacker manages to hijack signaling, they can stop sessions, redirect connections, and record, alter, or inject content.
The most important factor in securing signaling is to use secure protocols - HTTPS and WSS (for example, TLS) - which ensure that messages cannot be intercepted unencrypted. Also, be careful not to broadcast signaling messages in a way that they can be accessed by other callers using the same signaling server.
After signaling: Use ICE to cope with NATs and firewalls
For metadata signaling, WebRTC apps use an intermediary server, but for actual media and data streaming once a session is established, RTCPeerConnection
attempts to connect clients directly or peer-to-peer.
In a simpler world, every WebRTC endpoint would have a unique address that it could exchange with other peers in order to communicate directly.

In reality, most devices live behind one or more layers of NAT , some have antivirus software that blocks certain ports and protocols, and many are behind proxies and corporate firewalls. A firewall and NAT may in fact be implemented by the same device, such as a home WIFI router.

WebRTC apps can use the ICE framework to overcome the complexities of real-world networking. To enable this to happen, your app must pass ICE server URLs to RTCPeerConnection
, as described in this article.
ICE tries to find the best path to connect peers. It tries all possibilities in parallel and chooses the most efficient option that works. ICE first tries to make a connection using the host address obtained from a device's operating system and network card. If that fails (which it will for devices behind NATs), ICE obtains an external address using a STUN server and, if that fails, traffic is routed through a TURN relay server.
In other words, a STUN server is used to get an external network address and TURN servers are used to relay traffic if direct (peer-to-peer) connection fails.
Every TURN server supports STUN. A TURN server is a STUN server with additional built-in relaying functionality. ICE also copes with the complexities of NAT setups. In reality, NAT hole-punching may require more than just a public IP:port address.
URLs for STUN and/or TURN servers are (optionally) specified by a WebRTC app in the iceServers
configuration object that is the first argument to the RTCPeerConnection
constructor. For appr.tc , that value looks like this:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
Once RTCPeerConnection
has that information, the ICE magic happens automatically. RTCPeerConnection
uses the ICE framework to work out the best path between peers, working with STUN and TURN servers as necessary.
STUN
NATs provide a device with an IP address for use within a private local network, but this address can't be used externally. Without a public address, there's no way for WebRTC peers to communicate. To get around this problem, WebRTC uses STUN .
STUN servers live on the public internet and have one simple task - check the IP:port address of an incoming request (from an app running behind a NAT) and send that address back as a response. In other words, the app uses a STUN server to discover its IP:port from a public perspective. This process enables a WebRTC peer to get a publicly accessible address for itself and then pass it to another peer through a signaling mechanism in order to set up a direct link. (In practice, different NATs work in different ways and there may be multiple NAT layers, but the principle is still the same.)
STUN servers don't have to do much or remember much, so relatively low-spec STUN servers can handle a large number of requests.
Most WebRTC calls successfully make a connection using STUN - 86% according to Webrtcstats.com , though this can be less for calls between peers behind firewalls and complex NAT configurations.

بچرخانید
RTCPeerConnection
tries to set up direct communication between peers over UDP. If that fails, RTCPeerConnection
resorts to TCP. If that fails, TURN servers can be used as a fallback, relaying data between endpoints.
Just to reiterate, TURN is used to relay audio, video, and data streaming between peers, not signaling data!
TURN servers have public addresses, so they can be contacted by peers even if the peers are behind firewalls or proxies. TURN servers have a conceptually simple task - to relay a stream. However, unlike STUN servers, they inherently consume a lot of bandwidth. In other words, TURN servers need to be beefier.

This diagram shows TURN in action. Pure STUN didn't succeed, so each peer resorts to using a TURN server.
Deploying STUN and TURN servers
For testing, Google runs a public STUN server, stun.l.google.com:19302, as used by appr.tc . For a production STUN/TURN service, use the rfc5766-turn-server. Source code for STUN and TURN servers is available on GitHub , where you can also find links to several sources of information about server installation. A VM image for Amazon Web Services is also available.
An alternative TURN server is restund, available as source code and also for AWS. Here are instructions for how to set up restund on Compute Engine.
- Open firewall as necessary for tcp=443, udp/tcp=3478.
- Create four instances, one for each public IP, Standard Ubuntu 12.06 image.
- Set up local firewall config (allow ANY from ANY).
- Install tools:
shell sudo apt-get install make sudo apt-get install gcc
- Install libre from creytiv.com/re.html .
- Fetch restund from creytiv.com/restund.html and unpack./
-
wget
hancke.name/restund-auth.patch and apply withpatch -p1 < restund-auth.patch
. - Run
make
,sudo make install
for libre and restund. - Adapt
restund.conf
to your needs (replace IP addresses and make sure it contains the same shared secret) and copy to/etc
. - Copy
restund/etc/restund
to/etc/init.d/
. - Configure restund:
- Set
LD_LIBRARY_PATH
. - Copy
restund.conf
to/etc/restund.conf
. - Set
restund.conf
to use the right 10. IP address.
- Set
- Run restund
- Test using stund client from remote machine:
./client IP:port
Beyond one-to-one: Multiparty WebRTC
You may also want to take a look at Justin Uberti's proposed IETF standard for a REST API for access to TURN Services .
It's easy to imagine use cases for media streaming that go beyond a simple one-to-one call. For example, video conferencing between a group of colleagues or a public event with one speaker and hundreds or millions of viewers.
A WebRTC app can use multiple RTCPeerConnections so that every endpoint connects to every other endpoint in a mesh configuration. This is the approach taken by apps, such as talky.io , and works remarkably well for a small handful of peers. Beyond that, processing and bandwidth consumption becomes excessive, especially for mobile clients.

Alternatively, a WebRTC app could choose one endpoint to distribute streams to all others in a star configuration. It would also be possible to run a WebRTC endpoint on a server and construct your own redistribution mechanism (a sample client app is provided by webrtc.org).
Since Chrome 31 and Opera 18, a MediaStream
from one RTCPeerConnection
can be used as the input for another. This can enable more flexible architectures because it enables a web app to handle call-routing by choosing which other peer to connect to. To see this in action, see WebRTC samples Peer connection relay and WebRTC samples Multiple peer connections .
Multipoint Control Unit
A better option for a large number of endpoints is to use a Multipoint Control Unit (MCU). This is a server that works as a bridge to distribute media between a large number of participants. MCUs can cope with different resolutions, codecs, and frame rates in a video conference; handle transcoding; do selective stream forwarding; and mix or record audio and video. For multiparty calls, there are a number of issues to consider, particularly how to display multiple video inputs and mix audio from multiple sources. Cloud platforms, such as vLine , also attempt to optimize traffic routing.
It's possible to buy a complete MCU hardware package or build your own.

Several open source MCU software options are available. For example, Licode (previously known as Lynckia) produces an open source MCU for WebRTC. OpenTok has Mantis .
Beyond browsers: VoIP, telephones, and messaging
The standardized nature of WebRTC makes it possible to establish communication between a WebRTC app running in a browser and a device or platform running on another communication platform, such as a telephone or a video-conferencing system.
SIP is a signaling protocol used by VoIP and video-conferencing systems. To enable communication between a WebRTC web app and a SIP client, such as a video-conferencing system, WebRTC needs a proxy server to mediate signaling. Signaling must flow through the gateway but, once communication has been established, SRTP traffic (video and audio) can flow directly peer to peer.
The Public Switched Telephone Network (PSTN) is the circuit-switched network of all "plain old" analog telephones. For calls between WebRTC web apps and telephones, traffic must go through a PSTN gateway. Likewise, WebRTC web apps need an intermediary XMPP server to communicate with Jingle endpoints such as IM clients. Jingle was developed by Google as an extension to XMPP to enable voice and video for messaging services. Current WebRTC implementations are based on the C++ libjingle library, an implementation of Jingle initially developed for Talk.
A number of apps, libraries, and platforms make use of WebRTC's ability to communicate with the outside world:
- sipML5 : an open source JavaScript SIP client
- jsSIP : JavaScript SIP library
- Phono : open source JavaScript phone API built as a plugin
- Zingaya : an embeddable phone widget
- Twilio : voice and messaging
- Uberconference : conferencing
The sipML5 developers have also built the webrtc2sip gateway. Tethr and Tropo have demonstrated a framework for disaster communications "in a briefcase" using an OpenBTS cell to enable communications between feature phones and computers through WebRTC. That's telephone communication without a carrier!
بیشتر بدانید
The WebRTC codelab provides step-by-step instructions for how to build a video and text chat app using a Socket.io signaling service running on Node.
Google I/O WebRTC presentation from 2013 with WebRTC tech lead, Justin Uberti
Chris Wilson's SFHTML5 presentation - Introduction to WebRTC Apps
The 350-page book WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web provides a lot of detail about data and signaling pathways, and includes a number of detailed network topology diagrams.
WebRTC and Signaling: What Two Years Has Taught Us - TokBox blog post about why leaving signaling out of the spec was a good idea
Ben Strong's A Practical Guide to Building WebRTC Apps provides a lot of information about WebRTC topologies and infrastructure.
The WebRTC chapter in Ilya Grigorik's High Performance Browser Networking goes deep into WebRTC architecture, use cases, and performance.