برنامه نویسی

آموزش پخش ویدیو. JavaScript Webrtc Streaming مثال 🌐liberremoteplay

سلام ، در این پست فقط با استفاده از GetDisplayMedia () (صفحه)) فقط تنظیم ساده Webrtc را پوشش خواهم داد اما برای GetUsermedia () (دوربین ، میکروفون) نیز معتبر است.

اول اگر در توضیحات/آموزش های WEBRTC بیشتر مورد توجه قرار گرفته اید ، این بخشی از مقالات سری Webrtc برای JavaScript و Golang است (این شامل دانش عمومی در مورد Webrtc) است.

در وهله دوم ، اصول اولیه را در مورد Medialchannels ، آنچه آنها هستند و نحوه استفاده از آنها در WebApp شما را به شما معرفی می کنم.

در یک PeerConnection می توانیم دو نوع کانال ، Datachannels (برای انتقال داده های هدف کلی بین همسالان) و MediaChannels (برای داده های رسانه ای مانند فیلم/صوتی) ایجاد کنیم. MediaChannels قبل از محکم اتصال منفی می شوند اما پارتورهای آن می توانند با زمان به صورت خودکار یا دستی تغییر کنند.

جریان با استفاده از MediaChannels معمولاً فقط از جعبه خارج می شود اما اگر WebApp شما به رفتار خاصی نیاز دارد که با پیش فرض متفاوت باشد می توانید از کدک های ویدئویی/صوتی استفاده کنید.

کدک های زیادی برای استفاده هستند اما باید بدانید که همه کدک ها همیشه پشتیبانی نمی شوند (آنها به نرم افزار/سخت افزار کاربر وابسته هستند) اما جای نگرانی نیست زیرا منفی کدک توسط مرورگر مانند Magic انجام می شود. در اینجا لیستی از کدک های موجود برای Webrtc را در اختیار دارید.

برای کار با کدک ها ، به مجموعه ای از کدک های ترجیحی که در ترجیح داده می شوند ، نیاز داریم. سابق: [The codec I want the most, …, Other codecs, …, Worst codec]بشر تنظیمات Codecs باید توسط مشتری تنظیم شود (موردی که می خواهد فیلم/صوتی را دریافت کند).

اکنون که این اطلاعات کلی کوچک را در مورد MediaChannels آموخته اید ، نمونه هایی را مشاهده خواهیم کرد.

⭐ این نمونه های اصلاح شده و ساده از “لیبره بازی“محصول نرم افزاری من که سعی می کند یک باشد جایگزین برای بازی از راه دور Steamبشر اگر علاقه مند به کسب اطلاعات بیشتر در مورد نحوه عملکرد آن هستید ، من این سری را ادامه خواهم داد ، اما برای لحظه ای پایگاه کد را برای بررسی آن خواهید داشت

پرچم آرم LibererEmotePlay

📘 مثال کد برای همتا میزبان (که صفحه نمایش را به اشتراک می گذارد)

در این مثال سیگنالیسم با استفاده از WebSocket ساخته شده است ، من آن را WS () می نامم ()

بعد همه منطق را برای میزبان JS خود خواهیم نوشت


// PeerConnection declaration (note that you will need to specify iceServers)
let peerConnection = peerConnection = new RTCPeerConnection({iceServers});;

// This function returns the media stream generated by getDisplayMedia or
// undefined if the user rejects to share screen.
// Video and Audio properties can be objects to specify some parameters
// like resolution, frame rate, ...
async function getDisplayMediaStream(resolution, idealFrameRate maxFramerate) {
    try {
        const mediastream = await navigator.mediaDevices.getDisplayMedia({
            video: true,
            audio: true,
        });

        return mediastream;
    } catch (e) {
        return undefined;
    }
}

peerConnection.onicecandidate = async (event) => {
    if (event.candidate) {
        const data = {
            type: 'candidate',
            candidate: event.candidate.toJSON(),
            role: 'host'
        };

        return ws().send(JSON.stringify(data));

    }

    const answer = peerConnection?.localDescription?.toJSON();
    const data = {
        type: 'answer',
        answer,
        role: 'host'
    };

    return ws().send(JSON.stringify(data));

};

let offerArrived = false

async function onSignalArrive(data) {

    const { type, offer, candidate, role } = JSON.parse(data);

    if (role !== 'client') return;

    if (type === "candidate") {
        try {peerConnection.addIceCandidate(candidate)} catch {/** */}
        return
    }

    if (type !== 'offer') return;
    if (!offer || offerArrived) return;

    try {
        await peerConnection.setRemoteDescription(offer);
    } catch (e) {
        console.error(e)
        return
    }
    offerArrived = true;

    const stream = await getDisplayMediaStream(resolution, idealFrameRate, maxFramerate);

    // Here I add MediaStream tracks to the WebRTC Peerconnection
    stream?.getTracks().forEach((track) => {
        if (!stream) return;
        peerConnection?.addTrack(track, stream);
    });

    try {

        await peerConnection.setLocalDescription(await peerConnection.createAnswer());

    } catch (e) {
        console.error(e)
        return
    }

}


