dank074 / Discord-video-stream

Experiment for making video streaming work for discord selfbots.
177 stars 35 forks source link

How to stop a stream? #15

Closed DedaDev closed 1 year ago

DedaDev commented 1 year ago

title

dank074 commented 1 year ago
const stopStreaming = (client: Client) => {
  command?.kill("SIGINT");

  client.leaveVoice();
}
Naozumi520 commented 1 year ago

I tried to use command?.kill("SIGINT"); but it's not working. I'm trying to switch the video source. When I run the command can command?.kill("SIGINT"); being called, but the video is still playing.

Naozumi520 commented 1 year ago

I tired remove the question mark, and it turns out command is undefined. (Why? The video is playing.)

dank074 commented 1 year ago

Re-opened the issue because I've only just realized that DedaDev was asking how to close the stream without necessarily leaving the voice channel. There is a gateway message specifically for that it's just not currently implemented, so I will implement that.

I tired remove the question mark, and it turns out command is undefined. (Why? The video is playing.)

Can you share the code you're currently using to start the stream and switching the video @Naozumi520

dank074 commented 1 year ago

Fixed in https://github.com/dank074/Discord-video-stream/pull/17

DedaDev commented 1 year ago

Is it possible to switch the stream without stopping and then starting again? I'm trying to make a TV bot.

dank074 commented 1 year ago

Is it possible to switch the stream without stopping and then starting again?

Without closing down the voice/stream connection? Yes

Without restarting ffmpeg? No

You can just close ffmpeg and restart it with another input. It will take a couple seconds to start outputting packets for the new video so the users will see a gray/black loading screen during those seconds

DedaDev commented 1 year ago

Is it possible to switch the stream without stopping and then starting again?

Without closing down the voice/stream connection? Yes

Without restarting ffmpeg? No

You can just close ffmpeg and restart it with another input. It will take a couple seconds to start outputting packets for the new video so the users will see a gray/black loading screen during those seconds

how?

dank074 commented 1 year ago

how?

I'll write a snippet for you tonight when I get home

dank074 commented 1 year ago

this worked for me:

import { Client } from "discord.js-selfbot-v13";
import { command, streamLivestreamVideo, VoiceUdp, setStreamOpts } from "@dank074/discord-video-stream";
import config from "./config.json";

const client = new Client();

client.patchVoiceEvents(); //this is necessary to register event handlers

setStreamOpts({
    width: config.streamOpts.width, 
    height: config.streamOpts.height, 
    fps: config.streamOpts.fps, 
    bitrateKbps: config.streamOpts.bitrateKbps, 
    hardware_encoding: config.streamOpts.hardware_acc
})

// ready event
client.on("ready", () => {
    console.log(`--- ${client.user.tag} is ready ---`);
});

// message event
client.on("messageCreate", async (msg) => {
    if (msg.author.bot) return;

    if (!config.acceptedAuthors.includes(msg.author.id)) return;

    if (!msg.content) return;

    if(msg.content.startsWith('$join')) {

        const channel = msg.author.voice.channel;

        if(!channel) {
            console.log('you must be in a voice channel first');
            return;
        }

        console.log(`Attempting to join voice channel ${msg.guildId}/${channel.id}`);
        await client.joinVoice(msg.guildId, channel.id);
    } else if (msg.content.startsWith(`$play-live`)) {
        const args = parseArgs(msg.content)
        if (!args) return;

        if(!client.voiceConnection) {
            console.log('bot must be in a voice channel')
            return;
        }

        // lets stop the current ffmpeg instance first
        command?.kill('SIGINT');

        // lets give the process time to close before we spawn a new one
        await new Promise<void>((resolve, reject) => {
            setTimeout(() => {
                resolve();
            }, 500);
        });

        if(!client.voiceConnection.screenShareConn) {
            // no current stream has started, so lets start one
            const udpConn = await client.createStream();

            udpConn.voiceConnection.setSpeaking(true);
            udpConn.voiceConnection.setVideoStatus(true);
        }

        playVideo(args.url, client.voiceConnection.screenShareConn.udp);
        return;
    } else if (msg.content.startsWith("$disconnect")) {
        command?.kill("SIGINT");

        client.leaveVoice();
    } else if(msg.content.startsWith("$stop-stream")) {
        command?.kill('SIGINT');

        const stream = client.voiceConnection?.screenShareConn;

        if(!stream) return;

        stream.setSpeaking(false);
        stream.setVideoStatus(false);

        client.stopStream();
    }
});

// login
client.login(config.token);

async function playVideo(video: string, udpConn: VoiceUdp) {
    console.log("Started playing video");
    try {
        const res = await streamLivestreamVideo(video, udpConn);

        console.log("Finished playing video " + res);
    } catch (e) {
        console.log(e);
    }
}

function parseArgs(message: string): Args | undefined {
    const args = message.split(" ");
    if (args.length < 2) return;

    const url = args[1];

    return { url }
}

type Args = {
    url: string;
}

@DedaDev