WebRTC की मदद से रीयल-टाइम में बातचीत करने की सुविधा चालू करें

1. शुरू करने से पहले

यह कोडलैब आपको वीडियो बनाने और अपने वेबकैम से स्नैपशॉट लेने का तरीका बताता है. साथ ही, WebRTC के साथ उन्हें पीयर-टू-पीयर शेयर करने का तरीका भी बताता है. आप मुख्य WebRTC API को इस्तेमाल करने और Node.js के साथ मैसेज सर्वर सेट अप करने का तरीका भी सीख सकते हैं.

ज़रूरी बातें

  • एचटीएमएल, सीएसएस, और JavaScript की बुनियादी जानकारी

आप क्या बनाएंगे #39;

  • अपने वेबकैम से वीडियो पाएं.
  • RTCPeerConnection के साथ वीडियो स्ट्रीम करें.
  • RTCDataChannel के साथ डेटा स्ट्रीम करें.
  • मैसेज का लेन-देन करने के लिए सिग्नलिंग सेवा सेट अप करें.
  • मिलते-जुलते ऐप्लिकेशन के सिग्नल और मिलते-जुलते सिग्नल को एक साथ जोड़ें.
  • फ़ोटो लें और उसे शेयर करने के लिए किसी डेटा चैनल का इस्तेमाल करें.

आपको इनकी ज़रूरत होगी

  • Chrome 47 या उसके बाद का वर्शन
  • Chrome के लिए वेब सर्वर या आपकी पसंद का वेब सर्वर
  • आपकी पसंद का टेक्स्ट एडिटर
  • Node.js के लिए

2. सैंपल कोड पाएं

कोड डाउनलोड करना

  1. अगर आप GIF को जानते हैं, तो GitHub से इस कोडलैब के कोड को क्लोन करने के लिए, इस निर्देश का इस्तेमाल करें:
git clone https://github.com/googlecodelabs/webrtc-web

अगर आप चाहें, तो कोड की ज़िप फ़ाइल डाउनलोड करने के लिए इस लिंक पर क्लिक करें:

  1. डाउनलोड किए गए ज़िप फ़ाइल को खोलें और webrtc-web-master नाम के प्रोजेक्ट फ़ोल्डर को अनपैक करें. इसमें, इस कोडलैब के हर चरण के लिए एक फ़ोल्डर और आपकी ज़रूरत के सभी संसाधन शामिल हैं.

आप अपने सभी कोड का नाम work नाम की डायरेक्ट्री में रखते हैं.

step-nn फ़ोल्डर में इस कोडलैब के हर चरण के लिए, तैयार किया गया वर्शन मौजूद होता है. संदर्भ के लिए #39;

वेब सर्वर इंस्टॉल करना और उसकी पुष्टि करना

हालांकि, आप अपने वेब सर्वर का इस्तेमाल मुफ़्त में कर सकते हैं, लेकिन इस कोडलैब को इस तरह से डिज़ाइन किया गया है कि यह Chrome के वेब सर्वर के साथ अच्छी तरह काम करे.

  1. अगर आपके पास Chrome के लिए वेब सर्वर नहीं है, तो इस लिंक को Chrome वेब स्टोर से इंस्टॉल करने के लिए, इस लिंक पर क्लिक करें:

d0a4649b4920cf3.png

  1. Chrome में जोड़ें पर क्लिक करें, जो Chrome के लिए वेब सर्वर इंस्टॉल करता है. साथ ही, यह आपके Google ऐप्लिकेशन को अपने-आप एक नए टैब में खोलता है.
  2. वेब सर्वर पर क्लिक करें:

27fce4494f641883.png

एक डायलॉग दिखेगा, जो आपको अपना स्थानीय वेब सर्वर कॉन्फ़िगर करने देता है:

a300381a486b9e22.png

  1. फ़ोल्डर चुनें पर क्लिक करें.
  2. आपने जो work फ़ोल्डर बनाया है उसे चुनें.

वेब सर्वर के यूआरएल के तहत, आपको वह यूआरएल दिखता है जहां आप अपना काम देख सकते हैं

Chrome.

  1. विकल्पों में (फिर से शुरू करना ज़रूरी हो सकता है) में जाकर, index.html अपने-आप दिखाएं चेकबॉक्स को चुनें.
  2. सर्वर को बंद करने और रीस्टार्ट करने के लिए, वेब सर्वर: शुरू किया गया को दो बार टॉगल करें.

f23cafb3993dfac1.png

  1. अपने वेब ब्राउज़र में अपना काम देखने के लिए वेब सर्वर यूआरएल के नीचे मौजूद यूआरएल पर क्लिक करें.

आपको ऐसा दिखने वाला पेज दिखना चाहिए, जो work/index.html से जुड़ा हो:

18a705cb6ccc5181.png

बेशक, यह ऐप्लिकेशन अभी तक कुछ दिलचस्प नहीं कर रहा है. आपका वेब सर्वर ठीक से काम करे, यह पक्का करने के लिए यह एक छोटा कंकाल है. बाद के चरणों में आप फ़ंक्शन और लेआउट की सुविधाएं जोड़ सकते हैं.

3. अपने वेबकैम से वीडियो स्ट्रीम करें

इस चरण का पूरा वर्शन step-01 फ़ोल्डर में मौजूद है.

एचटीएमएल का डैश जोड़ें

video और script एलिमेंट जोड़ने के लिए, इस कोड को कॉपी करें और अपनी work डायरेक्ट्री में index.html फ़ाइल में चिपकाएं:

<!DOCTYPE html>
<html>

<head>

  <title>Real-time communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Real-time communication with WebRTC</h1>

  <video autoplay playsinline></video>

  <script src="js/main.js"></script>

</body>

</html>

JavaScript का पिंच करें

इस कोड को कॉपी करें और अपने js फ़ोल्डर में main.js फ़ाइल में चिपकाएं:

'use strict';