const cllbck = (ev) =>  onSignalArrive(ev.data)
ws().addEventListener("message", cllbck)
unlistenerStreamingSignal = () => ws().removeEventListener("message", cllbck)
return

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

📘 مثال کد برای مشتری مشتری (که جریان ویدیو/صوتی را دریافت می کند)

در این مثال سیگنالیسم با استفاده از WebSocket ساخته شده است ، من آن را WS () می نامم ()

اعلام عنصر ویدیویی HTML


حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اعلام کدک های ترجیحی ما

const DEFAULT_PREFERED_CODECS = ["video/VP9","video/AV1","video/H264", "video/VP8"]
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

ترتیب اولویت: “VP9” ، “AV1” ، “H264” و “VP8” است

ابتدا یک تابع را برای دریافت کدک های مورد نظر خود به ترتیب اعلام خواهیم کرد

// This function is a little modification of one that you can find in MDN
// docs
export function getSortedVideoCodecs() {

    const codecs = RTCRtpReceiver.getCapabilities("video")?.codecs;

    if (!codecs) return [];

    return codecs.sort((a, b) => {
      const indexA = DEFAULT_PREFERED_CODECS.value.indexOf(a.mimeType);
      const indexB = DEFAULT_PREFERED_CODECS.value.indexOf(b.mimeType);
      const orderA = indexA >= 0 ? indexA : Number.MAX_VALUE;
      const orderB = indexB >= 0 ? indexB : Number.MAX_VALUE;
      return orderA - orderB;
    });
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

و اکنون تمام منطق مشتری JS


// PeerConnection declaration (note that you will need to specify iceServers)
let peerConnection = peerConnection = new RTCPeerConnection({iceServers});;

// Get the video element
const videoElement = document.getElementById("video-streaming");

// Add transceiver to receive video (if you don't want codec preferences
// is not needed to declare the transceiver)
const transceiver = peerConnection.addTransceiver("video", { direction: "recvonly" });

// Set the codec preferences to the transceiver (this is the prefered
// syntax, a lot of StackOverflow answers are not updated and say that 
// you must modify the raw SDP messages. These days setCodecPreferences
// is supported in almost every modern browsers)
transceiver.setCodecPreferences(getSortedVideoCodecs());

peerConnection.onicecandidate = (e) => {
    if (!e.candidate) return;

    const data = {
        type: 'candidate',
        candidate: e.candidate.toJSON(),
        role: 'client'
    };

    ws().send(JSON.stringify(data));
};

peerConnection.ontrack = (ev) => {

    if (ev.streams && ev.streams[0]) {
        // Setting videoElement source and automatically play video
        videoElement.srcObject = ev.streams[0];
        videoElement.play();
    } else {
        if (!inboundStream) {
        // Setting videoElement source and automatically play video
            inboundStream = new MediaStream();
            videoElement.srcObject = inboundStream;
            videoElement.play();
        }
        // Adding the track to the MediaStream
        inboundStream.addTrack(ev.track);
};

// Create the offer indicating that we want to receive audio/video
const offer = await peerConnection.createOffer({
    offerToReceiveAudio: true,
    offerToReceiveVideo: true,
    iceRestart: true
});

await peerConnection.setLocalDescription(offer);

const data = {
    type: 'offer',
    offer: offer,
    role: 'client'
};

ws().send(JSON.stringify(data));

async function onSignalArrive(data) {
    const { type, answer, candidate, role } = JSON.parse(data);

    if (role !== 'host') {
        return;
    }

    switch (type) {
        case 'answer':
            if (!answer) return;
            await peerConnection.setRemoteDescription(answer);
            break;
        case 'candidate':
            try {await peerConnection.addIceCandidate(candidate)} catch {/** */}
            break;
    }
}

const cllbck = (ev) =>  onSignalArrive(ev.data);
ws().addEventListener("message", cllbck);
unlistenerStreamingSignal = () => ws().removeEventListener("message", cllbck);

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با استفاده از این کد می توانید شروع به اجرای راه حل پخش ویدیویی خود کنید ، امیدوارم که این آموزش کوچک را دوست داشته باشید. ❤

اگر می خواهید آموزش های بیشتر Webrtc در نظرات به من بگویید که آنها را می خوانم.

منابع اطلاعاتی:

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا