Пример #1
0
void runReceive(const char* addressOption, int port, int gap, int size, int report) {
    std::cout << "runReceive...\n";

#ifdef _WIN32
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        printf("WSAStartup failed with error %d\n", WSAGetLastError());
        return;
    }
#endif

    int sockfd, n;
    struct sockaddr_in myaddr;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myaddr.sin_port = htons(port);


    const int SAMPLES_FOR_SECOND = 1000000 / gap;
    std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n";
    const int INTERVALS_PER_30_SECONDS = 30;
    std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n";
    const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND;
    std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";
    const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report;
    std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n";

    int intervalsPerReport = report / MSEC_TO_USEC;
    if (intervalsPerReport < 1) {
        intervalsPerReport = 1;
    }
    std::cout << "intervalsPerReport:" << intervalsPerReport << "\n";
    MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS);
    MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport);

    char* inputBuffer = new char[size];
    memset(inputBuffer, 0, size);


    SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS);

    StDev stDevReportInterval;
    StDev stDev30s;
    StDev stDev;

    SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS);
    SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS);
    float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window
    bool hasStatsCalculationTime = false;

    if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
        std::cout << "bind failed\n";
        return;
    }

    quint64 last = 0; // first case
    quint64 lastReport = 0;
    
    while (true) {
    
        quint64 networkStart = usecTimestampNow();
        n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from

        quint64 networkEnd = usecTimestampNow();
        float networkElapsed = (float)(networkEnd - networkStart);

        if (n < 0) {
            std::cout << "Receive error: " << strerror(errno) << "\n";
        }

        // parse seq num
        quint16 incomingSequenceNumber = *(reinterpret_cast<quint16*>(inputBuffer));
        seqStats.sequenceNumberReceived(incomingSequenceNumber);

        if (last == 0) {
            last = usecTimestampNow();
            std::cout << "first packet received\n";
        } else {

            quint64 statsCalcultionStart = usecTimestampNow();
            quint64 now = usecTimestampNow();
            int actualGap = now - last;

            int gapDifferece = actualGap - gap;
            timeGaps.update(gapDifferece);
            timeGapsPerReport.update(gapDifferece);
            stDev.addValue(gapDifferece);
            stDev30s.addValue(gapDifferece);
            stDevReportInterval.addValue(gapDifferece);
            last = now;
            
            // track out network time and stats calculation times
            averageNetworkTime.updateAverage(networkElapsed);
            
            // for our stats calculation time, we actually delay the updating by one sample.
            // we do this so that the calculation of the average timing for the stats calculation
            // happen inside of the calculation processing. This ensures that tracking stats on
            // stats calculation doesn't side effect the remaining running time.
            if (hasStatsCalculationTime) {
                averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime);
            }

            if (now - lastReport >= (report * MSEC_TO_USEC)) {

                seqStats.pushStatsToHistory();

                std::cout << "RECEIVE gap Difference From Expected\n"
                    << "Overall:\n"
                    << "min: " << timeGaps.getMin() << " usecs, "
                    << "max: " << timeGaps.getMax() << " usecs, "
                    << "avg: " << timeGaps.getAverage() << " usecs, "
                    << "stdev: " << stDev.getStDev() << " usecs\n"
                    << "Last 30s:\n"
                    << "min: " << timeGaps.getWindowMin() << " usecs, "
                    << "max: " << timeGaps.getWindowMax() << " usecs, "
                    << "avg: " << timeGaps.getWindowAverage() << " usecs, "
                    << "stdev: " << stDev30s.getStDev() << " usecs\n"
                    << "Last report interval:\n"
                    << "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
                    << "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
                    << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
                    << "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
                    << "Average Execution Times Last 30s:\n"
                    << "    network: " << averageNetworkTime.getAverage() << " usecs average\n"
                    << "      stats: " << averageStatsCalcultionTime.getAverage() << " usecs average"
                    << "\n";
                stDevReportInterval.reset();

                if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
                    stDev30s.reset();
                }

                PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow();
                PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval();

                std::cout << "RECEIVE Packet Stats\n"
                    << "Overall:\n"
                    << "lost: " << seqStats.getLost() << ", "
                    << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n"
                    << "Last 30s:\n"
                    << "lost: " << packetStatsLast30s._lost << ", "
                    << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n"
                    << "Last report interval:\n"
                    << "lost: " << packetStatsLastReportInterval._lost << ", "
                    << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n"
                    << "\n\n";

                lastReport = now;
            }

            quint64 statsCalcultionEnd = usecTimestampNow();

            lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart);
            if (lastStatsCalculationTime > LARGE_STATS_TIME) {
                qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime;
            }
            hasStatsCalculationTime = true;
        }
    }
    delete[] inputBuffer;

#ifdef _WIN32
    WSACleanup();
#endif
}
Пример #2
0
void runSend(const char* addressOption, int port, int gap, int size, int report) {
    std::cout << "runSend...\n";

#ifdef _WIN32
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        printf("WSAStartup failed with error %d\n", WSAGetLastError());
        return;
    }
