Beispiel #1
0
        // Jitter buffer wrapper API

        // Locking must be done at the application level to ensure
        // that two threads can't be in jitter buffer methods.
        // timestamp is a counter incremented once per "tick"
        public void JitterBufferPut(byte[] frame, int startIndex, uint byteCount, uint timestamp)
        {
            if (jitterBuffer == null)
            {
                throw new Exception("JitterBufferPut: jitterBuffer is null!");
            }
            lock (jitterBufferLockable) {
                JitterBufferPacket p = new JitterBufferPacket();
                unsafe
                {
                    fixed(byte *frameBytes = &frame[startIndex])
                    {
                        p.data      = frameBytes;
                        p.len       = byteCount;
                        p.timestamp = timestamp;
                        p.span      = (uint)frameSize;
                        jitter_buffer_put(jitterBuffer, &p);
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Get one packet from the jitter buffer
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="desired_span"></param>
        /// <param name="start_offset"></param>
        /// <returns></returns>
        public int Get(ref JitterBufferPacket packet, int desired_span, out int start_offset)
        {
            if (desired_span <= 0)
            {
                throw new ArgumentOutOfRangeException("desired_span");
            }

            int   i;
            long  j;
            short opt;

            start_offset = 0;

            /* Syncing on the first call */
            if (reset_state)
            {
                bool found = false;
                /* Find the oldest packet */
                long oldest = 0;
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    if (packets[i].data != null && (!found || packets[i].timestamp < oldest))
                    {
                        oldest = packets[i].timestamp;
                        found  = true;
                    }
                }
                if (found)
                {
                    reset_state       = false;
                    pointer_timestamp = oldest;
                    next_stop         = oldest;
                }
                else
                {
                    packet.timestamp = 0;
                    packet.span      = interp_requested;
                    return(JITTER_BUFFER_MISSING);
                }
            }

            last_returned_timestamp = pointer_timestamp;

            if (interp_requested != 0)
            {
                packet.timestamp = pointer_timestamp;
                packet.span      = interp_requested;

                /* Increment the pointer because it got decremented in the delay update */
                pointer_timestamp += interp_requested;
                packet.len         = 0;
                /*fprintf (stderr, "Deferred interpolate\n");*/

                interp_requested = 0;

                buffered = packet.span - desired_span;

                return(JITTER_BUFFER_INSERTION);
            }

            /* Searching for the packet that fits best */

            /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
            for (i = 0; i < MAX_BUFFER_SIZE; i++)
            {
                if (packets[i].data != null && packets[i].timestamp == pointer_timestamp && (packets[i].timestamp + packets[i].span) >= (pointer_timestamp + desired_span))
                {
                    break;
                }
            }

            /* If no match, try for an "older" packet that still spans (fully) the current chunk */
            if (i == MAX_BUFFER_SIZE)
            {
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    if (packets[i].data != null && packets[i].timestamp <= pointer_timestamp && (packets[i].timestamp + packets[i].span) >= (pointer_timestamp + desired_span))
                    {
                        break;
                    }
                }
            }

            /* If still no match, try for an "older" packet that spans part of the current chunk */
            if (i == MAX_BUFFER_SIZE)
            {
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    if (packets[i].data != null && packets[i].timestamp <= pointer_timestamp && (packets[i].timestamp + packets[i].span) > pointer_timestamp)
                    {
                        break;
                    }
                }
            }

            /* If still no match, try for earliest packet possible */
            if (i == MAX_BUFFER_SIZE)
            {
                bool found     = false;
                long best_time = 0;
                long best_span = 0;
                int  besti     = 0;
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    /* check if packet starts within current chunk */
                    if (packets[i].data != null && packets[i].timestamp < (pointer_timestamp + desired_span) && (packets[i].timestamp >= pointer_timestamp))
                    {
                        if (!found || packets[i].timestamp < best_time || (packets[i].timestamp == best_time && packets[i].span > best_span))
                        {
                            best_time = packets[i].timestamp;
                            best_span = packets[i].span;
                            besti     = i;
                            found     = true;
                        }
                    }
                }
                if (found)
                {
                    i = besti;
                    /*fprintf (stderr, "incomplete: %d %d %d %d\n", packets[i].timestamp, pointer_timestamp, chunk_size, packets[i].span);*/
                }
            }

            /* If we find something */
            if (i != MAX_BUFFER_SIZE)
            {
                int offset;

                /* We (obviously) haven't lost this packet */
                lost_count = 0;

                /* In this case, 0 isn't as a valid timestamp */
                if (arrival[i] != 0)
                {
                    UpdateTimings(((int)packets[i].timestamp) - ((int)arrival[i]) - buffer_margin);
                }


                /* Copy packet */
                if (DestroyBufferCallback != null)
                {
                    packet.data = packets[i].data;
                    packet.len  = packets[i].len;
                }
                else
                {
                    if (packets[i].len > packet.len)
                    {
                        Debug.WriteLine("JitterBuffer.Get(): packet too large to fit. Size is", packets[i].len);
                    }
                    else
                    {
                        packet.len = packets[i].len;
                    }
                    for (j = 0; j < packet.len; j++)
                    {
                        packet.data[j] = packets[i].data[j];
                    }
                    /* Remove packet */
                    FreeBuffer(packets[i].data);
                }
                packets[i].data = null;
                /* Set timestamp and span (if requested) */
                offset = (int)packets[i].timestamp - (int)pointer_timestamp;
                if (start_offset != 0)
                {
                    start_offset = offset;
                }
                else if (offset != 0)
                {
                    Debug.WriteLine("JitterBuffer.Get(): discarding non-zero start_offset", offset);
                }

                packet.timestamp        = packets[i].timestamp;
                last_returned_timestamp = packet.timestamp;

                packet.span      = packets[i].span;
                packet.sequence  = packets[i].sequence;
                packet.user_data = packets[i].user_data;
                packet.len       = packets[i].len;
                /* Point to the end of the current packet */
                pointer_timestamp = packets[i].timestamp + packets[i].span;

                buffered = packet.span - desired_span;

                if (start_offset != 0)
                {
                    buffered += start_offset;
                }

                return(JITTER_BUFFER_OK);
            }


            /* If we haven't found anything worth returning */

            /*fprintf (stderr, "not found\n");*/
            lost_count++;
            /*fprintf (stderr, "m");*/
            /*fprintf (stderr, "lost_count = %d\n", lost_count);*/

            opt = ComputeOptDelay();

            /* Should we force an increase in the buffer or just do normal interpolation? */
            if (opt < 0)
            {
                /* Need to increase buffering */

                /* Shift histogram to compensate */
                ShiftTimings((short)-opt);

                packet.timestamp = pointer_timestamp;
                packet.span      = -opt;
                /* Don't move the pointer_timestamp forward */
                packet.len = 0;

                buffered = packet.span - desired_span;
                return(JITTER_BUFFER_INSERTION);
                /*pointer_timestamp -= delay_step;*/
                /*fprintf (stderr, "Forced to interpolate\n");*/
            }
            else
            {
                /* Normal packet loss */
                packet.timestamp = pointer_timestamp;

                desired_span       = RoundDown(desired_span, concealment_size);
                packet.span        = desired_span;
                pointer_timestamp += desired_span;
                packet.len         = 0;

                buffered = packet.span - desired_span;
                return(JITTER_BUFFER_MISSING);
                /*fprintf (stderr, "Normal loss\n");*/
            }
        }