// In this codelab, you  only stream video, not audio (video: true).
const mediaStreamConstraints = {
  video: true,
};

// The video element where the stream is displayed
const localVideo = document.querySelector('video');

// The local stream that's displayed on the video
let localStream;

// Handle success and add the MediaStream to the video element
function gotLocalMediaStream(mediaStream) {
  localStream = mediaStream;
  localVideo.srcObject = mediaStream;
}

// Handle error and log a message to the console with the error message
function handleLocalMediaStreamError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

// Initialize media stream
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
  .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);

इसे आज़माएं

अपने ब्राउज़र में index.html फ़ाइल खोलें. इसके बाद, आपको कुछ ऐसा दिखेगा कि उस फ़ाइल को वेबकैम से देखा जा सकता है:

9297048e43ed0f3d.png

यह कैसे काम करता है

getUserMedia() कॉल के बाद, ब्राउज़र मौजूदा कैमरे के लिए कैमरा ऐक्सेस करने का पहला अनुरोध होने पर, कैमरे को ऐक्सेस करने की अनुमति मांगता है.

अगर यह सही से काम करता है, तो MediaStream दिखता है, जिसका media एलिमेंट srcObject एट्रिब्यूट के ज़रिए इस्तेमाल किया जा सकता है:

navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
  .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);


}
function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
}

constraints तर्क की मदद से आप यह तय कर सकते हैं कि किस तरह की मीडिया फ़ाइलें हासिल करें. इस उदाहरण में, मीडिया सिर्फ़ वीडियो के तौर पर है, क्योंकि ऑडियो डिफ़ॉल्ट रूप से बंद होता है:

const mediaStreamConstraints = {
  video: true,
};

आप वीडियो रिज़ॉल्यूशन जैसी अन्य ज़रूरी शर्तों के लिए, कंस्ट्रेंट का इस्तेमाल कर सकते हैं:

const hdConstraints = {
  video: {
    width: {
      min: 1280
    },
    height: {
      min: 720
    }
  }
}

MediaTrackConstraints की खास जानकारी में, सभी संभावित कंस्ट्रेंट को सूची में शामिल किया गया है. हालांकि, सभी विकल्प सभी ब्राउज़र पर काम नहीं करते. अगर अनुरोध किए गए रिज़ॉल्यूशन को, फ़िलहाल चुने गए कैमरे के साथ इस्तेमाल नहीं किया जा सकता, तो getUserMedia() को OverconstrainedError के साथ अस्वीकार कर दिया गया है. आपको #39; कैमरा ऐक्सेस करने की अनुमति देने के लिए कहा जाता है.

अगर getUserMedia() सफल होता है, तो वेबकैम से वीडियो स्ट्रीम को वीडियो एलिमेंट के स्रोत के तौर पर सेट किया जाता है:

function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
}

स्कोर बोनस पॉइंट

  • getUserMedia() को भेजा गया localStream ऑब्जेक्ट, ग्लोबल दायरे में है, ताकि आप ब्राउज़र कंसोल से उसकी जांच कर सकें. कंसोल खोलें, stream, लिखें और Enter (Mac पर Return) दबाएं. Chrome में कंसोल देखने के लिए, Control+Shift+J (या Mac पर Command+Option+J) दबाएं.
  • localStream.getVideoTracks() क्या दिखाता है?
  • localStream.getVideoTracks()[0].stop() पर कॉल करें.
  • कंस्ट्रेंट ऑब्जेक्ट देखें. अगर आप इसे {audio: true, video: true} में बदलते हैं, तो क्या होता है?
  • वीडियो एलिमेंट का साइज़ क्या है? डिसप्ले साइज़ के बजाय, JavaScript से वीडियो का सामान्य साइज़ कैसे देखा जा सकता है? जांचने के लिए, Google Chrome डेवलपर टूल का इस्तेमाल करें.
  • वीडियो एलिमेंट में सीएसएस फ़िल्टर इस तरह जोड़ें:
video {
  filter: blur(4px) invert(1) opacity(0.5);
}
  • SVG फ़िल्टर जोड़ें, जैसे:
video {
   filter: hue-rotate(180deg) saturate(200%);
 }

सलाह

सबसे सही तरीका

पक्का करें कि वीडियो में मौजूद एलिमेंट अपने कंटेनर में ओवरफ़्लो न हो रहा हो. इस कोडलैब ने width और max-width को जोड़कर, वीडियो का पसंदीदा साइज़ और ज़्यादा से ज़्यादा साइज़ सेट किया. आपका ब्राउज़र अपने-आप ऊंचाई का हिसाब लगा लेता है.

video {
  max-width: 100%;
  width: 320px;
}

4. RTCPeerConnection API पर वीडियो स्ट्रीम करें

इस चरण का पूरा वर्शन step-2 फ़ोल्डर में मौजूद है.

वीडियो के एलिमेंट और कंट्रोल बटन जोड़ें

index.html फ़ाइल में, एक video एलिमेंट को दो video और तीन button एलिमेंट से बदलें:

<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>


<div>
  <button id="startButton">Start</button>
  <button id="callButton">Call</button>
  <button id="hangupButton">Hang Up</button>
</div>

एक वीडियो एलिमेंट, getUserMedia() की स्ट्रीम दिखाता है. वहीं, दूसरे एलिमेंट में RTCPeerconnection के ज़रिए स्ट्रीम किया गया वीडियो दिखता है. (असल दुनिया वाले ऐप्लिकेशन में, एक video एलिमेंट, स्थानीय स्ट्रीम दिखाएगा और दूसरा, रिमोट स्ट्रीम दिखाएगा.)

अडैप्टर.js शीम जोड़ें

इस स्क्रिप्ट एलिमेंट को कॉपी करें और main.js के स्क्रिप्ट एलिमेंट के ऊपर चिपकाएं:

<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

आपकी index.html फ़ाइल अब कुछ ऐसी दिखेगी:

