media/webrtc/trunk/webrtc/modules/audio_coding/neteq/rtp.c
author Phil Ringnalda <philringnalda@gmail.com>
Tue, 11 Jun 2013 21:39:02 -0700
changeset 146232 73b1a6ee8d12742d55b08e07d11860107b9243f9
parent 146210 92fc4bf7a9e96fe79af999ba0dbda55983b9bf2d
child 150239 6063eaf3633fec74f5289571c7dd2ef36ab07074
permissions -rw-r--r--
Back out 7e5522d403c1 and 92fc4bf7a9e9 (bug 880879) for Android test failures CLOSED TREE

/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * RTP related functions.
 */

#include "rtp.h"

#include "typedefs.h" /* to define endianness */

#include "neteq_error_codes.h"

int WebRtcNetEQ_RTPPayloadInfo(WebRtc_Word16* pw16_Datagram, int i_DatagramLen,
                               RTPPacket_t* RTPheader)
{
    int i_P, i_X, i_CC, i_startPosition;
    int i_IPver;
    int i_extlength = -1; /* Default value is there is no extension */
    int i_padlength = 0; /* Default value if there is no padding */

    if (i_DatagramLen < 12)
    {
        return RTP_TOO_SHORT_PACKET;
    }

#ifdef WEBRTC_BIG_ENDIAN
    i_IPver = (((WebRtc_UWord16) (pw16_Datagram[0] & 0xC000)) >> 14); /* Extract the version */
    i_P = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x2000)) >> 13); /* Extract the P bit */
    i_X = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x1000)) >> 12); /* Extract the X bit */
    i_CC = ((WebRtc_UWord16) (pw16_Datagram[0] >> 8) & 0xF); /* Get the CC number */
    RTPheader->payloadType = pw16_Datagram[0] & 0x7F; /* Get the coder type	*/
    RTPheader->seqNumber = pw16_Datagram[1]; /* Get the sequence number	*/
    RTPheader->timeStamp = ((((WebRtc_UWord32) ((WebRtc_UWord16) pw16_Datagram[2])) << 16)
        | (WebRtc_UWord16) (pw16_Datagram[3])); /* Get timestamp */
    RTPheader->ssrc = (((WebRtc_UWord32) pw16_Datagram[4]) << 16)
        + (((WebRtc_UWord32) pw16_Datagram[5])); /* Get the SSRC */

    if (i_X == 1)
    {
        /* Extension header exists. Find out how many WebRtc_Word32 it consists of. */
        i_extlength = pw16_Datagram[7 + 2 * i_CC];
    }
    if (i_P == 1)
    {
        /* Padding exists. Find out how many bytes the padding consists of. */
        if (i_DatagramLen & 0x1)
        {
            /* odd number of bytes => last byte in higher byte */
            i_padlength = (((WebRtc_UWord16) pw16_Datagram[i_DatagramLen >> 1]) >> 8);
        }
        else
        {
            /* even number of bytes => last byte in lower byte */
            i_padlength = ((pw16_Datagram[(i_DatagramLen >> 1) - 1]) & 0xFF);
        }
    }
