OBS-rtmp源码剖析之rtmp客户端通信介绍(三)

这里主要接着上一篇继续网络连接部分的讲解。主要包括函数SocksNegotiate()、RTMP_ReconnectStream()、RTMP_ConnectStream()、RTMP_ToggleStream()、RTMP_DeleteStream()、RTMP_GetNextMediaPacket()和RTMP_ClientPacket()
1、socket协议协商

static int
SocksNegotiate(RTMP *r)
{
    unsigned long addr;
    struct sockaddr_storage service;
    socklen_t addrlen = 0;
    int socket_error = 0;
    memset(&service, 0, sizeof(service));

    add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, 0, &socket_error);

    // not doing IPv6 socks
    if (service.ss_family == AF_INET6)
        return FALSE;

    addr = htonl((*(struct sockaddr_in *)&service).sin_addr.s_addr);

    {
        char packet[] =
        {
            4, 1,           /* SOCKS 4, connect */
            (r->Link.port >> 8) & 0xFF,
            (r->Link.port) & 0xFF,
            (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
            (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
            0
        };              /* NULL terminate */

        WriteN(r, packet, sizeof packet);

        if (ReadN(r, packet, 8) != 8)
            return FALSE;

        if (packet[0] == 0 && packet[1] == 90)
        {
            return TRUE;
        }
        else
        {
            RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
            return FALSE;
        }
    }
}

2、连接rtmp流

int
RTMP_ConnectStream(RTMP *r, int seekTime)
{
    RTMPPacket packet = { 0 };

    /* seekTime was already set by SetupStream / SetupURL.
     * This is only needed by ReconnectStream.
     */
    if (seekTime > 0)
        r->Link.seekTime = seekTime;

    r->m_mediaChannel = 0;

    while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
    {
        if (RTMPPacket_IsReady(&packet))
        {
            if (!packet.m_nBodySize)
                continue;
            if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
                    (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
                    (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
            {
                RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
                RTMPPacket_Free(&packet);
                continue;
            }

            RTMP_ClientPacket(r, &packet);
            RTMPPacket_Free(&packet);
        }
    }

    return r->m_bPlaying;
}

2、重连rtmp流操作

int
RTMP_ReconnectStream(RTMP *r, int seekTime, int streamIdx)
{
    RTMP_DeleteStream(r, streamIdx);

    RTMP_SendCreateStream(r);

    return RTMP_ConnectStream(r, seekTime);
}

3、暂停rtmp流操作

int
RTMP_ToggleStream(RTMP *r)
{
    int res;

    if (!r->m_pausing)
    {
        if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
            r->m_read.status = 0;

        res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
        if (!res)
            return res;

        r->m_pausing = 1;
        sleep(1);
    }
    res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
    r->m_pausing = 3;
    return res;
}

4、删除rtmp流操作

void
RTMP_DeleteStream(RTMP *r, int streamIdx)
{
    if (r->m_stream_id < 0)
        return;

    r->m_bPlaying = FALSE;

    if ((r->Link.protocol & RTMP_FEATURE_WRITE))
        SendFCUnpublish(r, streamIdx);

    SendDeleteStream(r, r->m_stream_id);
    r->m_stream_id = -1;
}

5、获取下一个媒体包

int
RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
{
    int bHasMediaPacket = 0;

    while (!bHasMediaPacket && RTMP_IsConnected(r)
            && RTMP_ReadPacket(r, packet))
    {
        if (!RTMPPacket_IsReady(packet))
        {
            continue;
        }

        bHasMediaPacket = RTMP_ClientPacket(r, packet);

        if (!bHasMediaPacket)
        {
            RTMPPacket_Free(packet);
        }
        else if (r->m_pausing == 3)
        {
            if (packet->m_nTimeStamp <= r->m_mediaStamp)
            {
                bHasMediaPacket = 0;
#ifdef _DEBUG
                RTMP_Log(RTMP_LOGDEBUG,
                         "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
                         packet->m_packetType, packet->m_nBodySize,
                         packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
                         r->m_mediaStamp);
#endif
                RTMPPacket_Free(packet);
                continue;
            }
            r->m_pausing = 0;
        }
    }

    if (bHasMediaPacket)
        r->m_bPlaying = TRUE;
    else if (r->m_sb.sb_timedout && !r->m_pausing)
        r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
                          r->m_channelTimestamp[r->m_mediaChannel] : 0;

    return bHasMediaPacket;
}

6、处理rtmp客户端收到的包

int
RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
{
    int bHasMediaPacket = 0;
    switch (packet->m_packetType)
    {
    case RTMP_PACKET_TYPE_CHUNK_SIZE:
        /* chunk size */
        HandleChangeChunkSize(r, packet);
        break;

    case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
        /* bytes read report */
        RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
        break;

    case RTMP_PACKET_TYPE_CONTROL:
        /* ctrl */
        HandleCtrl(r, packet);
        break;

    case RTMP_PACKET_TYPE_SERVER_BW:
        /* server bw */
        HandleServerBW(r, packet);
        break;

    case RTMP_PACKET_TYPE_CLIENT_BW:
        /* client bw */
        HandleClientBW(r, packet);
        break;

    case RTMP_PACKET_TYPE_AUDIO:
        /* audio data */
        /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
        HandleAudio(r, packet);
        bHasMediaPacket = 1;
        if (!r->m_mediaChannel)
            r->m_mediaChannel = packet->m_nChannel;
        if (!r->m_pausing)
            r->m_mediaStamp = packet->m_nTimeStamp;
        break;

    case RTMP_PACKET_TYPE_VIDEO:
        /* video data */
        /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
        HandleVideo(r, packet);
        bHasMediaPacket = 1;
        if (!r->m_mediaChannel)
            r->m_mediaChannel = packet->m_nChannel;
        if (!r->m_pausing)
            r->m_mediaStamp = packet->m_nTimeStamp;
        break;

    case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
        /* flex stream send */
        RTMP_Log(RTMP_LOGDEBUG,
                 "%s, flex stream send, size %u bytes, not supported, ignoring",
                 __FUNCTION__, packet->m_nBodySize);
        break;

    case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
        /* flex shared object */
        RTMP_Log(RTMP_LOGDEBUG,
                 "%s, flex shared object, size %u bytes, not supported, ignoring",
                 __FUNCTION__, packet->m_nBodySize);
        break;

    case RTMP_PACKET_TYPE_FLEX_MESSAGE:
        /* flex message */
    {
        RTMP_Log(RTMP_LOGDEBUG,
                 "%s, flex message, size %u bytes, not fully supported",
                 __FUNCTION__, packet->m_nBodySize);
        /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */

        /* some DEBUG code */
#if 0
        RTMP_LIB_AMFObject obj;
        int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
        if(nRes < 0)
        {
            RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
            /*return; */
        }

        obj.Dump();
#endif

        if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
            bHasMediaPacket = 2;
        break;
    }
    case RTMP_PACKET_TYPE_INFO:
        /* metadata (notify) */
        RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
                 packet->m_nBodySize);
        if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
            bHasMediaPacket = 1;
        break;

    case RTMP_PACKET_TYPE_SHARED_OBJECT:
        RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
                 __FUNCTION__);
        break;

    case RTMP_PACKET_TYPE_INVOKE:
        /* invoke */
        RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
                 packet->m_nBodySize);
        /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */

        if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
            bHasMediaPacket = 2;
        break;

    case RTMP_PACKET_TYPE_FLASH_VIDEO:
    {
        /* go through FLV packets and handle metadata packets */
        unsigned int pos = 0;
        uint32_t nTimeStamp = packet->m_nTimeStamp;

        while (pos + 11 < packet->m_nBodySize)
        {
            uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1);  /* size without header (11) and prevTagSize (4) */

            if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
            {
                RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
                break;
            }
            if (packet->m_body[pos] == 0x12)
            {
                HandleMetadata(r, packet->m_body + pos + 11, dataSize);
            }
            else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
            {
                nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
                nTimeStamp |= (packet->m_body[pos + 7] << 24);
            }
            pos += (11 + dataSize + 4);
        }
        if (!r->m_pausing)
            r->m_mediaStamp = nTimeStamp;

        /* FLV tag(s) */
        /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
        bHasMediaPacket = 1;
        break;
    }
    default:
        RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
                 packet->m_packetType);
#ifdef _DEBUG
        RTMP_LogHex(RTMP_LOGDEBUG, (const uint8_t*)packet->m_body, packet->m_nBodySize);
#endif
    }

    return bHasMediaPacket;
}

猜你喜欢

转载自blog.csdn.net/tong5956/article/details/81480043