<!DOCTYPE html>
<html>

<head>
  <title>Real-time communication with WebRTC</title>
  <link rel="stylesheet" href="css/main.css" />
</head>

<body>
  <h1>Real-time communication with WebRTC</h1>

  <video id="localVideo" autoplay playsinline></video>
  <video id="remoteVideo" autoplay playsinline></video>

  <div>
    <button id="startButton">Start</button>
    <button id="callButton">Call</button>
    <button id="hangupButton">Hang Up</button>
  </div>

  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>
</body>
</html>

RTCPeerConnection कोड इंस्टॉल करें

main.js को step-02 फ़ोल्डर के वर्शन से बदलें.

कॉल करो

  1. index.html फ़ाइल खोलें.
  2. अपने वेबकैम से वीडियो पाने के लिए शुरू करें पर क्लिक करें.
  3. मिलते-जुलते ऐप्लिकेशन का कनेक्शन बनाने के लिए, कॉल करें पर क्लिक करें

आपको अपने वेबकैम से एक ही वीडियो दोनों video एलिमेंट में दिखेगा.

  1. WebRTC लॉगिंग देखने के लिए ब्राउज़र कंसोल देखें.

यह कैसे काम करता है

यह कदम काफ़ी कारगर साबित होता है.

WebRTC, RTCPeerConnection एपीआई का इस्तेमाल करके, वीडियो को स्ट्रीम करने के लिए कनेक्शन सेट अप करता है. यह कनेक्शन WebRTC क्लाइंट के बीच मशहूर है.

इस उदाहरण में, दो RTCPeerConnection ऑब्जेक्ट एक ही पेज पर हैं: pc1 और pc2.

WebRTC पीयर के बीच कॉल सेट में तीन टास्क शामिल हैं:

  1. कॉल के हर खत्म के लिए RTCPeerConnection बनाएं और हर कॉल के आखिर में getUserMedia() की स्थानीय स्ट्रीम जोड़ें.
  2. नेटवर्क की जानकारी पाएं और उसे शेयर करें.

संभावित कनेक्शन एंडपॉइंट को ICE उम्मीदवार के तौर पर जाना जाता है.

  1. स्थानीय और दूर की जानकारी पाएं और शेयर करें.

स्थानीय मीडिया का मेटाडेटा सेशन ब्यौरे के प्रोटोकॉल (एसडीपी) फ़ॉर्मैट में है.

मान लें कि ऐलिस और बॉब वीडियो चैट सेट अप करने के लिए, RTCPeerConnection का इस्तेमाल करना चाहती हैं.

सबसे पहले, ऐलिस और बॉब नेटवर्क की जानकारी का लेन-देन करती हैं. एक्सप्रेशन ढूंढने वाले उम्मीदवार, ICE फ़्रेमवर्क का इस्तेमाल करके, नेटवर्क इंटरफ़ेस और पोर्ट ढूंढने की प्रोसेस को कहते हैं.

  1. ऐलिस, onicecandidate (addEventListener('icecandidate')) हैंडलर के साथ एक RTCPeerConnection ऑब्जेक्ट बनाती हैं.

यह main.js के इस कोड से मेल खाता है:

let localPeerConnection;
localPeerConnection = new RTCPeerConnection(servers);
localPeerConnection.addEventListener('icecandidate', handleConnection);
localPeerConnection.addEventListener(
    'iceconnectionstatechange', handleConnectionChange);
  1. ऐलिस ने getUserMedia() को कॉल किया और उसके लिए पास की गई स्ट्रीम को जोड़ दिया:
navigator.mediaDevices.getUserMedia(mediaStreamConstraints).
  then(gotLocalMediaStream).
  catch(handleLocalMediaStreamError);
function gotLocalMediaStream(mediaStream) {
  localVideo.srcObject = mediaStream;
  localStream = mediaStream;
  trace('Received local stream.');
  callButton.disabled = false;  // Enable call button.
}
localPeerConnection.addStream(localStream);
trace('Added local stream to localPeerConnection.');
  1. नेटवर्क कैंडिडेट के उपलब्ध होने पर, पहले चरण के onicecandidate हैंडलर को कॉल किया जाता है.
  2. ऐलिस, बॉब को क्रम से लगाया गया उम्मीदवार डेटा भेजती है.

किसी असली ऐप्लिकेशन में, यह प्रक्रिया सिग्नलिंग सेवा के ज़रिए होती है. इसे सिग्नलिंग कहा जाता है. बाद में, ऐसा करने का तरीका जानें. बेशक, इस चरण में दो RTCPeerConnection ऑब्जेक्ट एक ही पेज पर होते हैं और बाहरी मैसेज की ज़रूरत के बिना सीधे बातचीत कर सकते हैं.

  1. जब बॉब को ऐलिस से कोई कैंडिडेट मैसेज मिलता है, तो वह addIceCandidate() को कॉल करता है, ताकि वह मिलते-जुलते ऐप्लिकेशन के रिमोट ब्यौरे में उम्मीदवार जोड़ सके:
function handleConnection(event) {
  const peerConnection = event.target;
  const iceCandidate = event.candidate;

  if (iceCandidate) {
    const newIceCandidate = new RTCIceCandidate(iceCandidate);
    const otherPeer = getOtherPeer(peerConnection);

    otherPeer.addIceCandidate(newIceCandidate)
      .then(() => {
        handleConnectionSuccess(peerConnection);
      }).catch((error) => {
        handleConnectionFailure(peerConnection, error);
      });

    trace(`${getPeerName(peerConnection)} ICE candidate:\n` +
          `${event.candidate.candidate}.`);
  }
}