#else /* WEBRTC_LITTLE_ENDIAN */
    i_IPver = (((WebRtc_UWord16) (pw16_Datagram[0] & 0xC0)) >> 6); /* Extract the IP version */
    i_P = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x20)) >> 5); /* Extract the P bit */
    i_X = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x10)) >> 4); /* Extract the X bit */
    i_CC = (WebRtc_UWord16) (pw16_Datagram[0] & 0xF); /* Get the CC number */
    RTPheader->payloadType = (pw16_Datagram[0] >> 8) & 0x7F; /* Get the coder type */
    RTPheader->seqNumber = (((((WebRtc_UWord16) pw16_Datagram[1]) >> 8) & 0xFF)
        | (((WebRtc_UWord16) (pw16_Datagram[1] & 0xFF)) << 8)); /* Get the packet number */
    RTPheader->timeStamp = ((((WebRtc_UWord16) pw16_Datagram[2]) & 0xFF) << 24)
        | ((((WebRtc_UWord16) pw16_Datagram[2]) & 0xFF00) << 8)
        | ((((WebRtc_UWord16) pw16_Datagram[3]) >> 8) & 0xFF)
        | ((((WebRtc_UWord16) pw16_Datagram[3]) & 0xFF) << 8); /* Get timestamp */
    RTPheader->ssrc = ((((WebRtc_UWord16) pw16_Datagram[4]) & 0xFF) << 24)
        | ((((WebRtc_UWord16) pw16_Datagram[4]) & 0xFF00) << 8)
        | ((((WebRtc_UWord16) pw16_Datagram[5]) >> 8) & 0xFF)
        | ((((WebRtc_UWord16) pw16_Datagram[5]) & 0xFF) << 8); /* Get the SSRC */

    if (i_X == 1)
    {
        /* Extension header exists. Find out how many WebRtc_Word32 it consists of. */
        i_extlength = (((((WebRtc_UWord16) pw16_Datagram[7 + 2 * i_CC]) >> 8) & 0xFF)
            | (((WebRtc_UWord16) (pw16_Datagram[7 + 2 * i_CC] & 0xFF)) << 8));
    }
    if (i_P == 1)
    {
        /* Padding exists. Find out how many bytes the padding consists of. */
        if (i_DatagramLen & 0x1)
        {
            /* odd number of bytes => last byte in higher byte */
            i_padlength = (pw16_Datagram[i_DatagramLen >> 1] & 0xFF);
        }
        else
        {
            /* even number of bytes => last byte in lower byte */
            i_padlength = (((WebRtc_UWord16) pw16_Datagram[(i_DatagramLen >> 1) - 1]) >> 8);
        }
    }
#endif

    i_startPosition = 12 + 4 * (i_extlength + 1) + 4 * i_CC;
    RTPheader->payload = &pw16_Datagram[i_startPosition >> 1];
    RTPheader->payloadLen = i_DatagramLen - i_startPosition - i_padlength;
    RTPheader->starts_byte1 = 0;

    if ((i_IPver != 2) || (RTPheader->payloadLen <= 0) || (RTPheader->payloadLen >= 16000)
        || (i_startPosition < 12) || (i_startPosition > i_DatagramLen))
    {
        return RTP_CORRUPT_PACKET;
    }

    return 0;
}

#ifdef NETEQ_RED_CODEC

