如何在具有可变长度的RTP会话中(使用jrtplib)发送和接收数据包?

时间:2018-12-02 12:41:32

标签: c++ networking rtp

最近我已经安装了jrtplib(C ++),并且试图了解如何从数据包中接收数据,将其保存到一个缓冲区中,并在传输结束时将整个数据保存到一个文件中。到目前为止,我已经知道了这一点(大部分来自库提供的示例文件)。 这是服务器:

using namespace jrtplib;
int main(void)
{
    #ifdef RTP_SOCKETTYPE_WINSOCK
     WSADATA dat;
     WSAStartup(MAKEWORD(2,2),&dat);
    #endif // RTP_SOCKETTYPE_WINSOCK

    RTPSession sess;
    uint16_t portbase = 5000;

    RTPUDPv4TransmissionParams transparams;
    RTPSessionParams sessparams;

    // IMPORTANT: The local timestamp unit MUST be set, otherwise
    // RTCP Sender Report info will be calculated wrong
    // In this case, we'll be sending 10 samples each second, so we'll
    // put the timestamp unit to (1.0/10.0)
    sessparams.SetOwnTimestampUnit(1.0/10.0);

    sessparams.SetAcceptOwnPackets(true);
    transparams.SetPortbase(portbase);
    int status;
    status = sess.Create(sessparams,&transparams);
    checkerror(status);

    bool done = false;
    std::cout << "Waiting for some data...\n";

    RTPTime startTime = RTPTime::CurrentTime();
    std::vector<int8_t> data;

    while(!done)
    {
        std::cout << "Waiting for some data...\n";
        sess.BeginDataAccess();

        // check incoming packets
        if (sess.GotoFirstSourceWithData())
        {
            do
            {
                RTPPacket *pack;

                while ((pack = sess.GetNextPacket()) != NULL)
                {
                    // You can examine the data here
                    data.push_back(*(pack->GetPayloadData()));

                    // we don't longer need the packet, so
                    // we'll delete it
                    sess.DeletePacket(pack);
                }
            } while (sess.GotoNextSourceWithData());
        }

        sess.EndDataAccess();

        #ifndef RTP_SUPPORT_THREAD
         status = sess.Poll();
         checkerror(status);
        #endif // RTP_SUPPORT_THREAD

        RTPTime::Wait(RTPTime(0.020));
        RTPTime t = RTPTime::CurrentTime();
        t -= startTime;
        if ( t > RTPTime(100.0) ) {
            done = true;
        }
    }

    sess.BYEDestroy(RTPTime(10,0),0,0);

    #ifdef RTP_SOCKETTYPE_WINSOCK
     WSACleanup();
    #endif // RTP_SOCKETTYPE_WINSOCK

    FILE *file = fopen("d:/file.png", "w");
    if (file == NULL){
        printf("Could not open file for saving!\n");
        exit(1);
    }

    for (int i  = 0; i < data.size(); i++){
        fwrite(&data[i], sizeof(data[i]), 1, file);
    }

    return 0;
}

这是客户:

using namespace jrtplib;
int main()
{
    #ifdef RTP_SOCKETTYPE_WINSOCK
     WSADATA dat;
     WSAStartup(MAKEWORD(2,2),&dat); 
    #endif 


    FILE *file = fopen("c:/file.png", "rb");
    if (file == NULL){
        printf("Could not open file!\n");
        exit(1);
    }

    fseek(file, 0L, SEEK_END);
    auto fsize = ftell(file);
    fseek(file, 0L, SEEK_SET);
    printf("File size: %ld\n", fsize);
    auto *buffer = (unsigned char*) malloc(fsize);
    fread(buffer, fsize, 1, file);
    fclose(file);
    file = NULL;

    uint16_t portbase = 5000;
    uint16_t destport = 5000;

    std::string ipstr = "192.168.1.164";
    uint32_t destip = inet_addr(ipstr.c_str());    
    if (destip == INADDR_NONE)
    {
        std::cerr << "Bad IP address specified" << std::endl;
        return -1;
    }

    destip = ntohl(destip);

    /* Parameters for the transmission component */
    RTPUDPv4TransmissionParams transparams;
    transparams.SetPortbase(portbase);

    RTPSessionParams sessparams;
    sessparams.SetOwnTimestampUnit(1.0/10.0);
    sessparams.SetAcceptOwnPackets(true);

    // Give general options for session
    RTPSession sess;
    int status = sess.Create(sessparams,&transparams);
    checkerror(status);

    sess.SetDefaultPayloadType(96);
    sess.SetDefaultMark(false);
    sess.SetDefaultTimestampIncrement(160);

    /* Specify to which destinations rtp and rtcp data should be sent. */
    RTPIPv4Address addr(destip,destport);
    status = sess.AddDestination(addr);
    checkerror(status);

    RTPTime delay(0.020);
    RTPTime starttime = RTPTime::CurrentTime();

    int transmitted = 0;

    auto *p = buffer;
    bool done = false;
    while(!done) {
        // send the packet
        status = sess.SendPacket(p, sizeof(*p));
        checkerror(status);
        transmitted += sizeof(*p);
        p++;

        RTPTime::Wait(delay);
        RTPTime t = RTPTime::CurrentTime();
        t -= starttime;

        if (t > RTPTime(100.0)){
            *buffer = 0;
            status = sess.SendPacket(p, sizeof(*p));
            transmitted += sizeof(*p);
            done = true;
        }
        printf("\nSent %d bytes\n", transmitted);
    }

    sess.BYEDestroy(RTPTime(10,0),0,0);

    #ifdef RTP_SOCKETTYPE_WINSOCK
     WSACleanup();
    #endif 
    return 0;
}   

我已经成功发送了小文本文件,但是只有在我知道文件的确切大小的情况下,我才修改了服务器以使其停止在接收到的字节的确切数目上。第二件事是,我总是一次收到1个字节的向量到1个字节的向量:int8_t的向量。现在我只知道我一次发送一个字节。 问题是:

  • 当我知道传输完成时(从客户端和服务器端)如何停止传输?

  • 如何发送长度不同的数据,如果不知道将发送多少数据,该如何接收?这样,我认为我无法将所有数据保存到向量中,因此,如果缓冲区大小不断增加,应该如何将其存储在内存中?

我知道RTP用于实时传输(我打算在以后使用),但是现在我只想掌握网络的基本概念。

0 个答案:

没有答案