WebRTC पीयर को लोकल और रिमोट ऑडियो और वीडियो मीडिया जानकारी, जैसे कि रिज़ॉल्यूशन और कोडेक क्षमताओं को खोजना और उनका लेन-देन करना भी ज़रूरी है. मीडिया कॉन्फ़िगरेशन की जानकारी का लेन-देन करने के लिए, ब्लॉब में ब्लॉब को एक्सचेंज किया जाता है. इस बदलाव को ऑफ़र और जवाब के तौर पर जाना जाता है. इसके लिए, एसडीपी फ़ॉर्मैट का इस्तेमाल किया जाता है.

  1. ऐलिस RTCPeerConnection createOffer() तरीके को चलाती हैं.

रिटर्न का वादा RTCSessionDescription-एलिस के स्थानीय सेशन का ब्यौरा देता है:

trace('localPeerConnection createOffer start.');
localPeerConnection.createOffer(offerOptions)
  .then(createdOffer).catch(setSessionDescriptionError);
  1. अगर दावे की समीक्षा हो जाती है, तो ऐलिस setLocalDescription() का इस्तेमाल करके स्थानीय जानकारी सेट करती हैं. इसके बाद, वह अपने सिग्नल के ज़रिए बॉब को यह सत्र जानकारी भेजती हैं.
  2. बॉब ने ऐलिस को जो ब्यौरा भेजा है, उसे setRemoteDescription() की मदद से रिमोट के तौर पर सेट कर रहे हैं.
  3. बॉब RTCPeerConnection createAnswer() तरीका चलाता है और उसे ऐलिस से मिले रिमोट ब्यौरे को पास करता है. इससे, उसके साथ काम करने वाला एक स्थानीय सेशन जनरेट होता है.
  4. createAnswer() का वादा एक RTCSessionDescription से गुज़रता है, जिसे बॉब स्थानीय विवरण के रूप में सेट करता है और ऐलिस को भेजता है.
  5. जब ऐलिस को बॉब का सेशन का ब्यौरा मिलता है, तो वह setRemoteDescription() की मदद से उसे रिमोट ब्यौरे के तौर पर सेट करती है.
// Logs offer creation and sets peer connection session descriptions
function createdOffer(description) {
  trace(`Offer from localPeerConnection:\n${description.sdp}`);

  trace('localPeerConnection setLocalDescription start.');
  localPeerConnection.setLocalDescription(description)
    .then(() => {
      setLocalDescriptionSuccess(localPeerConnection);
    }).catch(setSessionDescriptionError);

  trace('remotePeerConnection setRemoteDescription start.');
  remotePeerConnection.setRemoteDescription(description)
    .then(() => {
      setRemoteDescriptionSuccess(remotePeerConnection);
    }).catch(setSessionDescriptionError);

  trace('remotePeerConnection createAnswer start.');
  remotePeerConnection.createAnswer()
    .then(createdAnswer)
    .catch(setSessionDescriptionError);
}

// Logs answer to offer creation and sets peer-connection session descriptions
function createdAnswer(description) {
  trace(`Answer from remotePeerConnection:\n${description.sdp}.`);

  trace('remotePeerConnection setLocalDescription start.');
  remotePeerConnection.setLocalDescription(description)
    .then(() => {
      setLocalDescriptionSuccess(remotePeerConnection);
    }).catch(setSessionDescriptionError);

  trace('localPeerConnection setRemoteDescription start.');
  localPeerConnection.setRemoteDescription(description)
    .then(() => {
      setRemoteDescriptionSuccess(localPeerConnection);
    }).catch(setSessionDescriptionError);
}

स्कोर बोनस पॉइंट

  1. chrome://webrtc-internals पर जाएं.

