Exemplo n.º 1
0
        public AudioOutStream CreateDirectPCMStream(AudioApplication application, int?bitrate)
        {
            var outputStream    = new OutputStream(ApiClient);
            var sodiumEncrypter = new SodiumEncryptStream(outputStream, this);
            var rtpWriter       = new RTPWriteStream(sodiumEncrypter, _ssrc);

            return(new OpusEncodeStream(rtpWriter, bitrate ?? (96 * 1024), application));
        }
Exemplo n.º 2
0
        public AudioOutStream CreateDirectPCMStream(AudioApplication application, int?bitrate, int packetLoss)
        {
            var outputStream    = new OutputStream(ApiClient);                                        //Ignores header
            var sodiumEncrypter = new SodiumEncryptStream(outputStream, this);                        //Passes header
            var rtpWriter       = new RTPWriteStream(sodiumEncrypter, _ssrc);                         //Consumes header, passes

            return(new OpusEncodeStream(rtpWriter, bitrate ?? (96 * 1024), application, packetLoss)); //Generates header
        }
Exemplo n.º 3
0
        private IconChar?SetKeyIcon(AudioApplication audioApplication)
        {
            if (audioApplication != null && audioApplication.IsMuted)
            {
                return(IconChar.VolumeMute);
            }

            return(null);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates a stream to which you can write audio data.
        /// </summary>
        /// <param name="application">What the encoding should be optimized for</param>
        public DiscordVoiceStream CreateStream(uint bitrate, AudioApplication application = AudioApplication.Mixed)
        {
            if (State != DiscordVoiceClientState.Connected)
            {
                throw new InvalidOperationException("Connection has been closed.");
            }

            return(new DiscordVoiceStream(this, (int)bitrate, application));
        }
Exemplo n.º 5
0
        public AudioOutStream CreatePCMStream(AudioApplication application, int?bitrate, int bufferMillis, int packetLoss)
        {
            var outputStream    = new OutputStream(ApiClient);                                                                   //Ignores header
            var sodiumEncrypter = new SodiumEncryptStream(outputStream, this);                                                   //Passes header
            var rtpWriter       = new RTPWriteStream(sodiumEncrypter, _ssrc);                                                    //Consumes header, passes
            var bufferedStream  = new BufferedWriteStream(rtpWriter, this, bufferMillis, _connection.CancelToken, _audioLogger); //Ignores header, generates header

            return(new OpusEncodeStream(bufferedStream, bitrate ?? (96 * 1024), application, packetLoss));                       //Generates header
        }
Exemplo n.º 6
0
        public AudioOutStream CreatePCMStream(AudioApplication application, int?bitrate, int bufferMillis)
        {
            var outputStream    = new OutputStream(ApiClient);
            var sodiumEncrypter = new SodiumEncryptStream(outputStream, this);
            var rtpWriter       = new RTPWriteStream(sodiumEncrypter, _ssrc);
            var bufferedStream  = new BufferedWriteStream(rtpWriter, this, bufferMillis, _connection.CancelToken, _audioLogger);

            return(new OpusEncodeStream(bufferedStream, bitrate ?? (96 * 1024), application));
        }
Exemplo n.º 7
0
        public bool Speak(byte[] audio, uint bitrate, AudioApplication usedFor = AudioApplication.Mixed)
        {
            while (Speaking)
            {
                Thread.Sleep(1);
            }

            Speaking = true;

            var encoder = new OpusEncoder((int)bitrate, usedFor, 0);

            int offset = 0;

            long nextTick = Environment.TickCount;

            try
            {
                while (offset + OpusEncoder.FrameBytes < audio.Length && !_stopCurrent)
                {
                    SetSpeaking(true);

                    long dist = nextTick - Environment.TickCount;

                    if (dist <= 0)
                    {
                        SendAudioData(encoder, ref audio, offset, _sequence, _timestamp);

                        nextTick += OpusEncoder.TimeBetweenFrames;
                        offset   += OpusEncoder.FrameBytes;
                        _sequence++;
                        _timestamp += OpusEncoder.FrameSamplesPerChannel;
                    }
                    else
                    {
                        Thread.Sleep((int)dist);
                    }
                }

                SetSpeaking(false);

                _stopCurrent = false;
                Speaking     = false;

                return(true);
            }
            catch
            {
                Speaking = false;

                return(false);
            }
        }
Exemplo n.º 8
0
        private static Process InputToOpus(string input, int bitrate = 96000, AudioApplication application = AudioApplication.Voice)
        {
            var opusApplication = application == AudioApplication.Voice ? "voip" : application == AudioApplication.Music ? "audio" : "lowdelay";
            var ffmpeg          = new ProcessStartInfo
            {
                FileName               = "ffmpeg",
                Arguments              = $"-hide_banner -loglevel debug -i \"{input}\" -sample_fmt s16 -ar 48000 -ac 2 -acodec libopus -b:a {bitrate} -vbr on -compression_level 0 -frame_duration 20 -application {opusApplication} -map 0:a -f data pipe:1",
                UseShellExecute        = false,
                RedirectStandardOutput = true
            };
            var procces = Process.Start(ffmpeg);

            return(procces);
        }
        public AudioStreamingService(IDiscordConnectionView discordConnectionView, IAudioCaptureView audioCaptureView)
        {
            // ask NAudio to send buffers by 40ms block
            captureBufferDuration   = 40;
            streamingBufferDuration = 1000;
            // 96kbps (high quality)
            // Opus supports bitrate from 6kbps to 510kbps
            // Default channel bitrate at the time this is being written is 64k
            // you need to change the channel setting to go to 96k
            // Discord won't go above 128kbps for boosted servers and only 96kbps for standard
            // According to Opus the quality increase from 96k to 128k is marginal anyway
            // https://opus-codec.org/comparison/
            // quality issue is most likely due to packet loss / jittering and discord
            // putting forward low latency vs quality
            audioBitrate = 128 * 1024;
            packetLoss   = 20;
            audioContent = AudioApplication.Music;
            // allocate buffer large enough for 100ms at 48khz 16bits stereo
            audioTxBuffer  = new byte[19200];
            audioVisBuffer = new byte[19200];

            autoReconnectChannel = false;

            gainUpdateLock = new object();
            muted          = false;
            gain           = 1.0f;

            DiscordConnectionView = discordConnectionView;
            AudioCaptureView      = audioCaptureView;
            discordSocketClient   = new DiscordSocketClient(
                new DiscordSocketConfig {
                LogLevel = LogSeverity.Verbose
            }
                );
            discordSocketClient.Log                   += LogAsync;
            discordSocketClient.Connected             += DiscordSocketClient_Connected;
            discordSocketClient.Disconnected          += DiscordSocketClient_Disconnected;
            discordSocketClient.Ready                 += DiscordSocketClient_Ready;
            discordSocketClient.LoggedIn              += DiscordSocketClient_LoggedIn;
            discordSocketClient.LoggedOut             += DiscordSocketClient_LoggedOut;
            discordSocketClient.VoiceServerUpdated    += DiscordSocketClient_VoiceServerUpdated;
            discordSocketClient.UserVoiceStateUpdated += DiscordSocketClient_UserVoiceStateUpdated;
        }
Exemplo n.º 10
0
        private string SetKeyTitle(AudioApplication audioApplication, bool hasImage)
        {
            StringBuilder title = new StringBuilder();

            if (mixerSettings.ShowVolume)
            {
                title.Append($"{(int)(audioApplication.Volume * 100)}%\n");
            }

            if (!hasImage || mixerSettings.ShowName)
            {
                if (audioApplication != null)
                {
                    // Add new line if mute icon is already shown
                    title.Append(audioApplication.Name);
                }
            }

            return(title.ToString());
        }
Exemplo n.º 11
0
        public OpusEncoder(int bitrate, AudioApplication application, int packetLoss)
        {
            if (bitrate < 5 * 1000 || bitrate > 384 * 1000)
            {
                throw new ArgumentOutOfRangeException(nameof(bitrate));
            }

            Application = application;
            BitRate     = bitrate;

            OpusApplication opusApplication;
            OpusSignal      opusSignal;

            switch (application)
            {
            case AudioApplication.Mixed:
                opusApplication = OpusApplication.MusicOrMixed;
                opusSignal      = OpusSignal.Auto;
                break;

            case AudioApplication.Music:
                opusApplication = OpusApplication.MusicOrMixed;
                opusSignal      = OpusSignal.Music;
                break;

            case AudioApplication.Voice:
                opusApplication = OpusApplication.Voice;
                opusSignal      = OpusSignal.Voice;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(application));
            }

            _ptr = CreateEncoder(SamplingRate, Channels, (int)opusApplication, out var error);
            CheckError(error);
            CheckError(EncoderCtl(_ptr, OpusCtl.SetSignal, (int)opusSignal));
            CheckError(EncoderCtl(_ptr, OpusCtl.SetPacketLossPercent, packetLoss)); //%
            CheckError(EncoderCtl(_ptr, OpusCtl.SetInbandFEC, 1));                  //True
            CheckError(EncoderCtl(_ptr, OpusCtl.SetBitrate, bitrate));
        }
