Вывод звука из MemoryStream с использованием TTS для Discord Bot - PullRequest
0 голосов
/ 25 декабря 2018

Я пишу Discord Bot в VS2017, используя оболочку Discord.Net.Я получил все для работы (разбор / отправка текстовых команд, объединение голосовых каналов), кроме основной цели: использование потока вывода звука TTS в голосовом канале.

По сути, я использую SpeechSynthesizer для создания MemoryStreamи напиши это боту Discord.Проблема в том, что нет звука.Совсем.Я следил за несколькими другими ответами, а также за документацией на сайте Discord.Net и, похоже, не могу найти способ заставить это работать.Потоковое аудио через url / file хорошо документировано, но не так.

var ffmpeg = CreateProcess("");
            var output = ffmpeg.StandardOutput.BaseStream;
            IAudioClient client;
            ConnectedChannels.TryGetValue(guild.Id, out client);
            var discord = client.CreatePCMStream(AudioApplication.Mixed);


            await output.CopyToAsync(discord);
            await discord.FlushAsync();

Выше был пример, который я использовал, который получен из файла через ffmpeg.Я вижу, что это просто копирование через поток, поэтому я попытался выполнить следующие действия в различных методах:

IAudioClient client;
            ConnectedChannels.TryGetValue(guild.Id, out client);
            var discord = client.CreatePCMStream(AudioApplication.Mixed);

            var synth = new SpeechSynthesizer();
            var stream = new MemoryStream();
            var synthFormat = new SpeechAudioFormatInfo(
                EncodingFormat.Pcm,
                8000,
                16,
                1,
                16000,
                2,
                null);

            synth.SetOutputToAudioStream(stream, synthFormat);
            synth.Speak("this is a test");

            await stream.CopyToAsync(discord);
            await discord.FlushAsync();

Я попытался изменить свойства SpeechAudioFormatInfo, изменив вывод в SpeechSynthesizer, полностью удаливАсинхронные вызовы, почти все, что я мог придумать без результата.

Я понимаю, что могу просто вывести звук на фиктивное аудиоустройство и получить другую учетную запись / бота, но это не было цельюэтого упражнения.Я также понимаю, что мог бы просто записать вывод в файл и просто передать его, но это увеличило бы время обработки.Эти инструкции TTS невелики, никогда не превышают 5 слов и должны быть достаточно быстрыми, поскольку они должны быть «выносками».

Наконец, я не смог точно найти способ сделать этоработать с ffmpeg либо.Все, что я прочитал, указывает на необходимость физического источника, а не только потока памяти.

Итак, я в конце.Любая помощь будет оценена.

1 Ответ

0 голосов
/ 26 марта 2019

Discord.NET немного требователен к AudioStreams.Вам нужно один PCMStream для каждого аудио соединения, или это сделает некоторые странные вещи.Вы можете создать свой PCMStream при голосовом подключении, а затем вызвать несколько SendAsync для отправки аудио.

Если я правильно помню, вы сможете выводить поток TTS в качестве мультимедиа (файл мультимедиа в формате mp3 или AAC). Затем воспроизведитеАудио файл TTS вот так

public async Task SendAsync(float volume, string path, AudioOutStream stream)
{
    _currentProcess = CreateStream(path);
    while (true)
    {
        if (_currentProcess.HasExited)
        { break; }
        int blockSize = 2880;
        byte[] buffer = new byte[blockSize];
        int byteCount;
        byteCount = await _currentProcess.StandardOutput.BaseStream.ReadAsync(buffer, 0, blockSize);
        if (byteCount == 0)
        { break; }
        await stream.WriteAsync(buffer, 0, byteCount);
     }
    await stream.FlushAsync();
}

И вызовите ffmpeg вот так:

private static Process CreateStream(string path)
{
    var ffmpeg = new ProcessStartInfo
    {
        FileName = "ffmpeg",
        Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1",
        UseShellExecute = false,
        RedirectStandardOutput = true
    };
    return Process.Start(ffmpeg);
}
...