यह पेज, WebRTC के आंकड़े और डीबग करने का डेटा देता है. (आप chrome://about पर Chrome यूआरएल की पूरी सूची देख सकते हैं.)

  1. पेज को सीएसएस की मदद से स्टाइल देना:
  2. वीडियो को साथ-साथ रखें.
  3. बड़े टेक्स्ट की मदद से, बटन का साइज़ एक जैसा रखें.
  4. देखें कि लेआउट, मोबाइल पर काम करता हो.
  5. Chrome डेवलपर टूल कंसोल से, localStream, localPeerConnection, और remotePeerConnection देखें.
  6. कंसोल में localPeerConnectionpc1.localDescription को देखें.

एसडीपी फ़ॉर्मैट कैसा दिखता है?

सलाह

  • अडैप्टर.js शिम के बारे में ज़्यादा जानकारी के लिए, adapter.js GitHub का रिपॉज़िटरी देखें.
  • WebRTC की कॉल के लिए, AppRTC और यह कोड, WebRTC प्रोजेक्ट's कैननिकल ऐप्लिकेशन देखें. कॉल सेट अप करने का समय 500 मि॰से॰ से कम है.

सबसे सही तरीका

अपने कोड को आने वाले समय में सुरक्षित बनाने के लिए, नए प्रॉमिस पर आधारित एपीआई का इस्तेमाल करें. साथ ही, ऐसे ब्राउज़र के साथ काम करने की सुविधा चालू करें जिन पर adpter.js से काम न किया जा सके.

5. डेटा चैनल का इस्तेमाल करके डेटा का लेन-देन करना

इस चरण का पूरा वर्शन step-03 फ़ोल्डर में मौजूद है.

अपना एचटीएमएल अपडेट करें

इस चरण के लिए, एक ही पेज पर दो textarea एलिमेंट के बीच टेक्स्ट भेजने के लिए, WebRTC डेटा चैनल का इस्तेमाल किया जाता है. यह बहुत #काम नहीं करता, लेकिन यह दिखाता है कि WebRTC की मदद से, डेटा शेयर करने के साथ-साथ वीडियो स्ट्रीम कैसे किया जा सकता है.

index.html, से video और button एलिमेंट हटाएं और उन्हें नीचे दिए गए एचटीएमएल से बदलें:

<textarea id="dataChannelSend" disabled
    placeholder="Press Start, enter some text, then press Send."></textarea>
<textarea id="dataChannelReceive" disabled></textarea>

<div id="buttons">
  <button id="startButton">Start</button>
  <button id="sendButton">Send</button>
  <button id="closeButton">Stop</button>
</div>

एक टेक्स्ट के लिए textarea है, जबकि दूसरे टेक्स्ट को 'मिलते-जुलते ऐप्लिकेशन' के बीच स्ट्रीम किए गए टेक्स्ट के तौर पर दिखाता है.

आपकी index.html फ़ाइल अब कुछ ऐसी दिखेगी:

<!DOCTYPE html>
<html>

<head>

  <title>Real-time communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Real-time communication with WebRTC</h1>

  <textarea id="dataChannelSend" disabled
    placeholder="Press Start, enter some text, then press Send."></textarea>
  <textarea id="dataChannelReceive" disabled></textarea>

  <div id="buttons">
    <button id="startButton">Start</button>
    <button id="sendButton">Send</button>
    <button id="closeButton">Stop</button>
  </div>

  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>

</body>

</html>

अपना JavaScript अपडेट करना

  1. main.js को step-03/js/main.js के कॉन्टेंट से बदलें.
  1. अपने ऐप्लिकेशन के उपयोगकर्ताओं के बीच डेटा स्ट्रीम करने की कोशिश करें:
  2. index.html खोलें.
  3. मिलते-जुलते ऐप्लिकेशन का कनेक्शन सेट अप करने के लिए, शुरू करें पर क्लिक करें.
  4. बाईं ओर textarea में टेक्स्ट डालें.
  5. WebRTC डेटा चैनल का इस्तेमाल करके टेक्स्ट ट्रांसफ़र करने के लिए, भेजें पर क्लिक करें.

यह कैसे काम करता है

यह कोड मैसेज के बीच अदला-बदली करने के लिए RTCPeerConnection और RTCDataChannel का इस्तेमाल करता है.

इस चरण का ज़्यादातर कोड वैसा ही है जैसा RTCPeerConnection उदाहरण के लिए है. sendData() और createConnection() फ़ंक्शन में ज़्यादातर नया कोड है:

function createConnection() {
  dataChannelSend.placeholder = '';
  var servers = null;
  pcConstraint = null;
  dataConstraint = null;
  trace('Using SCTP based data channels');
  // For SCTP, reliable and ordered delivery is true by default.
  // Add localConnection to global scope to make it visible
  // from the browser console.
  window.localConnection = localConnection =
      new RTCPeerConnection(servers, pcConstraint);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel',
      dataConstraint);
  trace('Created send data channel');

  localConnection.onicecandidate = iceCallback1;
  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;

  // Add remoteConnection to global scope to make it visible
  // from the browser console.
  window.remoteConnection = remoteConnection =
      new RTCPeerConnection(servers, pcConstraint);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = iceCallback2;
  remoteConnection.ondatachannel = receiveChannelCallback;

  localConnection.createOffer().then(
    gotDescription1,
    onCreateSessionDescriptionError
  );
  startButton.disabled = true;
  closeButton.disabled = false;
}

function sendData() {
  var data = dataChannelSend.value;
  sendChannel.send(data);
  trace('Sent Data: ' + data);
}

RTCDataChannel का सिंटैक्स, send() मैथड और message इवेंट के साथ WebSocket की तरह होता है.

dataConstraint के इस्तेमाल पर ध्यान दें. डेटा चैनलों को अलग-अलग तरह के डेटा शेयर करने के लिए कॉन्फ़िगर किया जा सकता है, जैसे कि भरोसेमंद डिलीवरी को प्राथमिकता पर सेट करना.

स्कोर बोनस पॉइंट

  1. SCTP के साथ, WebRTC डेटा चैनल का इस्तेमाल करने वाला प्रोटोकॉल, भरोसेमंद और ऑर्डर की गई डेटा डिलीवरी डिफ़ॉल्ट रूप से चालू होती है. RTCDataChannel को कब डेटा की भरोसेमंद डिलीवरी देनी चाहिए और कब परफ़ॉर्मेंस ज़्यादा अहम हो सकती है, भले ही उसका कुछ डेटा क्यों न खो गया हो?
  2. पेज के लेआउट को बेहतर बनाने और dataChannelReceive textarea में प्लेसहोल्डर एट्रिब्यूट जोड़ने के लिए, सीएसएस का इस्तेमाल करें.
  3. मोबाइल डिवाइस पर पेज की जांच करें.

ज़्यादा जानें

6. मैसेज के एक्सचेंज के लिए सिग्नलिंग सेवा सेट अप करना

आपने एक ही पेज पर मिलते-जुलते ऐप्लिकेशन के बीच डेटा का लेन-देन करने का तरीका जाना, लेकिन अलग-अलग मशीनों के बीच ऐसा कैसे करते हैं? सबसे पहले, आपको मेटाडेटा मैसेज के लेन-देन के लिए एक सिग्नलिंग चैनल सेट अप करना होगा.

इस चरण का पूरा वर्शन step-04 फ़ोल्डर में मौजूद है.

ऐप्लिकेशन के बारे में जानकारी

WebRTC की सुविधा क्लाइंट-साइड JavaScript एपीआई का इस्तेमाल करती है. हालांकि, असल में इस्तेमाल करने के लिए आपको सिग्नलिंग (मैसेज) सर्वर के साथ-साथ STUN और टर्न सर्वर का भी इस्तेमाल करना पड़ता है. इस बारे में ज़्यादा जानकारी के लिए यहां जाएं.

इस कदम में, मैसेज सेवा के लिए Socket.IO Node.js मॉड्यूल और JavaScript लाइब्रेरी का इस्तेमाल करके एक आसान Node.js सिग्नल सर्वर बनाया जाता है.

इस उदाहरण में, सर्वर (Node.js ऐप्लिकेशन) index.js में लागू किया गया है और इस पर चलने वाला क्लाइंट (वेब ऐप्लिकेशन) index.html में लागू किया गया है.