#endif

    int sockfd;
    struct sockaddr_in servaddr;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, addressOption, &servaddr.sin_addr);
    servaddr.sin_port = htons(port);

    const int SAMPLES_FOR_SECOND = 1000000 / gap;
    std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n";
    const int INTERVALS_PER_30_SECONDS = 30;
    std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n";
    const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND;
    std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";
    const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report;
    std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n";

    int intervalsPerReport = report / MSEC_TO_USEC;
    if (intervalsPerReport < 1) {
        intervalsPerReport = 1;
    }
    std::cout << "intervalsPerReport:" << intervalsPerReport << "\n";
    MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS);
    MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport);

    char* outputBuffer = new char[size];
    memset(outputBuffer, 0, size);

    quint16 outgoingSequenceNumber = 0;


    StDev stDevReportInterval;
    StDev stDev30s;
    StDev stDev;
    
    SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS);
    SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS);
    float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window
    bool hasStatsCalculationTime = false;

    quint64 last = usecTimestampNow();
    quint64 lastReport = 0;

    while (true) {

        quint64 now = usecTimestampNow();
        int actualGap = now - last;


        if (actualGap >= gap) {

            // pack seq num
            memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16));

            quint64 networkStart = usecTimestampNow();
            int n = sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
            quint64 networkEnd = usecTimestampNow();
            float networkElapsed = (float)(networkEnd - networkStart);

            if (n < 0) {
                std::cout << "Send error: " << strerror(errno) << "\n";
            }
            outgoingSequenceNumber++;

            quint64 statsCalcultionStart = usecTimestampNow();

            int gapDifferece = actualGap - gap;

            timeGaps.update(gapDifferece);
            timeGapsPerReport.update(gapDifferece);
            stDev.addValue(gapDifferece);
            stDev30s.addValue(gapDifferece);
            stDevReportInterval.addValue(gapDifferece);
            last = now;
            
            // track out network time and stats calculation times
            averageNetworkTime.updateAverage(networkElapsed);
            
            // for our stats calculation time, we actually delay the updating by one sample.
            // we do this so that the calculation of the average timing for the stats calculation
            // happen inside of the calculation processing. This ensures that tracking stats on
            // stats calculation doesn't side effect the remaining running time.
            if (hasStatsCalculationTime) {
                averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime);
            }

            if (now - lastReport >= (report * MSEC_TO_USEC)) {

                std::cout << "\n"
                    << "SEND gap Difference From Expected\n"
                    << "Overall:\n"
                    << "min: " << timeGaps.getMin() << " usecs, "
                    << "max: " << timeGaps.getMax() << " usecs, "
                    << "avg: " << timeGaps.getAverage() << " usecs, "
                    << "stdev: " << stDev.getStDev() << " usecs\n"
                    << "Last 30s:\n"
                    << "min: " << timeGaps.getWindowMin() << " usecs, "
                    << "max: " << timeGaps.getWindowMax() << " usecs, "
                    << "avg: " << timeGaps.getWindowAverage() << " usecs, "
                    << "stdev: " << stDev30s.getStDev() << " usecs\n"
                    << "Last report interval:\n"
                    << "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
                    << "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
                    << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
                    << "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
                    << "Average Execution Times Last 30s:\n"
                    << "    network: " << averageNetworkTime.getAverage() << " usecs average\n"
                    << "      stats: " << averageStatsCalcultionTime.getAverage() << " usecs average"
                    << "\n";

                stDevReportInterval.reset();
                if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
                    stDev30s.reset();
                }

                lastReport = now;
            }

            quint64 statsCalcultionEnd = usecTimestampNow();
            lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart);
            if (lastStatsCalculationTime > LARGE_STATS_TIME) {
                qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime;
            }
            hasStatsCalculationTime = true;

        }
    }
    delete[] outputBuffer;

#ifdef _WIN32
    WSACleanup();
#endif
}
Пример #3
0
void *receiveAudioViaUDP(void *args) {
    AudioRecThreadStruct *threadArgs = (AudioRecThreadStruct *) args;
    AudioData *sharedAudioData = threadArgs->sharedAudioData;
    
    int16_t *receivedData = new int16_t[PACKET_LENGTH_SAMPLES];
    ssize_t receivedBytes;
    
    //  Init Jitter timer values 
    timeval previousReceiveTime, currentReceiveTime = {};
    gettimeofday(&previousReceiveTime, NULL);
    gettimeofday(&currentReceiveTime, NULL);
    
    int totalPacketsReceived = 0;
    
    stdev.reset();
    
    if (LOG_SAMPLE_DELAY) {
        
        char *directory = new char[50];
        char *filename = new char[50];
        
        sprintf(directory, "%s/Desktop/echo_tests", getenv("HOME"));
        
        mkdir(directory, S_IRWXU | S_IRWXG | S_IRWXO);
        sprintf(filename, "%s/%ld.csv", directory, previousReceiveTime.tv_sec);
        
        logFile.open(filename, std::ios::out);
        
        delete[] directory;
        delete[] filename;
    }
        
    while (!stopAudioReceiveThread) {
        if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) {
            
            gettimeofday(&currentReceiveTime, NULL);
            totalPacketsReceived++;

            if (LOG_SAMPLE_DELAY) {
                // write time difference (in microseconds) between packet receipts to file
                double timeDiff = diffclock(&previousReceiveTime, &currentReceiveTime);
                logFile << timeDiff << std::endl;
            }
            
            double tDiff = diffclock(&previousReceiveTime, &currentReceiveTime);
            //printf("tDiff %4.1f\n", tDiff);
            //  Discard first few received packets for computing jitter (often they pile up on start)    
            if (totalPacketsReceived > 3) stdev.addValue(tDiff);
            if (stdev.getSamples() > 500) {
                sharedAudioData->measuredJitter = stdev.getStDev();
                //printf("Avg: %4.2f, Stdev: %4.2f\n", stdev.getAverage(), sharedAudioData->measuredJitter);
                stdev.reset();
            }
            
            AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer;
            
            
            if (!ringBuffer->isStarted()) {
                packetsReceivedThisPlayback++;
             }
            else {
                //printf("Audio packet received at %6.0f\n", usecTimestampNow()/1000);
            }
            if (packetsReceivedThisPlayback == 1) gettimeofday(&firstPlaybackTimer, NULL);

            ringBuffer->parseData(receivedData, PACKET_LENGTH_BYTES);

            previousReceiveTime = currentReceiveTime;
        }
    }
    
    pthread_exit(0);
}