// Release a TX frame, and mark it as ready to send bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_TX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Marking TX frame ready; invalid argument"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return FALSE; } if (timeNsec) { IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in ring_rawsock"); } volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize); AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p szFrame=%d, len=%d", pBuffer, pHdr, rawsock->base.frameSize, len); assert(len <= rawsock->bufferSize); pHdr->tp_len = len; pHdr->tp_status = TP_STATUS_SEND_REQUEST; rawsock->buffersReady += 1; if (rawsock->buffersReady >= rawsock->frameCount) { AVB_LOG_WARNING("All buffers in ready/unsent state, calling send"); ringRawsockSend(pvRawsock); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return TRUE; }
bool halTimeGetLocaltime(U64 *localTime64) { AVB_TRACE_ENTRY(AVB_TRACE_TIME); if (igb_get_wallclock(igb_dev, localTime64, NULL ) > 0) { IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Failed to get wallclock time"); AVB_TRACE_EXIT(AVB_TRACE_TIME); return FALSE; } AVB_TRACE_EXIT(AVB_TRACE_TIME); return TRUE; }
bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec) { pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock; int ret = -1; if (timeNsec) { IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in pcap_rawsock"); } if (rawsock) { ret = pcap_sendpacket(rawsock->handle, pBuffer, len); if (ret == -1) { AVB_LOGF_ERROR("pcap_sendpacket failed: %s", pcap_geterr(rawsock->handle)); } } return ret == 0; }
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; }
// Get a RX frame U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_RX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Getting RX frame; invalid arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if (rawsock->buffersOut >= rawsock->frameCount) { AVB_LOG_ERROR("Too many RX buffers in use"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Get pointer to active buffer in ring volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize; AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p", rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut, pBuffer, pHdr); // Check if buffer ready for user // In receive mode, we want TP_STATUS_USER flag set if ((pHdr->tp_status & TP_STATUS_USER) == 0) { struct timespec ts, *pts = NULL; struct pollfd pfd; // Use poll to wait for "ready to read" condition // Poll even if our timeout is 0 - to catch the case where // kernel is writing to the wrong slot (see below.) if (timeout != OPENAVB_RAWSOCK_BLOCK) { ts.tv_sec = timeout / MICROSECONDS_PER_SECOND; ts.tv_nsec = (timeout % MICROSECONDS_PER_SECOND) * NANOSECONDS_PER_USEC; pts = &ts; } pfd.fd = rawsock->sock; pfd.events = POLLIN; pfd.revents = 0; int ret = ppoll(&pfd, 1, pts, NULL); if (ret < 0) { if (errno != EINTR) { AVB_LOGF_ERROR("Getting RX frame; poll failed: %s", strerror(errno)); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pfd.revents & POLLIN) == 0) { // timeout AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pHdr->tp_status & TP_STATUS_USER) == 0) { // Hmmm, this is unexpected. poll indicated that the // socket was ready to read, but the slot in the TX ring // that we're looking for the kernel to fill isn't filled. // If there aren't any RX buffers held by the application, // we can try to fix this sticky situation... if (rawsock->buffersOut == 0) { // Scan forward through the RX ring, and look for a // buffer that's ready for us to read. The kernel has // a bad habit of not starting at the beginning of the // ring when the listener process is restarted. int nSkipped = 0; while((pHdr->tp_status & TP_STATUS_USER) == 0) { // Move to next slot in ring. // (Increment buffer/block indexes) if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Adjust pHdr, pBuffer to point to the new slot pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); pBuffer = (U8*)pHdr + rawsock->bufHdrSize; // If we've scanned all the way around the ring, bail out. if (++nSkipped > rawsock->frameCount) { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } // We found a slot that's ready. Hopefully, we're good now. AVB_LOGF_WARNING("Getting RX frame; skipped %d empty slots (rawsock=%p)", nSkipped, rawsock); } else { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } } AVB_LOGF_VERBOSE("Buffer status=0x%4.4lx", (unsigned long)pHdr->tp_status); if (pHdr->tp_status & TP_STATUS_COPY) { AVB_LOG_WARNING("Frame too big for receive buffer"); } // Check the "losing" flag. That indicates that the ring is full, // and the kernel had to toss some frames. There is no "winning" flag. if ((pHdr->tp_status & TP_STATUS_LOSING)) { if (!rawsock->bLosing) { AVB_LOG_WARNING("Getting RX frame; mmap buffers full"); rawsock->bLosing = TRUE; } } else { rawsock->bLosing = FALSE; } // increment indexes for next time if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Remember that the client has another buffer rawsock->buffersOut += 1; if (pHdr->tp_snaplen < pHdr->tp_len) { #if (AVB_LOG_LEVEL >= AVB_LOG_LEVEL_VERBOSE) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_LOG_BUFFER(AVB_LOG_LEVEL_VERBOSE, (const U8 *) pBuffer + (pHdr->tp_mac - rawsock->bufHdrSize), pHdr->tp_len, 16); #else IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); #endif ringRawsockRelRxFrame(rawsock, (U8*)pBuffer); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Return pointer to the buffer and length *offset = pHdr->tp_mac - rawsock->bufHdrSize; *len = pHdr->tp_snaplen; AVB_LOGF_VERBOSE("Good RX frame (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return (U8*)pBuffer; }