इस चरण के Node.js ऐप्लिकेशन में दो टास्क हैं.

सबसे पहले, यह मैसेज रिले के तौर पर काम करता है:

socket.on('message', function (message) {
  log('Got message: ', message);
  socket.broadcast.emit('message', message);
});

इसके बाद, यह WebRTC वीडियो चैट रूम को मैनेज करता है:

if (numClients === 0) {
  socket.join(room);
  socket.emit('created', room, socket.id);
} else if (numClients === 1) {
  socket.join(room);
  socket.emit('joined', room, socket.id);
  io.sockets.in(room).emit('ready');
} else { // max two clients
  socket.emit('full', room);
}

आपका आसान WebRTC ऐप्लिकेशन ज़्यादा से ज़्यादा दो मिलते-जुलते ऐप्लिकेशन को चैट रूम शेयर करने की अनुमति देता है.

एचटीएमएल और JavaScript

  1. index.html को अपडेट करें, ताकि यह कुछ ऐसा दिखे:
<!DOCTYPE html>
<html>

<head>

  <title>Real-time communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Real-time communication with WebRTC</h1>

  <script src="/socket.io/socket.io.js"></script>
  <script src="js/main.js"></script>
  
</body>

</html>

इस चरण में आपको पेज पर कुछ भी नहीं दिखेगा. सभी लॉग इन ब्राउज़र कंसोल पर किए जाते हैं. Chrome में कंसोल देखने के लिए, Control+Shift+J (या Mac पर Command+Option+J) दबाएं.

  1. js/main.js को इनमें से बदलें:
'use strict';

var isInitiator;

window.room = prompt("Enter room name:");

var socket = io.connect();

if (room !== "") {
  console.log('Message from client: Asking to join room ' + room);
  socket.emit('create or join', room);
}

socket.on('created', function(room, clientId) {
  isInitiator = true;
});

socket.on('full', function(room) {
  console.log('Message from client: Room ' + room + ' is full :^(');
});

socket.on('ipaddr', function(ipaddr) {
  console.log('Message from client: Server IP address is ' + ipaddr);
});

socket.on('joined', function(room, clientId) {
  isInitiator = false;
});

socket.on('log', function(array) {
  console.log.apply(console, array);
});

Node.js पर चलाने के लिए Socket.IO फ़ाइल सेट अप करें

एचटीएमएल फ़ाइल में, आपने देखा होगा कि आप Socket.IO फ़ाइल का इस्तेमाल कर रहे हैं:

<script src="/socket.io/socket.io.js"></script>
  1. अपनी work डायरेक्ट्री के सबसे ऊपर के लेवल पर, नीचे दी गई सामग्री के साथ package.json नाम की एक फ़ाइल बनाएं:
{
  "name": "webrtc-codelab",
  "version": "0.0.1",
  "description": "WebRTC codelab",
  "dependencies": {
    "node-static": "^0.7.10",
    "socket.io": "^1.2.0"
  }
}

यह ऐप्लिकेशन मेनिफ़ेस्ट है, जो नोड पैकेज मैनेजर (npm) को बताता है कि कौनसा प्रोजेक्ट है

इंस्टॉल करने की निर्भरता.

  1. डिपेंडेंसी जैसे कि /socket.io/socket.io.js इंस्टॉल करने के लिए, अपनी work डायरेक्ट्री में कमांड लाइन टर्मिनल से यह कोड चलाएं:
npm install

आपको इंस्टॉल करने का एक लॉग दिखेगा, जो कुछ इस तरह खत्म होता है:

3ab06b7bcc7664b9.png

जैसा कि आप देख सकते हैं, npm ने package.json में बताई गई डिपेंडेंसी इंस्टॉल कर दी हैं.

  1. अपनी work डायरेक्ट्री (न कि js डायरेक्ट्री) के सबसे ऊपर के लेवल पर एक नई फ़ाइल index.js बनाएं और यह कोड जोड़ें:
'use strict';

var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');

var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
  fileServer.serve(req, res);
}).listen(8080);

var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {

  // Convenience function to log server messages on the client
  function log() {
    var array = ['Message from server:'];
    array.push.apply(array, arguments);
    socket.emit('log', array);
  }

  socket.on('message', function(message) {
    log('Client said: ', message);
    // For a real app, would be room-only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', function(room) {
    log('Received request to create or join room ' + room);

    var clientsInRoom = io.sockets.adapter.rooms[room];
    var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;

    log('Room ' + room + ' now has ' + numClients + ' client(s)');

    if (numClients === 0) {
      socket.join(room);
      log('Client ID ' + socket.id + ' created room ' + room);
      socket.emit('created', room, socket.id);

    } else if (numClients === 1) {
      log('Client ID ' + socket.id + ' joined room ' + room);
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room, socket.id);
      io.sockets.in(room).emit('ready');
    } else { // max two clients
      socket.emit('full', room);
    }
  });

  socket.on('ipaddr', function() {
    var ifaces = os.networkInterfaces();
    for (var dev in ifaces) {
      ifaces[dev].forEach(function(details) {
        if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
          socket.emit('ipaddr', details.address);
        }
      });
    }
  });

});
  1. कमांड-लाइन टर्मिनल से, work डायरेक्ट्री में यह निर्देश चलाएं:
node index.js
  1. अपने ब्राउज़र में, http://localhost:8080 पर जाएं.

हर बार जब आप इस यूआरएल पर नेविगेट करते हैं, तो आपको चैट रूम का नाम डालने के लिए कहा जाता है.

उसी चैट रूम में शामिल होने के लिए, हर बार एक ही चैट रूम का नाम डालें, जैसे कि foo.

  1. नया टैब खोलें और http://localhost:8080 पर फिर से जाएं. इसके बाद, उसी चैट रूम का नाम फिर से डालें.
  2. एक और नया टैब खोलें, http://localhost:8080 पर फिर से जाएं और उसी चैट रूम का नाम फिर से डालें.
  3. हर टैब में कंसोल देखें.

