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;
 }