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)); }
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 }
private IconChar?SetKeyIcon(AudioApplication audioApplication) { if (audioApplication != null && audioApplication.IsMuted) { return(IconChar.VolumeMute); } return(null); }
/// <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)); }
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 }
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)); }
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); } }
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; }
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()); }
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)); }
internal DiscordVoiceStream(DiscordVoiceSession client, int bitrate, AudioApplication application = AudioApplication.Mixed) { _session = client; _encoder = new OpusEncoder(bitrate, application, 0); _nextTick = -1; }
public OpusEncodeStream(AudioStream next, int bitrate, AudioApplication application, int packetLoss) { _next = next; _encoder = new OpusEncoder(bitrate, application, packetLoss); _buffer = new byte[OpusConverter.FrameBytes]; }
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(); }