Example #1
0
        public static void poll(ReadOnlySpan <pollfd> waitHandles, out eDecoderBits decoderBits, out eAudioBits audio, out bool seekRequest, out bool shutdownRequest)
        {
            LibC.poll(waitHandles);
            decoderBits = (eDecoderBits)waitHandles[0].revents;
            audio       = (eAudioBits)waitHandles[1].revents;
            ePollEvents seek     = waitHandles[2].revents;
            ePollEvents shutdown = waitHandles[3].revents;

            if (decoderBits.HasFlag(eDecoderBits.Error))
            {
                throw new ApplicationException("poll(3) returned error status for the decoder device, probably the decoder failed");
            }
            if (audio.HasFlag(eAudioBits.Error))
            {
                throw new ApplicationException("poll(3) returned error status for the audio queue");
            }
            if (seek.HasFlag(ePollEvents.POLLERR))
            {
                throw new ApplicationException("poll(3) returned error status for the seek event handle");
            }
            if (shutdown.HasFlag(ePollEvents.POLLERR))
            {
                throw new ApplicationException("poll(3) returned error status for the shutdown event handle");
            }

            seekRequest     = seek.HasFlag(ePollEvents.POLLIN);
            shutdownRequest = shutdown.HasFlag(ePollEvents.POLLIN);
        }
Example #2
0
        void runThread()
        {
            int           playerHandlesCount = render.pollHandlesCount;
            Span <pollfd> waitHandles        = stackalloc pollfd[playerHandlesCount + 3];

            render.setupPollHandles(waitHandles.Slice(0, playerHandlesCount));
            setupInternalHandles(waitHandles, playerHandlesCount);

            while (true)
            {
                LibC.poll(waitHandles);
                if (waitHandles[playerHandlesCount + 1].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Asked to shut down
                    return;
                }
                if (waitHandles[playerHandlesCount + 2].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Got a seek event
                    if (!handleSeek())
                    {
                        return;
                    }
                    Logger.logDebug("Audio thread seek complete");
                    continue;
                }

                if (waitHandles[playerHandlesCount].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Got a buffer with encoded frame.
                    // Dequeue from Linux kernel so the poll() no longer triggers the data available bit for that particular frame, enqueue into the thread-local managed-only queue.
                    // var d = queues.dequeueEncoded();
                    // encodedFrames.Enqueue( d );
                    pendingQueue.enqueue();
                }
                render.handlePollResult(this, waitHandles);
            }
        }
Example #3
0
        bool handleSeek()
        {
            // Get seek destination timestamp
            TimeSpan seekDest;

            lock (this)
            {
                if (!seekDestination.HasValue)
                {
                    throw new ApplicationException("Seek event was set, but no destination timestamp");
                }
                seekEventHandle.reset();
                seekDest = seekDestination.Value;
            }

            // Stop playing, drop data in the ALSA queue
            render.beginSeek();

            pendingQueue.discardAndFlush();
            // Tell decoder thread it can now send new samples
            m_clock?.drainComplete();

            // Wait for video decoder to catch up
            if (!m_clock.waitForVideoFrame())
            {
                return(false);
            }

            // Run the poll waiting for that special frame
            Span <pollfd> waitHandles = stackalloc pollfd[3];

            setupInternalHandles(waitHandles, 0);

            bool foundTarget = false;

            while (true)
            {
                LibC.poll(waitHandles);

                if (waitHandles[1].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Asked to shut down
                    return(false);
                }
                if (waitHandles[2].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Got another seek event..
                    Logger.logWarning("Multiple seeks are not supported, probably won’t work");
                    lock (this)
                    {
                        if (!seekDestination.HasValue)
                        {
                            throw new ApplicationException("Seek event was set, but no destination timestamp");
                        }
                        seekEventHandle.reset();
                        seekDest        = seekDestination.Value;
                        seekDestination = null;
                    }
                }

                if (waitHandles[0].revents.HasFlag(ePollEvents.POLLIN))
                {
                    // Got a buffer with encoded frame.
                    var d = pendingQueue.queues.dequeueEncoded();

                    if (foundTarget)
                    {
                        pendingQueue.enqueue(d);
                        if (fillBuffer())
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        if (d.timestamp != seekDest)
                        {
                            Logger.logVerbose("Audio thread got sample {0}, needs {1}", d.timestamp, seekDest);
                            // Not the one we're looking for
                            pendingQueue.queues.enqueueEmpty(d.index);
                            continue;
                        }
                        // Received seek destination frame.
                        Logger.logVerbose("Audio thread got the destination audio sample after seek, preparing to resume the playback");
                        pendingQueue.enqueue(d);
                        render.prepareEndSeek();
                        foundTarget = true;
                        if (fillBuffer())
                        {
                            return(true);
                        }
                    }
                }
            }
        }