आपको JavaScript से लॉग इन करते हुए देखना चाहिए.

स्कोर बोनस पॉइंट

  • मैसेज भेजने के कौनसे दूसरे तरीके हो सकते हैं? आपको शुद्ध WebSocket का इस्तेमाल करने में क्या समस्याएं आ सकती हैं?
  • इस ऐप्लिकेशन को स्केल करने में क्या समस्याएं हो सकती हैं? क्या आप एक साथ लाखों या लाखों कमरों को आज़माने के लिए कोई तरीका बना सकते हैं?
  • यह ऐप्लिकेशन कमरे का नाम पाने के लिए, JavaScript प्रॉम्प्ट का इस्तेमाल करता है. यूआरएल से चैट रूम का नाम पता करने का तरीका जानें. उदाहरण के लिए, http://localhost:8080/foo चैट रूम का नाम foo बताएगा.

ज़्यादा जानें

7. मिलते-जुलते ऐप्लिकेशन के कनेक्शन और सिग्नलों को जोड़ें

इस चरण का पूरा वर्शन step-05 फ़ोल्डर में मौजूद है.

एचटीएमएल और JavaScript को बदलना

  1. index.html के कॉन्टेंट को इनमें से बदलें:
<!DOCTYPE html>
<html>

<head>

  <title>Real-time communication with WebRTC</title>

  <link rel="stylesheet" href="/css/main.css" />

</head>

<body>

  <h1>Real-time communication with WebRTC</h1>

  <div id="videos">
    <video id="localVideo" autoplay muted></video>
    <video id="remoteVideo" autoplay></video>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>
  
</body>

</html>
  1. js/main.js को step-05/js/main.js के कॉन्टेंट से बदलें.

Node.js सर्वर चलाएं

अगर आप work डायरेक्ट्री से इस कोडलैब को फ़ॉलो नहीं कर रहे हैं, तो आपको step-05 फ़ोल्डर या अपने मौजूदा काम करने वाले फ़ोल्डर के लिए, डिपेंडेंसी इंस्टॉल करनी पड़ सकती है.

  1. अपनी वर्किंग डायरेक्ट्री से यह निर्देश चलाएं:
npm install
  1. इंस्टॉल होने के बाद, अगर आपका Node.js सर्वर नहीं चल रहा है, तो इसे work डायरेक्ट्री में यह निर्देश देकर शुरू करें:
node index.js

पक्का करें कि आप पिछले वर्शन के index.js के वर्शन का इस्तेमाल कर रहे हैं जो Socket.IO को लागू करता है. नोड और Socket IO पर ज़्यादा जानकारी के लिए, मैसेज के लेन-देन के लिए सिग्नलिंग सेवा सेट करें को देखें.

  1. अपने ब्राउज़र में, http://localhost:8080 पर जाएं.
  2. नया टैब खोलें और http://localhost:8080 पर फिर से नेविगेट करें.

एक video एलिमेंट, getUserMedia() से मिली स्थानीय स्ट्रीम दिखाता है. वहीं, दूसरा एलिमेंट RTCPeerconnection के ज़रिए स्ट्रीम किए जाने वाले रिमोट वीडियो को दिखाता है.

  1. ब्राउज़र कंसोल में लॉग इन करने की प्रोसेस देखें.

स्कोर ***** पॉइंट

  • इस ऐप्लिकेशन में सिर्फ़ एक वीडियो चैट की सुविधा है. आप एक से ज़्यादा व्यक्तियों को एक ही वीडियो चैट रूम शेयर करने के लिए डिज़ाइन कैसे बदल सकते हैं?
  • उदाहरण में, कमरे के नाम को foo हार्ड कोड किया गया है. कमरे के दूसरे नामों को चालू करने का सबसे अच्छा तरीका क्या होगा?
  • उपयोगकर्ता, चैट रूम का नाम कैसे शेयर करेंगे? चैट रूम के नाम शेयर करने के लिए कोई दूसरा विकल्प बनाने की कोशिश करें.
  • आप ऐप्लिकेशन को कैसे बदल सकते हैं?

सलाह

  • chrome://webrtc-internals पर WebRTC के आंकड़े देखें और डेटा डीबग करें.
  • अपने आस-पास के माहौल की जांच करने के लिए, WebRTC की समस्या हल करने वाला टूल इस्तेमाल करें. साथ ही, अपने कैमरे और माइक्रोफ़ोन की जांच करें.
  • अगर आपको कैश मेमोरी में परेशानियां हो रही हैं, तो नीचे दिए गए तरीके आज़माएं:
  1. Control दबाएं और इस पेज को फिर से लोड करें पर क्लिक करें.
  2. ब्राउज़र को रीस्टार्ट करें.
  3. कमांड लाइन से npm cache clean चलाएं.

8. फ़ोटो लें और उसे डेटा चैनल से शेयर करें

इस चरण का पूरा वर्शन step-06 फ़ोल्डर में मौजूद है.

यह कैसे काम करता है

पहले आप RTCDataChannel की मदद से मैसेज के लेन-देन का तरीका सीख चुके थे. इस चरण से सभी फ़ाइलों को शेयर किया जा सकता है. इस उदाहरण में, फ़ोटो को getUserMedia() की मदद से कैप्चर किया गया है.

इस चरण के मुख्य हिस्से ये हैं:

  1. डेटा चैनल बनाना.

इस चरण में, मिलते-जुलते ऐप्लिकेशन के कनेक्शन में कोई मीडिया स्ट्रीम नहीं जोड़ें.

  1. getUserMedia() की मदद से अपना वेबकैम वीडियो स्ट्रीम कैप्चर करें:
var video = document.getElementById('video');

