static void* avdeccServerThread(void *arg) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC); while (avdeccRunning) { if (!openavbAvdeccInitialize()) { AVB_LOG_ERROR("Failed to initialize AVDECC"); break; } AVB_LOG_DEBUG("AVDECC Initialized"); if (!openavbAvdeccStart()) { AVB_LOG_ERROR("Failed to start AVDECC"); openavbAvdeccStop(); break; } if (!openavbAvdeccMsgServerOpen()) { AVB_LOG_ERROR("Failed to start AVDECC Server"); openavbAvdeccStop(); break; } else { AVB_LOG_INFO("AVDECC Started"); avdeccInitSucceeded = TRUE; // Wait until AVDECC is finished. while (avdeccRunning) { openavbAvdeccMsgSrvrService(); } openavbAvdeccMsgServerClose(); } // Stop AVDECC AVB_LOG_DEBUG("AVDECC Stopping"); openavbAvdeccStop(); AVB_LOG_INFO("AVDECC Stopped"); } // Shutdown AVDECC openavbAvdeccCleanup(); avdeccRunning = FALSE; AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return NULL; }
openavbAvdeccMsgStateType_t openavbAVDECCGetStreamingState(openavb_aem_descriptor_stream_io_t *pDescriptorStream, U16 configIdx) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC); // Sanity tests. if (!pDescriptorStream) { AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return OPENAVB_AVDECC_MSG_UNKNOWN; } if (!pDescriptorStream->stream) { AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor stream"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return OPENAVB_AVDECC_MSG_UNKNOWN; } if (!pDescriptorStream->stream->client) { AVB_LOG_DEBUG("openavbAVDECCGetStreamingState Invalid stream client pointer"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return OPENAVB_AVDECC_MSG_UNKNOWN; } // Return the current state. AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return pDescriptorStream->stream->client->lastReportedState; }
int openavbEptClntOpenSrvrConnection(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); struct sockaddr_un server; server.sun_family = AF_UNIX; snprintf(server.sun_path, UNIX_PATH_MAX, AVB_ENDPOINT_UNIX_PATH); int h = socket(AF_UNIX, SOCK_STREAM, 0); if (h < 0) { AVB_LOGF_DEBUG("Failed to open socket: %s", strerror(errno)); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return AVB_ENDPOINT_HANDLE_INVALID; } AVB_LOGF_DEBUG("Connecting to %s", server.sun_path); int rslt = connect(h, (struct sockaddr*)&server, sizeof(struct sockaddr_un)); if (rslt < 0) { AVB_LOGF_DEBUG("Failed to connect socket: %s", strerror(errno)); socketClose(h); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return AVB_ENDPOINT_HANDLE_INVALID; } AVB_LOG_DEBUG("Connected to endpoint"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return h; }
static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); if (!msg) { AVB_LOG_ERROR("Receiving message; invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return FALSE; } bool ret = FALSE; switch (msg->type) { case OPENAVB_AVDECC_MSG_VERSION_REQUEST: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_REQUEST"); ret = openavbAvdeccMsgSrvrHndlVerRqstFromClient(avdeccMsgHandle); break; case OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY"); ret = openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(avdeccMsgHandle, msg->params.clientInitIdentify.friendly_name, msg->params.clientInitIdentify.talker); break; case OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID"); ret = openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(avdeccMsgHandle, msg->params.c2sTalkerStreamID.sr_class, msg->params.c2sTalkerStreamID.stream_src_mac, ntohs(msg->params.c2sTalkerStreamID.stream_uid), msg->params.c2sTalkerStreamID.stream_dest_mac, ntohs(msg->params.c2sTalkerStreamID.stream_vlan_id)); break; case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION"); ret = openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeNotification.current_state); break; default: AVB_LOG_ERROR("Unexpected message received at server"); break; } AVB_LOGF_VERBOSE("Message handled, ret=%d", ret); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return ret; }
// Open a rawsock for TX or RX void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK); AVB_LOGF_DEBUG("Open, rx=%d, tx=%d, ethertype=%x size=%d, num=%d", rx_mode, tx_mode, ethertype, frame_size, num_frames); baseRawsockOpen(&rawsock->base, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames); if (tx_mode) { AVB_LOG_DEBUG("pcap rawsock transmit mode will bypass FQTSS"); } rawsock->handle = 0; // Get info about the network device if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) { AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname); free(rawsock); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK); return NULL; } // Deal with frame size. if (rawsock->base.frameSize == 0) { // use interface MTU as max frames size, if none specified rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN; } else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) { AVB_LOG_ERROR("Creating rawsock; requested frame size exceeds MTU"); free(rawsock); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK); return NULL; } char errbuf[PCAP_ERRBUF_SIZE]; rawsock->handle = open_pcap_dev(ifname, rawsock->base.frameSize, errbuf); if (!rawsock->handle) { AVB_LOGF_ERROR("Cannot open device %s: %s", ifname, errbuf); free(rawsock); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK); return NULL; } // fill virtual functions table rawsock_cb_t *cb = &rawsock->base.cb; cb->close = pcapRawsockClose; cb->getTxFrame = pcapRawsockGetTxFrame; cb->txFrameReady = pcapRawsockTxFrameReady; cb->send = pcapRawsockSend; cb->getRxFrame = pcapRawsockGetRxFrame; cb->rxMulticast = pcapRawsockRxMulticast; cb->rxParseHdr = pcapRawsockRxParseHdr; AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK); return rawsock; }
bool openavbAVDECCGetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC); // Sanity tests. if (!pDescriptorStreamOutput) { AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid descriptor"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return FALSE; } if (!pTalkerStreamInfo) { AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid streaminfo"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return FALSE; } if (!pDescriptorStreamOutput->stream) { AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid StreamInput descriptor stream"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return FALSE; } // Get the destination MAC Address. if (!pDescriptorStreamOutput->stream->dest_addr.mac || memcmp(pDescriptorStreamOutput->stream->dest_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) { AVB_LOG_DEBUG("openavbAVDECCGetTalkerStreamInfo Invalid stream dest_addr"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return FALSE; } memcpy(pTalkerStreamInfo->stream_dest_mac, pDescriptorStreamOutput->stream->dest_addr.mac, ETH_ALEN); AVB_LOGF_DEBUG("Talker stream_dest_mac: " ETH_FORMAT, ETH_OCTETS(pTalkerStreamInfo->stream_dest_mac)); // Get the Stream ID. if (!pDescriptorStreamOutput->stream->stream_addr.mac || memcmp(pDescriptorStreamOutput->stream->stream_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) { AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid stream stream_addr"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return FALSE; } memcpy(pTalkerStreamInfo->stream_id, pDescriptorStreamOutput->stream->stream_addr.mac, ETH_ALEN); U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6; *(U16 *)(pStreamUID) = htons(pDescriptorStreamOutput->stream->stream_uid); AVB_LOGF_DEBUG("Talker stream_id: " ETH_FORMAT "/%u", ETH_OCTETS(pTalkerStreamInfo->stream_id), (((U16) pTalkerStreamInfo->stream_id[6]) << 8) | (U16) pTalkerStreamInfo->stream_id[7]); // Get the VLAN ID. pTalkerStreamInfo->stream_vlan_id = pDescriptorStreamOutput->stream->vlan_id; AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return TRUE; }
bool openavbAdpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP) { AVB_TRACE_ENTRY(AVB_TRACE_ADP); hdr_info_t hdr; #ifndef UBUNTU // This is the normal case for most of our supported platforms rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_8021Q, ADP_FRAME_LEN, ADP_NUM_BUFFERS); #else rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS); #endif txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS); if (txSock && rxSock && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr)) && ether_aton_r(ADP_PROTOCOL_ADDR, &adpAddr) && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&adpAddr))) { if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_ADP_AVTP_SUBTYPE | 0x80)) { AVB_LOG_DEBUG("RX AVTP Subtype not supported"); } memset(&hdr, 0, sizeof(hdr_info_t)); hdr.shost = ADDR_PTR(&intfAddr); hdr.dhost = ADDR_PTR(&adpAddr); hdr.ethertype = ETHERTYPE_AVTP; if (vlanID != 0 || vlanPCP != 0) { hdr.vlan = TRUE; hdr.vlan_pcp = vlanPCP; hdr.vlan_vid = vlanID; AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid); } if (!openavbRawsockTxSetHdr(txSock, &hdr)) { AVB_LOG_ERROR("TX socket Header Failure"); openavbAdpCloseSocket(); AVB_TRACE_EXIT(AVB_TRACE_ADP); return false; } AVB_TRACE_EXIT(AVB_TRACE_ADP); return true; } AVB_LOG_ERROR("Invalid socket"); openavbAdpCloseSocket(); AVB_TRACE_EXIT(AVB_TRACE_ADP); return false; }
/*********************************************** * Signal handler - used to respond to signals. * Allows graceful cleanup. */ static void openavbTLSigHandler(int signal) { AVB_TRACE_ENTRY(AVB_TRACE_HOST); if (signal == SIGINT) { AVB_LOG_INFO("Host shutting down"); bRunning = FALSE; } else if (signal == SIGUSR1) { AVB_LOG_DEBUG("Waking up streaming thread"); } else { AVB_LOG_ERROR("Unexpected signal"); } AVB_TRACE_EXIT(AVB_TRACE_HOST); }
static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); if (!msg) { AVB_LOG_ERROR("Receiving message; invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } bool ret = FALSE; switch (msg->type) { case OPENAVB_ENDPOINT_TALKER_REGISTER: AVB_LOGF_DEBUG("TalkerRegister from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrRegisterStream(h, &msg->streamID, msg->params.talkerRegister.destAddr, &msg->params.talkerRegister.tSpec, msg->params.talkerRegister.srClass, msg->params.talkerRegister.srRank, msg->params.talkerRegister.latency); break; case OPENAVB_ENDPOINT_LISTENER_ATTACH: AVB_LOGF_DEBUG("ListenerAttach from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrAttachStream(h, &msg->streamID, msg->params.listenerAttach.lsnrDecl); break; case OPENAVB_ENDPOINT_CLIENT_STOP: AVB_LOGF_DEBUG("Stop from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrStopStream(h, &msg->streamID); break; case OPENAVB_ENDPOINT_VERSION_REQUEST: AVB_LOG_DEBUG("Version request from client"); ret = openavbEptSrvrHndlVerRqstFromClient(h); break; default: AVB_LOG_ERROR("Unexpected message received at server"); break; } AVB_LOGF_VERBOSE("Message handled, ret=%d", ret); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return ret; }
void openavbAVDECCPauseStream(openavb_aem_descriptor_stream_io_t *pDescriptor, bool bPause) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC); // Sanity test. if (!pDescriptor) { AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid descriptor"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } if (!pDescriptor->stream) { AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid StreamInput descriptor stream"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } if (!pDescriptor->stream->client) { AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid stream client pointer"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) { if (bPause) { // If the client is not running (or already paused), ignore this command. if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) { AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not running"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } // Send the request to the client. if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) { AVB_LOG_ERROR("Error requesting Listener change to Paused"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } AVB_LOG_INFO("Listener state change from Running to Paused requested"); } else { // If the client is not paused, ignore this command. if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) { AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not paused"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } // Send the request to the client. if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) { AVB_LOG_ERROR("Error requesting Listener change to Running"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } AVB_LOG_INFO("Listener state change from Paused to Running requested"); } } else if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) { if (bPause) { // If the client is not running (or already paused), ignore this command. if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) { AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not running"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } // Send the request to the client. if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) { AVB_LOG_ERROR("Error requesting Talker change to Paused"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } AVB_LOG_INFO("Talker state change from Running to Paused requested"); } else { // If the client is not paused, ignore this command. if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) { AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not paused"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } // Send the request to the client. if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) { AVB_LOG_ERROR("Error requesting Talker change to Running"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC); return; } AVB_LOG_INFO("Talker state change from Paused to Running requested"); } } else { AVB_LOG_ERROR("openavbAVDECCPauseStream unsupported descriptor"); } AVB_TRACE_EXIT(AVB_TRACE_AVDECC); }
// Get a buffer from the ring to use for TX U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; // Displays only warning when buffer busy after second try int bBufferBusyReported = 0; if (!VALID_TX_RAWSOCK(rawsock) || len == NULL) { AVB_LOG_ERROR("Getting TX frame; bad arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if (rawsock->buffersOut >= rawsock->frameCount) { AVB_LOG_ERROR("Getting TX frame; too many TX buffers in use"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Get pointer to next framebuf. volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); // And pointer to portion of buffer to be filled with frame 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 send mode, we want to see TP_STATUS_AVAILABLE while (pHdr->tp_status != TP_STATUS_AVAILABLE) { switch (pHdr->tp_status) { case TP_STATUS_SEND_REQUEST: case TP_STATUS_SENDING: if (blocking) { #if 0 // We should be able to poll on the socket to wait for the buffer to // be ready, but it doesn't work (at least on 2.6.37). // Keep this code, because it may work on newer kernels // poll until tx buffer is ready struct pollfd pfd; pfd.fd = rawsock->sock; pfd.events = POLLWRNORM; pfd.revents = 0; int ret = poll(&pfd, 1, -1); if (ret < 0 && errno != EINTR) { AVB_LOGF_DEBUG("getting TX frame; poll failed: %s", strerror(errno)); } #else // Can't poll, so sleep instead to avoid tight loop if(0 == bBufferBusyReported) { if(!rawsock->txOutOfBuffer) { // Display this info only once just to let know that something like this happened AVB_LOGF_INFO("Getting TX frame (sock=%d): TX buffer busy", rawsock->sock); } ++rawsock->txOutOfBuffer; ++rawsock->txOutOfBufferCyclic; } else if(1 == bBufferBusyReported) { //Display this warning if buffer was busy more than once because it might influence late/lost AVB_LOGF_WARNING("Getting TX frame (sock=%d): TX buffer busy after usleep(50) verify if there are any lost/late frames", rawsock->sock); } ++bBufferBusyReported; usleep(50); #endif } else { AVB_LOG_DEBUG("Non-blocking, return NULL"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } break; case TP_STATUS_WRONG_FORMAT: default: pHdr->tp_status = TP_STATUS_AVAILABLE; break; } } // Remind client how big the frame buffer is if (len) *len = rawsock->base.frameSize; // increment indexes to point to next buffer if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // increment the count of buffers held by client rawsock->buffersOut += 1; // warn if too many are out if (rawsock->buffersOut >= (rawsock->frameCount * 4)/5) { AVB_LOGF_WARNING("Getting TX frame; consider increasing buffers: count=%d, out=%d", rawsock->frameCount, rawsock->buffersOut); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return (U8*)pBuffer; }
/* Talker callback comes from endpoint, to indicate when listeners * come and go. We may need to start or stop the talker thread. */ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle, AVBStreamID_t *streamID, char *ifname, U8 destAddr[], openavbSrpLsnrDeclSubtype_t lsnrDecl, U8 srClass, U32 classRate, U16 vlanID, U8 priority, U16 fwmark) { AVB_TRACE_ENTRY(AVB_TRACE_TL); tl_state_t *pTLState = TLHandleListGet(endpointHandle); talker_data_t *pTalkerData = pTLState->pPvtTalkerData; if (!pTLState) { AVB_LOG_WARNING("Unable to get talker from endpoint handle."); return; } // If not a talker, ignore this callback. if (pTLState->cfg.role != AVB_ROLE_TALKER) { AVB_LOG_DEBUG("Ignoring Talker callback"); return; } AVB_LOGF_DEBUG("%s streaming=%d, lsnrDecl=%d", __FUNCTION__, pTLState->bStreaming, lsnrDecl); openavb_tl_cfg_t *pCfg = &pTLState->cfg; if (!pTLState->bStreaming) { if (lsnrDecl == openavbSrp_LDSt_Ready || lsnrDecl == openavbSrp_LDSt_Ready_Failed) { // Save the data provided by endpoint/SRP if (!pCfg->ifname[0]) { strncpy(pTalkerData->ifname, ifname, IFNAMSIZ); } else { strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ); } memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t)); memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN); pTalkerData->srClass = srClass; pTalkerData->classRate = classRate; pTalkerData->vlanID = vlanID; pTalkerData->vlanPCP = priority; pTalkerData->fwmark = fwmark; // We should start streaming AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID)); talkerStartStream(pTLState); } else if (lsnrDecl == openavbSrp_LDSt_Stream_Info) { // Stream information is available does NOT mean listener is ready. Stream not started yet. if (!pCfg->ifname[0]) { strncpy(pTalkerData->ifname, ifname, IFNAMSIZ); } else { strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ); } memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t)); memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN); pTalkerData->srClass = srClass; pTalkerData->classRate = classRate; pTalkerData->vlanID = vlanID; pTalkerData->vlanPCP = priority; pTalkerData->fwmark = fwmark; } } else { if (lsnrDecl != openavbSrp_LDSt_Ready && lsnrDecl != openavbSrp_LDSt_Ready_Failed) { // Nobody is listening any more AVB_LOGF_INFO("Stopping stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID)); talkerStopStream(pTLState); } } // Let the AVDECC Msg server know our current stream ID, in case it was updated by MAAP. if (pTLState->avdeccMsgHandle != AVB_AVDECC_MSG_HANDLE_INVALID) { if (!openavbAvdeccMsgClntTalkerStreamID(pTLState->avdeccMsgHandle, pTalkerData->srClass, pTalkerData->streamID.addr, pTalkerData->streamID.uniqueID, pTalkerData->destAddr, pTalkerData->vlanID)) { AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed"); } } AVB_TRACE_EXIT(AVB_TRACE_TL); }
void openavbAcmpSMControllerStateMachine() { AVB_TRACE_ENTRY(AVB_TRACE_ACMP); openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state openavb_acmp_sm_controller_state_t state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses. ACMP_SM_LOCK(); while (bRunning) { switch (state) { case OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING: AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING"); openavbAcmpSMControllerVars.rcvdResponse = FALSE; // Calculate timeout for inflight commands // Start is a arbitrary large time out. struct timespec timeout; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout); timeout.tv_sec += 60; // At most will timeout after 60 seconds // Look for soonest inflight command timeout openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) { timeout.tv_sec = pInflight->timer.tv_sec; timeout.tv_nsec = pInflight->timer.tv_nsec; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } ACMP_SM_UNLOCK(); U32 timeoutMSec = 0; struct timespec now; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now); timeoutMSec = openavbTimeUntilMSec(&now, &timeout); SEM_ERR_T(err); SEM_TIMEDWAIT(openavbAcmpSMControllerSemaphore, timeoutMSec, err); ACMP_SM_LOCK(); if (!SEM_IS_ERR_NONE(err)) { if (SEM_IS_ERR_TIMEOUT(err)) { struct timespec now; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now); // Look for a timed out inflight command openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) { // Found a timed out command state = OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT; pInflightActive = pInflight; break; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } } } else { if (openavbAcmpSMControllerVars.doTerminate) { bRunning = FALSE; } else if (openavbAcmpSMControllerVars.rcvdResponse && memcmp(pRcvdCmdResp->controller_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) { // Look for a corresponding inflight command openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if (pRcvdCmdResp->sequence_id == pInflight->command.sequence_id && pRcvdCmdResp->message_type == pInflight->command.message_type + 1) { // Found a corresponding command state = OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE; pInflightActive = pInflight; break; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } } break; case OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT: { AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT"); if (pInflightActive) { if (pInflightActive->retried) { openavbAcmpSMController_removeInflight(&pInflightActive->command); } else { openavbAcmpSMController_txCommand(pInflightActive->command.message_type, &pInflightActive->command, TRUE); } } pInflightActive = NULL; state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; } break; case OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE: { AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE"); if (pInflightActive) { openavbAcmpSMController_cancelTimeout(pRcvdCmdResp); openavbAcmpSMController_processResponse(pRcvdCmdResp); openavbAcmpSMController_removeInflight(pRcvdCmdResp); } pInflightActive = NULL; state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; } break; } } } ACMP_SM_UNLOCK(); AVB_TRACE_EXIT(AVB_TRACE_ACMP); }
/* SRP tells us about a listener peer (Listener Ready or Failed) */ openavbRC strmAttachCb(void* pv, openavbSrpLsnrDeclSubtype_t lsnrDecl) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); openavbRC rc = OPENAVB_FAILURE; clientStream_t *ps = (clientStream_t*)pv; AVB_LOGF_INFO("SRP talker callback uid=%d: lsnrDecl=%x", ps->streamID.uniqueID, lsnrDecl); if (lsnrDecl == openavbSrp_LDSt_Ready || lsnrDecl == openavbSrp_LDSt_Ready_Failed) { // Somebody is listening - get ready to stream if (ps->fwmark != INVALID_FWMARK) { AVB_LOG_DEBUG("attach callback: already setup queues"); rc = OPENAVB_SUCCESS; } else { AVB_LOG_DEBUG("Attach callback: setting up queues for streaming"); rc = openavbSrpGetClassParams(ps->srClass, &ps->priority, &ps->vlanID, &ps->classRate); if (IS_OPENAVB_SUCCESS(rc)) { ps->fwmark = openavbQmgrAddStream(ps->srClass, ps->classRate, ps->tSpec.maxIntervalFrames, ps->tSpec.maxFrameSize); if (ps->fwmark == INVALID_FWMARK) { AVB_LOG_ERROR("Error in attach callback: unable to setup stream queues"); rc = OPENAVB_FAILURE; } else { rc = OPENAVB_SUCCESS; } } else { AVB_LOG_ERROR("Error in attach callback: unable to get class params"); rc = OPENAVB_FAILURE; } } } else { // Nobody listening if (ps->fwmark != INVALID_FWMARK) { AVB_LOG_DEBUG("Attach callback: tearing down queues"); openavbQmgrRemoveStream(ps->fwmark); ps->fwmark = INVALID_FWMARK; } rc = OPENAVB_SUCCESS; } if (IS_OPENAVB_SUCCESS(rc)) { openavbEptSrvrNotifyTlkrOfSrpCb(ps->clientHandle, &ps->streamID, x_cfg.ifname, ps->destAddr, lsnrDecl, ps->srClass, ps->classRate, ps->vlanID, ps->priority, ps->fwmark); rc = OPENAVB_SUCCESS; } AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return rc; }