1

I am using Agora for Video Chat in my ASP.NET MVC web app and Android. This is how it is working.

There is a separate view in ASP.NET MVC web app for VideoCall, in which there is a button on click of that the partial view for video chat is being displayed in the screen and also video part is being initialized and played.

Video part and floating video view through partial view is working fine in this VideoCall page. But when I am navigating to other views like Index, Privacy or other view/page the floating video view is still there but there is not any video on it.

What I want to achieve is when user clicks the button "Join", it displays the floating video view and joins the call (which is working in VideoCall view only), but when I navigate to other views the video get vanished but floating partial view remains there (it's because I have called the partial view in the main layout of the web app), probably because we are only initializing the video in VideoCall but I don't know the exact reason.

I want the video to play in the floating partial view until user leaves the video chat (option is available in floating partial video view and working). If the user is not leaving the video, it should keep playing in floating view, even if user navigate to other web pages in the web app.

Partial view code:

<!-- Floating window for video -->
<div id="floating-video-window" class="floating-video-window" style="display: none;">
    <div class="floating-header">
        <span id="close-floating-window" class="close-btn">×</span>
    </div>

    <div class="video-container">
        <!-- Remote video -->
        <div id="remote-player" class="remote-player"></div>

        <!-- Local video (Picture-in-Picture) -->
        <div id="local-player-container" class="local-player-container">
            <div id="local-player" class="local-player"></div>
        </div>
    </div>
</div>

<style>

    /* Floating window styles */
    .floating-video-window {
        position: fixed;
        bottom: 20px;
        right: 20px;
        width: 480px; /* Width of the floating window */
        height: 360px; /* Height of the floating window */
        background-color: #fff;
        border: 1px solid #ddd;
        z-index: 1000;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    }

    .floating-header {
        padding: 5px;
        background-color: #007bff;
        color: white;
        text-align: right;
    }

    .close-btn {
        cursor: pointer;
        font-size: 18px;
        font-weight: bold;
    }

    /* Container for both remote and local videos */
    .video-container {
        position: relative;
        width: 100%;
        height: 100%;
    }

    /* Styles for remote video */
    .remote-player {
        width: 100%;
        height: 100%;
        background-color: #000; /* Black background for the remote video */
    }

    /* Styles for local video container */
    .local-player-container {
        position: absolute;
        bottom: 10px; /* Distance from bottom */
        right: 10px; /* Distance from right */
        width: 120px; /* Width of the local video */
        height: 90px; /* Height of the local video */
        border: 2px solid #fff; /* White border around the local video */
        border-radius: 4px; /* Rounded corners for the local video */
        overflow: hidden; /* Hide overflow to keep border radius effect */
    }

    /* Styles for local video */
    .local-player {
        width: 100%;
        height: 100%;
        background-color: #000; /* Black background for the local video */
    }

</style>

JS file which is responsible for handling video it comes with Agora SDK, I have made some modifications to it, but failed to achieve my goal.

// Create Agora client
var client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });

var localTracks = {
    videoTrack: null,
    audioTrack: null
};
var remoteUsers = {};

// Agora client options
var options = {
    appid: "myid here", // Hardcoded AppID
    channel: "my channel name here", // Hardcoded channel name
    token: "my token here" // Hardcoded Token 
};

// Initialize or join video call
async function join() {

    if (sessionStorage.getItem('videoCallJoined') === 'true') {
        $("#floating-video-window").show();
        return; // Skip re-joining if already joined
    }

    client.on("user-published", handleUserPublished);
    client.on("user-unpublished", handleUserUnpublished);

    [options.uid, localTracks.audioTrack, localTracks.videoTrack] = await Promise.all([
        client.join(options.appid, options.channel, options.token || null),
        AgoraRTC.createMicrophoneAudioTrack(),
        AgoraRTC.createCameraVideoTrack()
    ]);

    localTracks.videoTrack.play("local-player");
    $("#local-player-name").text(`localVideo(${options.uid})`);

    await client.publish(Object.values(localTracks));
    console.log("publish success");

    sessionStorage.setItem('videoCallJoined', 'true');
    $("#floating-video-window").show();
}

// Leave the video call
async function leave() {
    for (let trackName in localTracks) {
        const track = localTracks[trackName];
        if (track) {
            track.stop();
            track.close();
            localTracks[trackName] = undefined;
        }
    }

    remoteUsers = {};
    $("#remote-player").html("");
    await client.leave();

    $("#local-player-name").text("");
    $("#join").attr("disabled", false);
    $("#leave").attr("disabled", true);
    $("#floating-video-window").hide(); // Hide the floating window on leave

    sessionStorage.setItem('videoCallJoined', 'false');
    console.log("client leaves channel successfully");
}

// Subscribe to remote user tracks
async function subscribe(user, mediaType) {
    const uid = user.uid;
    await client.subscribe(user, mediaType);
    console.log("subscribe success");

    if (mediaType === 'video') {
        const player = $(`
          <div id="player-wrapper-${uid}">
            <p class="player-name">remoteUser(${uid})</p>
            <div id="player-${uid}" class="player"></div>
          </div>
        `);
        $("#remote-player").append(player);
        user.videoTrack.play(`player-${uid}`);
    }
    if (mediaType === 'audio') {
        user.audioTrack.play();
    }
}

// Handle user publishing video
function handleUserPublished(user, mediaType) {
    const id = user.uid;
    remoteUsers[id] = user;
    subscribe(user, mediaType);
}

// Handle user unpublishing video
function handleUserUnpublished(user) {
    const id = user.uid;
    delete remoteUsers[id];
    $(`#player-wrapper-${id}`).remove();
}

// Event handlers
$(document).ready(function () {
    // Handle Join button click
    $("#join").click(async function () {
        $("#join").attr("disabled", true);
        try {
            await join();
            if (options.token) {
                $("#success-alert-with-token").css("display", "block");
            } else {
                $("#success-alert a").attr("href", `index.html?appid=${options.appid}&channel=${options.channel}&token=${options.token}`);
                $("#success-alert").css("display", "block");
            }
        } catch (error) {
            console.error(error);
        } finally {
            $("#leave").attr("disabled", false);
        }
    });

    // Handle Leave button click
    $("#leave").click(function (e) {
        leave();
    });

    // Handle Close button click
    $("#close-floating-window").click(function () {
        $("#floating-video-window").hide();
        leave(); // Leave the call when the window is closed
    });

    // Check if the video call should be joined on page load
    if (sessionStorage.getItem('videoCallJoined') === 'true') {
        $("#floating-video-window").show();
        join();
    }
});

// Handle page visibility changes
document.addEventListener('visibilitychange', function () {
    if (document.visibilityState === 'hidden') {
        // Optionally, pause the video call if needed
    } else {
        // Optionally, resume the video call if needed
        if (sessionStorage.getItem('videoCallJoined') === 'true') {
            join();
        }
    }
});

I have simply called the partial view in the main layout like this:

<partial name="_FloatingVideoView" />

Waiting for a solution :)

I tried to solve it but unable to understand this.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.