Exemplo n.º 12
0
 internal DiscordVoiceStream(DiscordVoiceSession client, int bitrate, AudioApplication application = AudioApplication.Mixed)
 {
     _session  = client;
     _encoder  = new OpusEncoder(bitrate, application, 0);
     _nextTick = -1;
 }
Exemplo n.º 13
0
 public OpusEncodeStream(AudioStream next, int bitrate, AudioApplication application, int packetLoss)
 {
     _next    = next;
     _encoder = new OpusEncoder(bitrate, application, packetLoss);
     _buffer  = new byte[OpusConverter.FrameBytes];
 }
Exemplo n.º 14
0
        public void Load(JToken root)
        {
            var stack = new JTokenStack(root);

            // #general
            stack.Push("general");
            botToken = (string)stack.Get("botToken");
            stack.Pop();
            // #

            // #voice
            stack.Push("voice");

            // #voice - speak
            stack.Push("speak");
            speakEnabled         = (bool)stack.Get("enabled");
            speakRecordingDevice = (string)stack.Get("recordingDevice");
            speakAudioType       = (AudioApplication)Enum.Parse(typeof(AudioApplication), (string)stack.Get("audioType"));
            speakBitRate         = (int?)stack.Get("bitRate");
            speakBufferMillis    = (int)stack.Get("bufferMillis");
            stack.Pop();
            // #voice

            // #voice - listen
            stack.Push("listen");
            listenEnabled        = (bool)stack.Get("enabled");
            listenPlaybackDevice = (string)stack.Get("playbackDevice");
            stack.Pop();
            // #voice

            voiceAutoJoinVoiceChannels = readVoiceChannels((JObject)stack.Get("autoJoinVoiceChannels"));
            stack.Pop();
            // #

            // #text
            stack.Push("text");

            // #text - commands
            stack.Push("commands");
            commandsBotAgent = (string)stack.Get("botAgent");
            if (commandsBotAgent == null)
            {
                throw new FormatException("bot agent cannot be null");
            }

            // #text - commands - permissions
            stack.Push("permissions");
            commandsDefaultPermissions.Clear();
            foreach (var defaultPermission in stack.Get("defaultPermissions").Value <string>().Split(' '))
            {
                commandsDefaultPermissions.Add(defaultPermission);
            }
            commandsUserPermissions = readUserPermissions((JObject)stack.Get("userPermissions"));
            commandsRolePermissions = readRolePermissions((JObject)stack.Get("rolePermissions"));
            stack.Pop();
            // #text - commands

            stack.Pop();
            // #text

            stack.Pop();
            // #

            stack.Pop();
        }