private int playbackDevice_audioRequested(int handle, IntPtr buffer, int length, IntPtr user) { if (firstPlayProcCall) { // first call is synchronous, following calls are asynchronous. firstPlayProcCall = false; if (playbackQueue == null) { playbackQueue = new MemoryQueue(); } else { playbackQueue.Clear(); } return(0); } try { lock (playback_lock) { // read audio from users we're listening to var frames = new List <RTPFrame>(); foreach (var voiceSet in voiceSets) { var guild = Discord.GetGuild(voiceSet.Key); foreach (var listenStream in voiceSet.Value.listenStreams) { if (listenStream.Value == null) { continue; } var sender = guild.GetUser(listenStream.Key); if (sender == null || sender.IsMuted || sender.IsSelfMuted || sender.IsSuppressed) { continue; } Log(LogSeverity.Debug, "listen:" + sender.Nickname + " frames[" + listenStream.Value.AvailableFrames + "]"); for (int f = 0; f < listenStream.Value.AvailableFrames; f++) { var frame = listenStream.Value.ReadFrameAsync(CancellationToken.None).GetAwaiter().GetResult(); if (frame.Missed) { Log(LogSeverity.Debug, "RTP frame missed"); } frames.Add(frame); } } } // mix audio frames.Sort((o1, o2) => (int)(o1.Timestamp - o2.Timestamp)); using (var stream = playbackQueue.AsStream(FileAccess.Write)) { mixRTPFrames(frames, stream); } // send audio to playback device using (var stream = Utils.OpenBuffer(buffer, length, FileAccess.Write)) { playbackQueue.Dequeue(stream, Math.Min(Math.Max(0, playbackQueue.Length), length)); return((int)stream.Position); } } } catch (OperationCanceledException) { Log(LogSeverity.Debug, "Audio playback canceled"); return((int)BASSStreamProc.BASS_STREAMPROC_END); } catch (Exception ex) { Log(LogSeverity.Error, "Error in audio playback", ex); return((int)BASSStreamProc.BASS_STREAMPROC_END); } }
public MemoryQueueStream(MemoryQueue queue, FileAccess access) { this.Queue = queue; this.Access = access; }