function grabWebCamVideo() {
  console.log('Getting user media (video) ...');
  navigator.mediaDevices.getUserMedia({
    video: true
  })
  .then(gotStream)
  .catch(function(e) {
    alert('getUserMedia() error: ' + e.name);
  });
}
  1. वीडियो स्ट्रीम से स्नैपशॉट (वीडियो फ़्रेम) पाने और उसे canvas एलिमेंट में दिखाने के लिए स्नैप करें पर क्लिक करें:
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');

function snapPhoto() {
  photoContext.drawImage(video, 0, 0, photo.width, photo.height);
  show(photo, sendBtn);
}
  1. इमेज को बाइट में बदलने और उन्हें डेटा चैनल से भेजने के लिए, भेजें पर क्लिक करें:
function sendPhoto() {
  // Split the data-channel message in chunks of this byte length.
  var CHUNK_LEN = 64000;
  var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
    len = img.data.byteLength,
    n = len / CHUNK_LEN | 0;

  console.log('Sending a total of ' + len + ' byte(s)');
  dataChannel.send(len);

  // Split the photo and send in chunks of approximately 64KB.
  for (var i = 0; i < n; i++) {
    var start = i * CHUNK_LEN,
      end = (i + 1) * CHUNK_LEN;
    console.log(start + ' - ' + (end - 1));
    dataChannel.send(img.data.subarray(start, end));
  }

  // Send the reminder, if applicable.
  if (len % CHUNK_LEN) {
    console.log('last ' + len % CHUNK_LEN + ' byte(s)');
    dataChannel.send(img.data.subarray(n * CHUNK_LEN));
  }
}

मैसेज पाने वाला साइड, डेटा चैनल मैसेज की बाइट को इमेज में बदलता है और इमेज को उपयोगकर्ता को दिखाता है:

function receiveDataChromeFactory() {
  var buf, count;

  return function onmessage(event) {
    if (typeof event.data === 'string') {
      buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
      count = 0;
      console.log('Expecting a total of ' + buf.byteLength + ' bytes');
      return;
    }

    var data = new Uint8ClampedArray(event.data);
    buf.set(data, count);

    count += data.byteLength;
    console.log('count: ' + count);

    if (count === buf.byteLength) {
      // we're done: all data chunks have been received
      console.log('Done. Rendering photo.');
      renderPhoto(buf);
    }
  };
}

function renderPhoto(data) {
  var canvas = document.createElement('canvas');
  canvas.width = photoContextW;
  canvas.height = photoContextH;
  canvas.classList.add('incomingPhoto');
  // The trail is the element that holds the incoming images.
  trail.insertBefore(canvas, trail.firstChild);

  var context = canvas.getContext('2d');
  var img = context.createImageData(photoContextW, photoContextH);
  img.data.set(data);
  context.putImageData(img, 0, 0);
}

कोड पाएं

  1. अपने work फ़ोल्डर की सामग्री को step-06 की सामग्री से बदलें.

work में आपकी index.html फ़ाइल अब इस तरह दिखेगी**:**

<!DOCTYPE html>
<html>

<head>

  <title>Real-time communication with WebRTC</title>

  <link rel="stylesheet" href="/css/main.css" />

</head>

<body>

  <h1>Real-time communication with WebRTC</h1>

  <h2>
    <span>Room URL: </span><span id="url">...</span>
  </h2>

  <div id="videoCanvas">
    <video id="camera" autoplay></video>
    <canvas id="photo"></canvas>
  </div>

  <div id="buttons">
    <button id="snap">Snap</button><span> then </span><button id="send">Send</button>
    <span> or </span>
    <button id="snapAndSend">Snap &amp; Send</button>
  </div>

  <div id="incoming">
    <h2>Incoming photos</h2>
    <div id="trail"></div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>

</body>

</html>
  1. अगर आप work डायरेक्ट्री से इस कोडलैब को फ़ॉलो नहीं कर रहे हैं, तो आपको step-06 फ़ोल्डर या अपने मौजूदा काम करने वाले फ़ोल्डर के लिए, डिपेंडेंसी इंस्टॉल करनी पड़ सकती है. बस अपनी काम करने वाली निर्देशिका से निम्न आदेश चलाएं:
npm install
  1. इंस्टॉल होने के बाद, अगर आपका Node.js सर्वर नहीं चल रहा है, तो इसे अपनी work डायरेक्ट्री से नीचे दिए गए निर्देश पर चलाकर शुरू करें:
node index.js
    Make sure that you're using the version of `index.js` that implements Socket.IO and 

अगर आप बदलाव करते हैं, तो अपना Node.js सर्वर रीस्टार्ट करना न भूलें.

Node और Socket.IO के बारे में ज़्यादा जानकारी के लिए, 'सिग्लिंग सेट अप करें' सेक्शन को देखें

मैसेज का लेन-देन करने के लिए.

  1. अगर ज़रूरी हो, तो ऐप्लिकेशन को अपना वेबकैम इस्तेमाल करने की अनुमति देने के लिए, अनुमति दें पर क्लिक करें.

यह ऐप्लिकेशन, रैंडम रूम आईडी बनाता है और आईडी को यूआरएल में जोड़ता है.

  1. पता बार से यूआरएल को एक नए ब्राउज़र टैब या विंडो में खोलें.
  2. Snap और &भेजें; पर क्लिक करें. इसके बाद, पेज के सबसे नीचे मौजूद दूसरे टैब में आने वाली फ़ोटो पर जाएं.

यह ऐप्लिकेशन, टैब के बीच फ़ोटो ट्रांसफ़र करता है.

आपको कुछ ऐसा दिखेगा:

911b40f36ba6ba8.png

स्कोर बोनस पॉइंट

किसी फ़ाइल टाइप को शेयर करने के लिए कोड कैसे बदला जा सकता है?

ज़्यादा जानें

9. बधाई हो

आपने रीयल-टाइम वीडियो स्ट्रीमिंग और डेटा एक्सचेंज के लिए एक ऐप्लिकेशन बनाया है!

ज़्यादा जानें