Bu codelab hakkında
1. Başlamadan önce
Bu codelab'de, WebRTC'yle video çekmek, web kameranızla anlık görüntüler almak ve bunları eşler arası paylaşım için nasıl oluşturacağınızı öğrenebilirsiniz. Ayrıca, temel WebRTC API'lerini nasıl kullanacağınızı ve Node.js ile bir mesajlaşma sunucusunu nasıl ayarlayacağınızı öğreneceksiniz.
Ön koşullar
- HTML, CSS ve JavaScript ile ilgili temel bilgiler
Derlemeniz istenen nedir?
- Web kameranızdan video alın.
RTCPeerConnection
ile video yayını yap.- Verileri
RTCDataChannel
ile kullanın. - Mesaj alışverişi için bir sinyal hizmeti ayarlayın.
- Eş bağlantısı ile sinyali birleştirme.
- Fotoğraf çekin ve paylaşmak için bir veri kanalı kullanın.
Gerekenler
- Chrome 47 veya sonraki sürümler
- Chrome için Web Sunucusu veya tercih ettiğiniz bir web sunucusu
- İstediğiniz bir metin düzenleyici
- Node.js
2. Örnek kodu alın
Kodu indirin
- Git'i tanıyorsanız GitHub'dan bu codelab'in kodunu klonlamak için şu komutu çalıştırın:
git clone https://github.com/googlecodelabs/webrtc-web
Alternatif olarak, kodun zip dosyasını indirmek için şu bağlantıyı tıklayın:
- Bu codelab'in her adımı ve ihtiyaç duyduğunuz tüm kaynaklar için bir klasör içeren
webrtc-web-master
adlı proje klasörünün paketini açmak için indirilen zip dosyasını açın.
Tüm kodunuzu work
adlı dizinde yaparsınız.
step-nn
klasörleri, bu codelab'in her adımı için tamamlanmış bir sürüm içerir. Referans için yanınızdalar.
Web sunucusunu yükleyip doğrulayın
Kendi web sunucunuzu kullanabilirsiniz ancak bu codelab, Chrome için Web Sunucusu ile uyumlu çalışacak şekilde tasarlanmıştır.
- Chrome için Web Sunucusu'nu bilmiyorsanız Chrome Web Mağazası'ndan yüklemek için şu bağlantıyı tıklayın:
- Chrome için Web Sunucusu'nu yükleyen ve Google uygulamalarınızı otomatik olarak yeni bir sekmede açan Chrome'a ekle'yi tıklayın.
- Web Server'ı (Web Sunucusu) tıklayın:
Yerel web sunucunuzu yapılandırmanıza olanak tanıyan bir iletişim kutusu görünür:
- Klasör Seç'i tıklayın.
- Oluşturduğunuz
work
klasörünü seçin.
Web Sunucusu URL'leri altında, devam eden çalışmalarınızı görüntülemek için kullanabileceğiniz URL'yi görürsünüz.
Chrome.
- Seçenekler (yeniden başlatma gerekebilir) altında, index.html'yi otomatik olarak göster onay kutusunu seçin.
- Sunucuyu durdurup yeniden başlatmak için Web Server: Başlatıldı seçeneğini iki kez etkinleştirin.
- Çalışmanızı web tarayıcınızda görmek için Web Sunucusu URL'leri altında URL'yi tıklayın.
work/index.html
sayfasına benzeyen bir sayfa görürsünüz:
Elbette bu uygulama henüz ilgi çekici bir şey yapmıyor. Web sunucunuzun düzgün çalışmasını sağlamak için yalnızca minimum düzeyde bir iskelettir. Sonraki adımlarda işlevsellik ve düzen özelliklerini eklersiniz.
3. Web kameranızla video yayını yapın
Bu adımın tam sürümü step-01
klasöründedir.
Kısa çizgi ekleyin
Bir video
ve script
öğesi eklemek için bu kodu kopyalayın ve work
dizininizdeki index.html
dosyasına yapıştırın:
<!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>
Bir tutam JavaScript ekleyin
Bu kodu kopyalayıp js
klasörünüzdeki main.js
dosyasına yapıştırın:
'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);
Dene
index.html
dosyasını tarayıcınızda açın. Böyle bir şey göreceksiniz, ancak web kameranızın görünümünden yararlanırsınız:
İşleyiş şekli
getUserMedia()
çağrısından sonra tarayıcı, geçerli kaynak için kamera erişimi için yapılan ilk istekse kameranıza erişim izni ister.
Başarılı olursa MediaStream
döndürülür, media
öğesi bu srcObject
özelliği aracılığıyla kullanılabilir:
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
.then(gotLocalMediaStream).catch(handleLocalMediaStreamError);
}
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
constraints
bağımsız değişkeni, alacağınız medyayı belirtmenizi sağlar. Bu örnekte, ses varsayılan olarak devre dışı bırakılmış olduğundan medya yalnızca videodur:
const mediaStreamConstraints = {
video: true,
};
Video çözünürlüğü gibi ek gereksinimler için kısıtlamaları kullanabilirsiniz:
const hdConstraints = {
video: {
width: {
min: 1280
},
height: {
min: 720
}
}
}
MediaTrackConstraints
spesifikasyonu tüm potansiyel sınırlama türlerini listeler, ancak tüm seçenekler tüm tarayıcılar tarafından desteklenmez. İstenen çözünürlük şu anda seçili olan kamera tarafından desteklenmiyorsa getUserMedia()
, OverconstrainedError
ile reddedilir ve kameranıza erişim izni vermeniz istenir.
getUserMedia()
başarılı olursa web kamerasındaki video akışı, video öğesinin kaynağı olarak ayarlanır:
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
Bonus puan kazanın
getUserMedia()
nesnesine iletilenlocalStream
nesnesi genel kapsamda olduğundan tarayıcı konsolundan inceleyebilirsiniz. Konsolu açın,stream,
yazın veEnter
(Mac'teReturn
) tuşuna basın. Konsolu Chrome'da görüntülemek içinControl+Shift+J
(veya Mac'teCommand+Option+J
) tuşuna basın.localStream.getVideoTracks()
ne döndürür?localStream.getVideoTracks()[0].stop()
Hizmetleri İçin Arayın.- Kısıtlamalar nesnesine bakın. Bunu
{audio: true, video: true}
olarak değiştirdiğinizde ne olur? - Video öğesi hangi boyutta? Görüntü boyutunun yerine videonun doğal boyutunu JavaScript'ten nasıl alabilirsiniz? Kontrol etmek için Google Chrome Geliştirici Araçları'nı kullanın.
- Video öğesine CSS filtreleri ekleyin. Örneğin:
video {
filter: blur(4px) invert(1) opacity(0.5);
}
- Aşağıdaki gibi SVG filtreleri ekleyin:
video {
filter: hue-rotate(180deg) saturate(200%);
}
İpuçları
video
öğesindekiautoplay
özelliğini unutmayın. Bu olmadan, yalnızca tek bir kare görürsünüz.getUserMedia()
kısıtlamaları için daha pek çok seçenek vardır. Daha fazla örnek için WebRTC örneklerinde Sınırlamalar & istatistikleri ve Daha fazla sınırlama & istatistikleri bölümüne bakın.
En iyi uygulama
Video öğenizin, kapsayıcısından taşmadığından emin olun. Bu codelab, video için tercih edilen boyut ve maksimum boyut ayarlamak amacıyla width
ve max-width
değerlerini ekledi. Tarayıcınız yüksekliği otomatik olarak hesaplar.
video {
max-width: 100%;
width: 320px;
}
4. RTCPeerConnection API ile video akışı yapma
Bu adımın tam sürümü step-2
klasöründedir.
Video öğeleri ve kontrol düğmeleri ekleme
index.html
dosyasında, tek video
öğesini iki video
ve üç button
öğesiyle değiştirin:
<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>
Bir video öğesi getUserMedia()
tarafından sağlanan akışı, diğeri ise RTCPeerconnection
üzerinden yayınlanan videoyu gösterir. (Gerçek dünyadaki bir uygulamada, bir video
öğesi yerel akışı, diğeri ise uzak akışı görüntüler.)
adaptör.js dolgusu ekleme
Bu komut dosyası öğesini kopyalayıp main.js
için komut dosyası öğesinin üst kısmına yapıştırın:
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
index.html
dosyanız şu şekilde görünmelidir:
<!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
kodunu yükleyin
main.js
öğesini step-02
klasöründeki sürümle değiştirin.
Telefon et
index.html
dosyasını açın.- Web kameranızdan video almak için Başlat'ı tıklayın.
- Eş bağlantısını yapmak için Ara'yı tıklayın
Her iki video
öğesinde de web kameranızdan aynı videoyu görmeniz gerekir.
- WebRTC günlük kaydını görmek için tarayıcı konsolunu görüntüleyin.
İşleyiş şekli
Bu adım çok yararlı oluyor.
WebRTC, eş zamanlı olarak bilinen WebRTC istemcileri arasında video akışı oluşturmak için RTCPeerConnection
API'yi kullanır.
Bu örnekte, iki RTCPeerConnection
nesnesi aynı sayfada yer almaktadır: pc1
ve pc2
.
WebRTC eşleri arasında arama kurulumu üç görev içerir:
- Görüşmenin her ucu için bir
RTCPeerConnection
oluşturun ve her iki ucun dagetUserMedia()
üzerinden yerel akışını ekleyin. - Ağ bilgilerini alabilir ve paylaşabilirsiniz.
Olası bağlantı uç noktaları, ICE adayları olarak bilinir.
- Yerel ve uzaktan açıklamalar alın ve paylaşın.
Yerel medya ile ilgili meta veriler Oturum Açıklama Protokolü (SDP) biçimindedir.
Ayşe ve Ali'nin görüntülü sohbet oluşturmak için RTCPeerConnection
uygulamasını kullanmak istediğini düşünün.
İlk olarak, Ayşe ve Ali, ağ bilgilerini değiş tokuş eder. Aday bulma ifadesi, ICE çerçevesini kullanarak ağ arayüzlerini ve bağlantı noktalarını bulma işlemini belirtir.
- Ayşe,
onicecandidate (addEventListener('icecandidate'))
işleyicisine sahipRTCPeerConnection
nesnesi oluşturur.
Bu, main.js
kaynağından gelen aşağıdaki koda karşılık gelir:
let localPeerConnection;
localPeerConnection = new RTCPeerConnection(servers);
localPeerConnection.addEventListener('icecandidate', handleConnection);
localPeerConnection.addEventListener(
'iceconnectionstatechange', handleConnectionChange);
- Ayşe,
getUserMedia()
öğesini çağırır ve kendisine iletilen akışı ekler:
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.');
- Ağ adayları kullanılabilir olduğunda ilk adımdaki
onicecandidate
işleyici çağrılır. - Ayşe, serileştirilmiş aday verilerini İbrahim'e gönderir.
Gerçek bir uygulamada, sinyal olarak bilinen bu işlem bir mesajlaşma hizmeti üzerinden gerçekleşir. Bunu nasıl yapacağınızı sonraki bir adımda öğreneceksiniz. Elbette bu adımda, iki RTCPeerConnection
nesnesi aynı sayfada bulunur ve harici mesajlaşmaya gerek kalmadan doğrudan iletişim kurabilir.
- Barış, Ayşe'den bir aday mesajı aldığında adayı uzaktaki benzerler açıklamasına eklemek için
addIceCandidate()
numarasını arar:
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 eşlerinin ayrıca, çözünürlük ve codec özellikleri gibi yerel ve uzak ses ve video medya bilgilerini keşfetmesi ve alıp vermesi gerekir. Exchange medya yapılandırma bilgilerinin sinyali, teklif ve yanıt olarak bilinen meta veri blob'larının SDP biçimi kullanılarak aktarılmasıyla devam eder.
- Ayşe,
RTCPeerConnection
createOffer()
yöntemini çalıştırır.
Alınan vaat RTCSessionDescription
, Alice'in yerel oturum açıklamasını sunuyor:
trace('localPeerConnection createOffer start.');
localPeerConnection.createOffer(offerOptions)
.then(createdOffer).catch(setSessionDescriptionError);
- İşlem başarılı olursa Ayşe, yerel açıklamayı
setLocalDescription()
kullanarak ayarlar ve daha sonra bu oturum açıklamasını sinyal kanalları üzerinden Ali'ye gönderir. - İbrahim,
setRemoteDescription()
adlı çocuğun uzaktan açıklaması olarak gönderdiği açıklamayı Ayşe'ye ayarlar. - İbrahim,
RTCPeerConnection
createAnswer()
yöntemini çalıştırır ve bu yöntemi Ayşe'den aldığı uzaktan açıklama yöntemini iletir. Böylece Ali'yle uyumlu bir yerel oturum oluşturulur. createAnswer()
taahhüdü söz konusuRTCSessionDescription
.- Ayşe, Ali'nin oturum açıklamasını aldığında
setRemoteDescription()
ile uzaktan açıklama olarak belirler.
// 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);
}
Bonus puan kazanın
- chrome://webrtc-internals sayfasına gidin.
Bu sayfada WebRTC istatistikleri ve hata ayıklama verileri yer alır. (Chrome URL'lerinin tam listesini chrome://about adresinde bulabilirsiniz.)
- Sayfaya CSS ile stil ekleme:
- Videoları yan yana koyun.
- Düğmeleri daha büyük metinle aynı genişlikte yapın.
- Düzenin mobil cihazlarda çalıştığından emin olun.
- Chrome Geliştirici Araçları konsolunda
localStream
,localPeerConnection
veremotePeerConnection
eklentilerine bakın. - Konsoldan
localPeerConnectionpc1.localDescription
ürününe bakın.
SDP biçimi nasıl görünür?
İpuçları
- adaptör.js dolgusu hakkında daha fazla bilgi için adapter.js GitHub veri havuzuna bakın.
- AppRTC'ye ve WebRTC'nin yaptığı aramalar için WebRTC projesinin uygulama koduna göz atın. Arama süresi 500 ms'den az.
En iyi uygulama
Kodunuzu geleceğe hazırlamak için yeni Promise tabanlı API'leri kullanın ve adapter.js ile desteklemeyen tarayıcılarla uyumluluğu etkinleştirin.
5. Veri alışverişi için veri kanalını kullanma
Bu adımın tam sürümü step-03
klasöründedir.
HTML'nizi güncelleyin
Bu adımda, aynı sayfadaki iki textarea
öğesi arasında kısa mesaj göndermek için WebRTC veri kanallarını kullanırsınız. Bu çok yararlı bir yöntem olmasa da WebRTC'nin veri paylaşmak ve video akışı yapmak için nasıl kullanılabileceğini gösterir.
video
ve button
öğelerini index.html,
öğesinden kaldırın ve aşağıdaki HTML ile değiştirin:
<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
metin girmek içindir, diğeri ise metni benzerler arasında akış şeklinde göstermek içindir.
index.html
dosyanız şu şekilde görünmelidir:
<!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'inizi güncelleyin
main.js
içeriğinistep-03/js/main.js
içeriğiyle değiştirin.
- Benzerler arasında veri akışı yapmayı deneyin:
index.html
'yi açın.- Eş bağlantısını ayarlamak için Başlat'ı tıklayın.
- Soldaki
textarea
alana bir metin girin. - WebRTC veri kanalı kullanarak metin aktarmak için Gönder'i tıklayın.
İşleyiş şekli
Bu kod, kısa mesaj alışverişini etkinleştirmek için RTCPeerConnection
ve RTCDataChannel
işaretlemelerini kullanır.
Bu adımdaki kodun çoğu RTCPeerConnection
örneğiyle aynıdır. sendData()
ve createConnection()
işlevleri yeni kodun büyük bölümüne sahiptir:
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
söz dizimi, send()
yöntemi ve message
etkinliğiyle kasıtlı olarak WebSocket'e benzer.
dataConstraint
kullanımına dikkat edin. Veri kanalları, performans üzerinde güvenilir yayına öncelik verme gibi farklı veri paylaşımı türlerini etkinleştirecek şekilde yapılandırılabilir.
Bonus puan kazanın
- SCTP ile WebRTC veri kanalları tarafından kullanılan protokol, güvenilir ve sıralı veri dağıtımı varsayılan olarak açıktır.
RTCDataChannel
veri kaybı yaşansa bile ne zaman güvenilir bir veri akışı sağlamak ve performansın daha önemli olabileceği durumlar olabilir. - Sayfa düzenini iyileştirmek ve
dataChannelReceive
textarea
öğesine bir yer tutucu özelliği eklemek için CSS kullanın. - Sayfayı bir mobil cihazda test edin.
Daha fazla bilgi
6. Mesaj alışverişinde sinyal hizmeti ayarlama
Aynı sayfadaki benzerler arasında nasıl veri alışverişi yapılacağını öğrendiniz. Peki bunu farklı makineler arasında nasıl yaparsınız? Öncelikle, meta veri mesajlarını takas etmek için bir sinyal kanalı oluşturmanız gerekir.
Bu adımın tam sürümü step-04
klasöründedir.
Uygulama hakkında
WebRTC, istemci tarafı JavaScript API'si kullanır ancak gerçek dünyada kullanım için hem sinyal (mesajlaşma) sunucusunun hem de STUN ve TURN sunucularının kullanılması gerekir. Daha fazla bilgiye buradan ulaşabilirsiniz.
Bu adımda, mesajlar için Socket.IO Node.js modülünü ve JavaScript kitaplığını kullanarak basit bir Node.js sinyal sunucusu oluşturursunuz.
Bu örnekte, sunucu (Node.js uygulaması) index.js
üzerinde ve istemci üzerinde çalışan istemci (web uygulaması) index.html
konumunda uygulanır.
Bu adımdaki Node.js uygulamasında iki görev vardır.
Öncelikle, mesaj geçişi işlevi görür:
socket.on('message', function (message) {
log('Got message: ', message);
socket.broadcast.emit('message', message);
});
İkincisi, WebRTC görüntülü sohbet odalarını yönetir:
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);
}
Basit WebRTC uygulamanız, en fazla iki benzer kullanıcının oda paylaşmasına izin verir.
HTML ve JavaScript
index.html
dosyasını şu şekilde görünecek şekilde güncelleyin:
<!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>
Bu adımda sayfada hiçbir şey görmezsiniz. Tüm günlük kaydı, tarayıcı konsoluna yapılır. Konsolu Chrome'da görüntülemek için Control+Shift+J
(veya Mac'te Command+Option+J
) tuşuna basın.
js/main.js
ifadesini şununla değiştirin:
'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);
});
Socket.IO dosyasını Node.js'de çalışacak şekilde ayarlama
HTML dosyasında, bir Socket.IO dosyası kullandığınızı görmüş olabilirsiniz:
<script src="/socket.io/socket.io.js"></script>
work
dizininizin en üst düzeyinde aşağıdaki içeriğe sahippackage.json
adlı bir dosya oluşturun:
{
"name": "webrtc-codelab",
"version": "0.0.1",
"description": "WebRTC codelab",
"dependencies": {
"node-static": "^0.7.10",
"socket.io": "^1.2.0"
}
}
Bu, Node Package Manager'a (npm
) hangi projenin olduğunu bildiren bir uygulama manifestidir
yardımcı oluyor.
/socket.io/socket.io.js
gibi bağımlılıkları yüklemek içinwork
dizininizdeki komut satırı terminalinden aşağıdakileri çalıştırın:
npm install
Şuna benzer bir yükleme günlüğü görürsünüz:
Gördüğünüz gibi npm
, package.json
içinde tanımlanan bağımlılıkları yükledi.
work
dizininizin en üst düzeyinde (js
dizini değil) yeni bir dosyaindex.js
oluşturun ve aşağıdaki kodu ekleyin:
'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);
}
});
}
});
});
- Komut satırı terminalinden
work
dizininde aşağıdaki komutu çalıştırın:
node index.js
- Tarayıcınızdan http://localhost:8080 adresine gidin.
Bu URL'ye her gittiğinizde bir oda adı girmeniz istenir.
Aynı odaya katılmak için her seferinde aynı oda adını girin (ör. foo
).
- Yeni bir sekme açıp http://localhost:8080 adresine tekrar gidin ve aynı oda adını tekrar girin.
- Başka bir yeni sekme açın, tekrar http://localhost:8080 adresine gidin ve aynı oda adını tekrar girin.
- Sekmelerin her birinde konsolu kontrol edin.
JavaScript'ten günlük kaydı göreceksiniz.
Bonus puan kazanın
- Hangi alternatif mesajlaşma mekanizmaları kullanılabilir? Tam WebSocket kullanırken ne tür sorunlarla karşılaşabilirsiniz?
- Bu uygulamanın ölçeklendirilmesiyle ilgili hangi sorunlar olabilir? Binlerce veya milyonlarca eş zamanlı oda isteğini test etmek için bir yöntem geliştirebilir misiniz?
- Bu uygulama, oda adını almak için bir JavaScript istemi kullanır. URL'den oda adını nasıl alacağınızı öğrenin. Örneğin, http://localhost:8080/foo oda adı olarak
foo
verir.
Daha fazla bilgi
7. Eş bağlantı ve sinyal özelliklerini birleştirme
Bu adımın tam sürümü step-05
klasöründedir.
HTML ve JavaScript'i değiştirin
index.html
içeriğini aşağıdakilerle değiştirin:
<!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>
js/main.js
içeriğinistep-05/js/main.js
içeriğiyle değiştirin.
Node.js sunucusunu çalıştırma
work
dizininizden bu codelab'i takip etmiyorsanız step-05
klasörüne veya geçerli çalışma klasörünüze ait bağımlılıkları yüklemeniz gerekebilir.
- Çalışma dizininizden aşağıdaki komutu çalıştırın:
npm install
- Yüklendikten sonra, Node.js sunucunuz çalışmıyorsa
work
dizininde aşağıdaki komutu çalıştırarak başlatın:
node index.js
Socket.IO'yu uygulayan önceki adımdaki index.js
sürümünü kullandığınızdan emin olun. Düğüm ve Yuva IO hakkında daha fazla bilgi edinmek için Mesaj alışverişi için sinyal hizmeti ayarlama bölümünü inceleyin.
- Tarayıcınızdan http://localhost:8080 adresine gidin.
- Yeni bir sekme açıp tekrar http://localhost:8080 adresine gidin.
Bir video
öğesi getUserMedia()
tarafından sağlanan yerel akışı, diğeri RTCPeerconnection
aracılığıyla yayınlanan uzaktan videoyu gösterir.
- Günlük kaydını tarayıcı konsolunda görüntüleyin.
Puan puanı puanı
- Bu uygulama yalnızca bire bir görüntülü sohbeti desteklemektedir. Aynı görüntülü sohbet odasını birden fazla kişinin paylaşabilmesi için tasarımı nasıl değiştirebilirsiniz?
- Örnekte,
foo
adlı odanın kodu sabit kodludur. Diğer oda adlarını etkinleştirmenin en iyi yolu hangisidir? - Kullanıcılar oda adını nasıl paylaşır? Oda adlarını paylaşmaya alternatif bir yöntem oluşturmaya çalışın.
- Uygulamayı nasıl değiştirebilirsiniz?
İpuçları
- chrome://webrtc-internals sayfasındaki WebRTC istatistiklerini bulabilir ve hata ayıklaması yapabilirsiniz.
- Yerel ortamınızı kontrol etmek, kamera ve mikrofonunuzu test etmek için WebRTC Troubleshooter'ı kullanın.
- Önbelleğe almayla ilgili sorun yaşıyorsanız aşağıdakileri deneyin:
Control
tuşuna basın ve Bu sayfayı yeniden yükle'yi tıklayın.- Tarayıcıyı yeniden başlatın.
- Komut satırından
npm cache clean
çalıştırın.
8. Bir fotoğraf çekin ve veri kanalı üzerinden paylaşın
Bu adımın tam sürümü step-06
klasöründedir.
İşleyiş şekli
Önceden, RTCDataChannel
kullanarak kısa mesaj gönderip almayı öğrendiniz. Bu adım tüm dosyaların paylaşılmasını sağlar. Bu örnekte, fotoğraflar getUserMedia()
ile çekilmiştir.
Bu adımın temel bölümleri şunlardır:
- Veri kanalı oluşturun.
Bu adımda eş bağlantısına herhangi bir medya akışı eklemezsiniz.
getUserMedia()
ile web kamerası video akışınızı yakalayın:
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);
});
}
- Video akışından anlık görüntü (video çerçevesi) almak ve bunu
canvas
öğesinde göstermek için Snap'i tıklayın:
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');
function snapPhoto() {
photoContext.drawImage(video, 0, 0, photo.width, photo.height);
show(photo, sendBtn);
}
- Resmi baytlara dönüştürmek ve veri kanalı üzerinden göndermek için Gönder'i tıklayın:
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));
}
}
Alıcı taraf, veri kanalı mesaj baytlarını bir resme dönüştürür ve resmi kullanıcıya gösterir:
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);
}
Kodu alın
work
klasörünüzün içeriğinistep-06
içeriğiyle değiştirin.
work
içindeki index.html
dosyanız şu şekilde görünmelidir**:**
<!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 & 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>
work
dizininizden bu codelab'i takip etmiyorsanızstep-06
klasörüne veya geçerli çalışma klasörünüze ait bağımlılıkları yüklemeniz gerekebilir. Çalışma dizininizden aşağıdaki komutu çalıştırmanız yeterlidir:
npm install
- Yüklendikten sonra, Node.js sunucunuz çalışmıyorsa
work
dizininizden aşağıdaki komutu çalıştırarak başlatın:
node index.js
Make sure that you're using the version of `index.js` that implements Socket.IO and
Değişiklik yaparsanız Node.js sunucunuzu yeniden başlatmayı unutmayın.
Node ve Socket.IO hakkında daha fazla bilgi için Sinyal ayarlama kurulumu bölümüne bakın
mesaj gönderip alma hizmeti.
- Gerekirse uygulamanın web kameranızı kullanmasına izin vermek için İzin ver'i tıklayın.
Uygulama rastgele bir oda kimliği oluşturur ve URL'ye kimliği ekler.
- Yeni bir tarayıcı sekmesinde veya penceresinde adres çubuğundaki URL'yi açın.
- Fotoğraf çek ve Gönder'i tıklayın, ardından sayfanın alt kısmındaki diğer sekmede Gelen fotoğraflar'a bakın.
Uygulama, fotoğrafları sekmeler arasında aktarır.
Aşağıdakine benzer bir tablo görürsünüz:
Bonus puan kazanın
Herhangi bir dosya türünü paylaşmayı mümkün kılmak için kodu nasıl değiştirebilirsiniz?
Daha fazla bilgi
9. Tebrikler
Gerçek zamanlı video akışı ve veri alışverişi için bir uygulama oluşturdunuz.