// This callback will be called for each AVB transmit interval. Commonly this will be // 4000 or 8000 times per second. bool openavbIntfLoggerTxCB(media_q_t *pMediaQ) { AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL); if (pMediaQ) { pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo; if (!pPvtData) { AVB_LOG_ERROR("Private interface module data not allocated."); return FALSE; } media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ); if (pMediaQItem) { U32 dataLen = avbLogGetMsg(pMediaQItem->pPubData, pMediaQItem->itemSize); if (dataLen) { pMediaQItem->dataLen = dataLen; openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); openavbMediaQHeadPush(pMediaQ); AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return TRUE; } else { openavbMediaQHeadUnlock(pMediaQ); } } else { AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return FALSE; // Media queue full } } AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return FALSE; }
bool openavbIntfMpeg2tsGstTxCB(media_q_t *pMediaQ) { AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL); if (!pMediaQ) { AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return FALSE; } pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo; if (!pPvtData) { AVB_LOG_ERROR("Private interface module data not allocated."); return FALSE; } if (!pPvtData->appsink) { AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return FALSE; } media_q_item_t *pMediaQItem; GstAlBuf *txBuf; while (g_atomic_int_get(&pPvtData->nWaiting) > 0) { // Get a mediaQItem to hold the buffered data pMediaQItem = openavbMediaQHeadLock(pMediaQ); if (!pMediaQItem) { IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full"); break; } /* Retrieve the buffer */ txBuf = gst_al_pull_buffer(pPvtData->appsink); if (txBuf) { g_atomic_int_add(&pPvtData->nWaiting, -1); if ( GST_AL_BUF_SIZE(txBuf) > pMediaQItem->itemSize ) { AVB_LOGF_ERROR("GStreamer buffer too large (size=%d) for mediaQ item (dataLen=%d)", GST_AL_BUF_SIZE(txBuf), pMediaQItem->itemSize); pMediaQItem->dataLen = 0; openavbMediaQHeadUnlock(pMediaQ); } else { memcpy(pMediaQItem->pPubData, GST_AL_BUF_DATA(txBuf), GST_AL_BUF_SIZE(txBuf)); pMediaQItem->dataLen = GST_AL_BUF_SIZE(txBuf); openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); openavbMediaQHeadPush(pMediaQ); } gst_al_buffer_unref(txBuf); } else { AVB_LOG_ERROR("GStreamer buffer pull failed"); // assume the pipeline is empty g_atomic_int_set(&pPvtData->nWaiting, 0); // abandon the mediaq item pMediaQItem->dataLen = 0; openavbMediaQHeadUnlock(pMediaQ); // and get out break; } } AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return TRUE; }
// This callback is called when acting as a listener. bool openavbIntfViewerRxCB(media_q_t *pMediaQ) { AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL); if (pMediaQ) { pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo; if (!pPvtData) { AVB_LOG_ERROR("Private interface module data not allocated."); return FALSE; } media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp); if (pMediaQItem) { // The skip countdown allow the viewer modes to set a number of packets to ignore // after logging to reduce or eliminate the logging from affecting the stats. if (pPvtData->skipCountdown) pPvtData->skipCountdown--; if (pMediaQItem->dataLen && !pPvtData->skipCountdown) { pPvtData->servicedCount++; if (pPvtData->viewType == VIEWER_MODE_DETAIL) { U32 avtpTimestamp; U64 avtpTimestampTime; bool avtpTimestampValid; U32 nowTimestamp; U64 nowTimestampTime; bool nowTimestampValid; U64 nowTime; S32 lateNS = 0; U64 gapNS = 0; avtpTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime); avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); nowTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime); nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime); if (avtpTimestampValid && nowTimestampValid) { lateNS = nowTimestampTime - avtpTimestampTime; if (lateNS > pPvtData->maxLateNS) { pPvtData->maxLateNS = lateNS; } pPvtData->accumLateNS += lateNS; if (pPvtData->servicedCount > 1) { gapNS = nowTime - pPvtData->prevNowTime; if (gapNS > pPvtData->maxGapNS) { pPvtData->maxGapNS = gapNS; } pPvtData->accumGapNS += gapNS; } pPvtData->prevNowTime = nowTime; if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) { S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount; S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "****************************", LOG_RT_DATATYPE_CONST_STR, NULL); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Packets: %u", LOG_RT_DATATYPE_U32, &pPvtData->servicedCount); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "AVTP Timestamp: %u NS", LOG_RT_DATATYPE_U32, &avtpTimestamp); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Now Timestamp: %u NS", LOG_RT_DATATYPE_U32, &nowTimestamp); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late: %d NS", LOG_RT_DATATYPE_S32, &lateNS); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Avg: %d NS", LOG_RT_DATATYPE_S32, &lateAvg); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Max: %d NS", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap: %u NS", LOG_RT_DATATYPE_U32, &gapNS); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Avg: %u NS", LOG_RT_DATATYPE_U32, &gapAvg); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Max: %u NS", LOG_RT_DATATYPE_U32, &pPvtData->maxGapNS); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Data length: %u", LOG_RT_DATATYPE_U32, &pMediaQItem->dataLen); pPvtData->accumLateNS = 0; pPvtData->maxLateNS = 0; pPvtData->accumGapNS = 0; pPvtData->maxGapNS = 0; pPvtData->prevNowTime = 0; pPvtData->servicedCount = 0; pPvtData->skipCountdown = 10; } } } else if (pPvtData->viewType == VIEWER_MODE_MAPPING_AWARE) { } else if (pPvtData->viewType == VIEWER_MODE_AVTP_TIMESTAMP) { U64 avtpTimestampTime; bool avtpTimestampValid; S32 deltaNS = 0; avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); if (avtpTimestampValid) { if (pPvtData->servicedCount > 1) { deltaNS = avtpTimestampTime - pPvtData->prevAvtpTimestampTime; if (deltaNS > pPvtData->maxAvtpDeltaNS) { pPvtData->maxAvtpDeltaNS = deltaNS; } pPvtData->accumAvtpDeltaNS += deltaNS; if (pPvtData->avgForJitter != 0) { S32 deltaJitter = pPvtData->avgForJitter - deltaNS; if (deltaJitter < 0) deltaJitter = -deltaJitter; pPvtData->jitter += (1.0/16.0) * ((float)deltaJitter - pPvtData->jitter); } } pPvtData->prevAvtpTimestampTime = avtpTimestampTime; if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) { S32 deltaAvg = pPvtData->accumAvtpDeltaNS / (pPvtData->servicedCount - 1); U32 jitter = (U32)(pPvtData->jitter); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta: %d NS ", LOG_RT_DATATYPE_S32, &deltaNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Avg: %d NS ", LOG_RT_DATATYPE_S32, &deltaAvg); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxAvtpDeltaNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter); pPvtData->accumAvtpDeltaNS = 0; pPvtData->maxAvtpDeltaNS = 0; pPvtData->servicedCount = 0; pPvtData->prevAvtpTimestampTime = 0; pPvtData->skipCountdown = 10; pPvtData->jitter = 0.0; pPvtData->avgForJitter = deltaAvg; } } } else if (pPvtData->viewType == VIEWER_MODE_LATENCY) { U64 avtpTimestampTime; bool avtpTimestampValid; U64 nowTimestampTime; bool nowTimestampValid; S32 lateNS = 0; avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); if (avtpTimestampValid && nowTimestampValid) { lateNS = nowTimestampTime - avtpTimestampTime; if (lateNS > pPvtData->maxLateNS) { pPvtData->maxLateNS = lateNS; } pPvtData->accumLateNS += lateNS; if (pPvtData->avgForJitter != 0) { S32 lateJitter = pPvtData->avgForJitter - lateNS; if (lateJitter < 0) lateJitter = -lateJitter; pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter); } if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) { S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount; U32 jitter = (U32)(pPvtData->jitter); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Latency: %d NS ", LOG_RT_DATATYPE_S32, &lateNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter); pPvtData->accumLateNS = 0; pPvtData->maxLateNS = 0; pPvtData->servicedCount = 0; pPvtData->skipCountdown = 10; pPvtData->jitter = 0.0; pPvtData->avgForJitter = lateAvg; } } } else if (pPvtData->viewType == VIEWER_MODE_SELECTIVE_TIMESTAMP) { } else if (pPvtData->viewType == VIEWER_MODE_LATE) { U64 avtpTimestampTime; bool avtpTimestampValid; U64 nowTimestampTime; bool nowTimestampValid; S32 lateNS = 0; avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime); nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime); nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime); if (avtpTimestampValid && nowTimestampValid) { lateNS = nowTimestampTime - avtpTimestampTime; if (lateNS > pPvtData->maxLateNS) { pPvtData->maxLateNS = lateNS; } pPvtData->accumLateNS += lateNS; if (pPvtData->avgForJitter != 0) { S32 lateJitter = pPvtData->avgForJitter - lateNS; if (lateJitter < 0) lateJitter = -lateJitter; pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter); } if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) { S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount; U32 jitter = (U32)(pPvtData->jitter); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Late: %d NS ", LOG_RT_DATATYPE_S32, &lateNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter); pPvtData->accumLateNS = 0; pPvtData->maxLateNS = 0; pPvtData->servicedCount = 0; pPvtData->skipCountdown = 10; pPvtData->jitter = 0.0; pPvtData->avgForJitter = lateAvg; } } } else if (pPvtData->viewType == VIEWER_MODE_GAP) { U64 nowTime; U64 gapNS = 0; CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime); if (pPvtData->servicedCount > 1) { gapNS = nowTime - pPvtData->prevNowTime; if (gapNS > pPvtData->maxGapNS) { pPvtData->maxGapNS = gapNS; } pPvtData->accumGapNS += gapNS; if (pPvtData->avgForJitter != 0) { S32 gapJitter = pPvtData->avgForJitter - gapNS; if (gapJitter < 0) gapJitter = -gapJitter; pPvtData->jitter += (1.0/16.0) * ((float)gapJitter - pPvtData->jitter); } } pPvtData->prevNowTime = nowTime; if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) { S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1); U32 jitter = (U32)(pPvtData->jitter); AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Gap: %d NS ", LOG_RT_DATATYPE_S32, &gapNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Avg: %d NS ", LOG_RT_DATATYPE_S32, &gapAvg); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxGapNS); AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter); pPvtData->accumGapNS = 0; pPvtData->maxGapNS = 0; pPvtData->prevNowTime = 0; pPvtData->servicedCount = 0; pPvtData->skipCountdown = 10; pPvtData->jitter = 0.0; pPvtData->avgForJitter = gapAvg; } } } openavbMediaQTailPull(pMediaQ); } } AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL); return TRUE; }