Beispiel #3
0
        /// <summary>
        /// Put one packet into the jitter buffer
        /// </summary>
        /// <param name="packet"></param>
        public void Put(JitterBufferPacket packet)
        {
            int  i, j;
            bool late;

            /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/

            // Cleanup buffer (remove old packets that weren't played)
            if (!reset_state)
            {
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
                    if (packets[i].data != null && (packets[i].timestamp + packets[i].span) <= pointer_timestamp)
                    {
                        /*fprintf (stderr, "cleaned (not played)\n");*/
                        if (DestroyBufferCallback != null)
                        {
                            DestroyBufferCallback(packets[i].data);
                        }
                        else
                        {
                            FreeBuffer(packets[i].data);
                        }
                        packets[i].data = null;
                    }
                }
            }

            /*fprintf(stderr, "arrival: %d %d %d\n", packet.timestamp, next_stop, pointer_timestamp);*/
            /* Check if packet is late (could still be useful though) */
            if (!reset_state && packet.timestamp < next_stop)
            {
                UpdateTimings(((int)packet.timestamp) - ((int)next_stop) - buffer_margin);
                late = true;
            }
            else
            {
                late = false;
            }

            /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
             * used to resync. */
            if (lost_count > 20)
            {
                Reset();
            }

            /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
            if (reset_state || (packet.timestamp + packet.span + delay_step) >= pointer_timestamp)
            {
                /*Find an empty slot in the buffer*/
                for (i = 0; i < MAX_BUFFER_SIZE; i++)
                {
                    if (packets[i].data == null)
                    {
                        break;
                    }
                }

                /*No place left in the buffer, need to make room for it by discarding the oldest packet */
                if (i == MAX_BUFFER_SIZE)
                {
                    long earliest = packets[0].timestamp;
                    i = 0;
                    for (j = 1; j < MAX_BUFFER_SIZE; j++)
                    {
                        if (packets[i].data == null || packets[j].timestamp < earliest)
                        {
                            earliest = packets[j].timestamp;
                            i        = j;
                        }
                    }
                    if (DestroyBufferCallback != null)
                    {
                        DestroyBufferCallback(packets[i].data);
                    }
                    else
                    {
                        FreeBuffer(packets[i].data);
                    }
                    packets[i].data = null;
                    /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, pointer_timestamp);*/
                }

                /* Copy packet in buffer */
                if (DestroyBufferCallback != null)
                {
                    packets[i].data = packet.data;
                }
                else
                {
                    packets[i].data = AllocBuffer(packet.len);
                    for (j = 0; j < packet.len; j++)
                    {
                        packets[i].data[j] = packet.data[j];
                    }
                }
                packets[i].timestamp = packet.timestamp;
                packets[i].span      = packet.span;
                packets[i].len       = packet.len;
                packets[i].sequence  = packet.sequence;
                packets[i].user_data = packet.user_data;
                if (reset_state || late)
                {
                    arrival[i] = 0;
                }
                else
                {
                    arrival[i] = next_stop;
                }
            }
        }