int WebRtcNetEQ_RedundancySplit(RTPPacket_t* RTPheader[], int i_MaximumPayloads,
                                int *i_No_Of_Payloads)
{
    const WebRtc_Word16 *pw16_data = RTPheader[0]->payload; /* Pointer to the data */
    WebRtc_UWord16 uw16_offsetTimeStamp = 65535, uw16_secondPayload = 65535;
    int i_blockLength, i_k;
    int i_discardedBlockLength = 0;
    int singlePayload = 0;

#ifdef WEBRTC_BIG_ENDIAN
    if ((pw16_data[0] & 0x8000) == 0)
    {
        /* Only one payload in this packet*/
        singlePayload = 1;
        /* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
        i_blockLength = -4;
        RTPheader[0]->payloadType = ((((WebRtc_UWord16)pw16_data[0]) & 0x7F00) >> 8);
    }
    else
    {
        /* Discard all but the two last payloads. */
        while (((pw16_data[2] & 0x8000) != 0) &&
            (pw16_data<((RTPheader[0]->payload)+((RTPheader[0]->payloadLen+1)>>1))))
        {
            i_discardedBlockLength += (4+(((WebRtc_UWord16)pw16_data[1]) & 0x3FF));
            pw16_data+=2;
        }
        if (pw16_data>=(RTPheader[0]->payload+((RTPheader[0]->payloadLen+1)>>1)))
        {
            return RED_SPLIT_ERROR2; /* Error, we are outside the packet */
        }
        singlePayload = 0; /* the packet contains more than one payload */
        uw16_secondPayload = ((((WebRtc_UWord16)pw16_data[0]) & 0x7F00) >> 8);
        RTPheader[0]->payloadType = ((((WebRtc_UWord16)pw16_data[2]) & 0x7F00) >> 8);
        uw16_offsetTimeStamp = ((((WebRtc_UWord16)pw16_data[0]) & 0xFF) << 6) +
        ((((WebRtc_UWord16)pw16_data[1]) & 0xFC00) >> 10);
        i_blockLength = (((WebRtc_UWord16)pw16_data[1]) & 0x3FF);
    }
#else /* WEBRTC_LITTLE_ENDIAN */
    if ((pw16_data[0] & 0x80) == 0)
    {
        /* Only one payload in this packet */
        singlePayload = 1;
        /* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
        i_blockLength = -4;
        RTPheader[0]->payloadType = (((WebRtc_UWord16) pw16_data[0]) & 0x7F);
    }
    else
    {
        /* Discard all but the two last payloads. */
        while (((pw16_data[2] & 0x80) != 0) && (pw16_data < ((RTPheader[0]->payload)
            + ((RTPheader[0]->payloadLen + 1) >> 1))))
        {
            i_discardedBlockLength += (4 + ((((WebRtc_UWord16) pw16_data[1]) & 0x3) << 8)
                + ((((WebRtc_UWord16) pw16_data[1]) & 0xFF00) >> 8));
            pw16_data += 2;
        }
        if (pw16_data >= (RTPheader[0]->payload + ((RTPheader[0]->payloadLen + 1) >> 1)))
        {
            return RED_SPLIT_ERROR2; /* Error, we are outside the packet */;
        }
        singlePayload = 0; /* the packet contains more than one payload */
        uw16_secondPayload = (((WebRtc_UWord16) pw16_data[0]) & 0x7F);
        RTPheader[0]->payloadType = (((WebRtc_UWord16) pw16_data[2]) & 0x7F);
        uw16_offsetTimeStamp = ((((WebRtc_UWord16) pw16_data[0]) & 0xFF00) >> 2)
            + ((((WebRtc_UWord16) pw16_data[1]) & 0xFC) >> 2);
        i_blockLength = ((((WebRtc_UWord16) pw16_data[1]) & 0x3) << 8)
            + ((((WebRtc_UWord16) pw16_data[1]) & 0xFF00) >> 8);
    }
#endif

    if (i_MaximumPayloads < 2 || singlePayload == 1)
    {
        /* Reject the redundancy; or no redundant payload present. */
        for (i_k = 1; i_k < i_MaximumPayloads; i_k++)
        {
            RTPheader[i_k]->payloadType = -1;
            RTPheader[i_k]->payloadLen = 0;
        }

        /* update the pointer for the main data */
        pw16_data = &pw16_data[(5 + i_blockLength) >> 1];
        RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
        RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
            - i_discardedBlockLength;
        RTPheader[0]->payload = pw16_data;

        *i_No_Of_Payloads = 1;

    }
    else
    {
        /* Redundancy accepted, put the redundancy in second RTPheader. */
        RTPheader[1]->payloadType = uw16_secondPayload;
        RTPheader[1]->payload = &pw16_data[5 >> 1];
        RTPheader[1]->starts_byte1 = 5 & 0x1;
        RTPheader[1]->seqNumber = RTPheader[0]->seqNumber;
        RTPheader[1]->timeStamp = RTPheader[0]->timeStamp - uw16_offsetTimeStamp;
        RTPheader[1]->ssrc = RTPheader[0]->ssrc;
        RTPheader[1]->payloadLen = i_blockLength;

        /* Modify first RTP packet, so that it contains the main data. */
        RTPheader[0]->payload = &pw16_data[(5 + i_blockLength) >> 1];
        RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
        RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
            - i_discardedBlockLength;

        /* Clear the following payloads. */
        for (i_k = 2; i_k < i_MaximumPayloads; i_k++)
        {
            RTPheader[i_k]->payloadType = -1;
            RTPheader[i_k]->payloadLen = 0;
        }

        *i_No_Of_Payloads = 2;
    }
    return 0;
}

#endif