Beispiel #4
0
        // Returns the length of the _encoded_ frame in bytes
        public void JitterBufferGet(short[] decodedFrame, uint timestamp, ref int startOffset)
        {
            int i;
            int ret;
            int activity = 0;

            if (jitterBuffer == null)
            {
                throw new Exception("JitterBufferPut: jitterBuffer is null!");
            }

            lock (jitterBufferLockable) {
                if (validJitterBits)
                {
                    // Try decoding last received packet
                    ret = DecoderDecodeBits(decodedFrame);
                    if (ret == 0)
                    {
                        jitter_buffer_tick(jitterBuffer);
                        return;
                    }
                    else
                    {
                        validJitterBits = false;
                    }
                }

                JitterBufferPacket packet = new JitterBufferPacket();
                packet.span      = (uint)frameSize;
                packet.timestamp = timestamp;
                // The encoded buffer must be fixed, because
                // jitter_buffer_get refers to it through packet
                unsafe
                {
                    fixed(byte *pData = &encodedJitterFrame[0])
                    {
                        fixed(int *pStartOffset = &startOffset)
                        {
                            packet.data = pData;
                            packet.span = (uint)frameSize;
                            packet.len  = 2048;
                            ret         = jitter_buffer_get(jitterBuffer, &packet, frameSize, pStartOffset);
                        }
                    }
                }
                encodedJitterFrameErrorCode = ret;
                if (ret != (int)JitterBufferRetCode.JITTER_BUFFER_OK)
                {
                    // No packet found: Packet is late or lost
                    DecoderDecodeNullBits(decodedFrame);
                }
                else
                {
                    encodedJitterFrameLength = (int)packet.len;
                    DecoderReadFrom(encodedJitterFrame, encodedJitterFrameLength);
                    /* Decode packet */
                    ret = DecoderDecodeBits(decodedFrame);
                    if (ret == 0)
                    {
                        validJitterBits = true;
                    }
                    else
                    {
                        /* Error while decoding */
                        for (i = 0; i < frameSize; i++)
                        {
                            decodedFrame[i] = 0;
                        }
                    }
                }

                GetOneCodecSetting(false, SpeexCtlCode.SPEEX_GET_ACTIVITY, ref activity);
                if (activity < 30)
                {
                    jitter_buffer_update_delay(jitterBuffer, &packet, null);
                }
                jitter_buffer_tick(jitterBuffer);
            }
        }
Beispiel #5
0
 public static extern int jitter_buffer_update_delay(IntPtr jitter, ref JitterBufferPacket packet,
                                                     [Out] out int start_offset);
Beispiel #6
0
 public static extern int jitter_buffer_get_another(IntPtr jitter, ref JitterBufferPacket packet);
Beispiel #7
0
 public static extern int jitter_buffer_get(IntPtr jitter, ref JitterBufferPacket packet, int desired_span,
                                            [Out] out int start_offset);
Beispiel #8
0
 public static extern void jitter_buffer_put(IntPtr jitter, ref JitterBufferPacket packet);