void talkerStopStream(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_TL); if (!pTLState) { AVB_LOG_ERROR("Invalid TLState"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } talker_data_t *pTalkerData = pTLState->pPvtTalkerData; if (!pTalkerData) { AVB_LOG_ERROR("Invalid listener data"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } void *rawsock = NULL; if (pTalkerData->avtpHandle) { rawsock = ((avtp_stream_t*)pTalkerData->avtpHandle)->rawsock; } openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes); openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames); // openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, 0); // Can't calulate at this time openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, openavbAvtpBytes(pTalkerData->avtpHandle)); AVB_LOGF_INFO("TX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", late=%" PRIu64 ", bytes=%" PRIu64 ", TXOutOfBuffs=%ld", STREAMID_ARGS(&pTalkerData->streamID), openavbTalkerGetStat(pTLState, TL_STAT_TX_CALLS), openavbTalkerGetStat(pTLState, TL_STAT_TX_FRAMES), openavbTalkerGetStat(pTLState, TL_STAT_TX_LATE), openavbTalkerGetStat(pTLState, TL_STAT_TX_BYTES), openavbRawsockGetTXOutOfBuffers(rawsock) ); if (pTLState->bStreaming) { openavbAvtpShutdown(pTalkerData->avtpHandle); pTLState->bStreaming = FALSE; } AVB_TRACE_EXIT(AVB_TRACE_TL); }
bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID) { tl_state_t *pTLState = TLHandleListGet(hnd); openavb_tl_cfg_t *pCfg = &pTLState->cfg; listener_data_t *pListenerData = pTLState->pPvtListenerData; strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ); memcpy(&pListenerData->streamID.addr, &pCfg->stream_addr.mac->ether_addr_octet, ETH_ALEN); pListenerData->streamID.uniqueID = pCfg->stream_uid; memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN); pListenerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames; pListenerData->tSpec.maxFrameSize = pCfg->max_frame_size; AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pListenerData->destAddr)); AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID)); listenerStartStream(pTLState); return TRUE; }
void listenerStopStream(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_TL); if (!pTLState) { AVB_LOG_ERROR("Invalid TLState"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } listener_data_t *pListenerData = pTLState->pPvtListenerData; if (!pListenerData) { AVB_LOG_ERROR("Invalid listener data"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } openavbListenerAddStat(pTLState, TL_STAT_RX_CALLS, pListenerData->nReportCalls); openavbListenerAddStat(pTLState, TL_STAT_RX_FRAMES, pListenerData->nReportFrames); openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, openavbAvtpLost(pListenerData->avtpHandle)); openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, openavbAvtpBytes(pListenerData->avtpHandle)); AVB_LOGF_INFO("RX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", lost=%" PRIu64 ", bytes=%" PRIu64, STREAMID_ARGS(&pListenerData->streamID), openavbListenerGetStat(pTLState, TL_STAT_RX_CALLS), openavbListenerGetStat(pTLState, TL_STAT_RX_FRAMES), openavbListenerGetStat(pTLState, TL_STAT_RX_LOST), openavbListenerGetStat(pTLState, TL_STAT_RX_BYTES)); if (pTLState->bStreaming) { openavbAvtpShutdownListener(pListenerData->avtpHandle); pTLState->bStreaming = FALSE; } AVB_TRACE_EXIT(AVB_TRACE_TL); }
// Called from openavbTLThreadFn() which is started from openavbTLRun() void openavbTLRunListener(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_TL); if (!pTLState) { AVB_LOG_ERROR("Invalid TLState"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } openavb_tl_cfg_t *pCfg = &pTLState->cfg; pTLState->pPvtListenerData = calloc(1, sizeof(listener_data_t)); if (!pTLState->pPvtListenerData) { AVB_LOG_WARNING("Failed to allocate listener data."); return; } AVBStreamID_t streamID; memset(&streamID, 0, sizeof(streamID)); memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN); streamID.uniqueID = pCfg->stream_uid; AVB_LOGF_INFO("Attach "STREAMID_FORMAT, STREAMID_ARGS(&streamID)); // Create Stats Mutex { MUTEX_ATTR_HANDLE(mta); MUTEX_ATTR_INIT(mta); MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT); MUTEX_ATTR_SET_NAME(mta, "TLStatsMutex"); MUTEX_CREATE_ERR(); MUTEX_CREATE(pTLState->statsMutex, mta); MUTEX_LOG_ERR("Could not create/initialize 'TLStatsMutex' mutex"); } // Tell endpoint to listen for our stream. // If there is a talker, we'll get callback (above.) pTLState->bConnected = openavbTLRunListenerInit(pTLState->endpointHandle, &streamID); if (pTLState->bConnected) { bool bServiceIPC; // Notify AVDECC Msg of the state change. openavbAvdeccMsgClntNotifyCurrentState(pTLState); // Do until we are stopped or lose connection to endpoint while (pTLState->bRunning && pTLState->bConnected) { // Listen for an RX frame (or just sleep if not streaming) bServiceIPC = listenerDoStream(pTLState); if (bServiceIPC) { // Look for messages from endpoint. Don't block (timeout=0) if (!openavbEptClntService(pTLState->endpointHandle, 0)) { AVB_LOGF_WARNING("Lost connection to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID)); pTLState->bConnected = FALSE; pTLState->endpointHandle = 0; } } } // Stop streaming listenerStopStream(pTLState); { MUTEX_CREATE_ERR(); MUTEX_DESTROY(pTLState->statsMutex); // Destroy Stats Mutex MUTEX_LOG_ERR("Error destroying mutex"); } // withdraw our listener attach if (pTLState->bConnected) openavbEptClntStopStream(pTLState->endpointHandle, &streamID); // Notify AVDECC Msg of the state change. openavbAvdeccMsgClntNotifyCurrentState(pTLState); } else { AVB_LOGF_WARNING("Failed to connect to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID)); } if (pTLState->pPvtListenerData) { free(pTLState->pPvtListenerData); pTLState->pPvtListenerData = NULL; } AVB_TRACE_EXIT(AVB_TRACE_TL); }
bool talkerStartStream(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_TL); if (!pTLState) { AVB_LOG_ERROR("Invalid TLState"); AVB_TRACE_EXIT(AVB_TRACE_TL); return FALSE; } openavb_tl_cfg_t *pCfg = &pTLState->cfg; talker_data_t *pTalkerData = pTLState->pPvtTalkerData; assert(!pTLState->bStreaming); pTalkerData->wakeFrames = pCfg->max_interval_frames * pCfg->batch_factor; // Set a max_transmit_deficit_usec default if (pCfg->max_transmit_deficit_usec == 0) pCfg->max_transmit_deficit_usec = 50000; openavbRC rc = openavbAvtpTxInit(pTLState->pMediaQ, &pCfg->map_cb, &pCfg->intf_cb, pTalkerData->ifname, &pTalkerData->streamID, pTalkerData->destAddr, pCfg->max_transit_usec, pTalkerData->fwmark, pTalkerData->vlanID, pTalkerData->vlanPCP, pTalkerData->wakeFrames * pCfg->raw_tx_buffers, &pTalkerData->avtpHandle); if (IS_OPENAVB_FAILURE(rc)) { AVB_LOG_ERROR("Failed to create AVTP stream"); AVB_TRACE_EXIT(AVB_TRACE_TL); return FALSE; } avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle); if (!pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ)) { pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor; } else { // Override the class observation interval with the one provided by the mapping module. pTalkerData->wakeRate = pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor; } pTalkerData->sleepUsec = MICROSECONDS_PER_SECOND / pTalkerData->wakeRate; pTalkerData->intervalNS = NANOSECONDS_PER_SECOND / pTalkerData->wakeRate; U32 SRKbps = ((unsigned long)pTalkerData->classRate * (unsigned long)pCfg->max_interval_frames * (unsigned long)pStream->frameLen * 8L) / 1000; U32 DataKbps = ((unsigned long)pTalkerData->wakeRate * (unsigned long)pCfg->max_interval_frames * (unsigned long)pStream->frameLen * 8L) / 1000; AVB_LOGF_INFO(STREAMID_FORMAT", sr-rate=%" PRIu32 ", data-rate=%lu, frames=%" PRIu16 ", size=%" PRIu16 ", batch=%" PRIu32 ", sleep=%" PRIu64 "us, sr-Kbps=%d, data-Kbps=%d", STREAMID_ARGS(&pTalkerData->streamID), pTalkerData->classRate, pTalkerData->wakeRate, pTalkerData->tSpec.maxIntervalFrames, pTalkerData->tSpec.maxFrameSize, pCfg->batch_factor, pTalkerData->intervalNS / 1000, SRKbps, DataKbps); // number of intervals per report pTalkerData->wakesPerReport = pCfg->report_seconds * NANOSECONDS_PER_SECOND / pTalkerData->intervalNS; // counts of intervals and frames between reports pTalkerData->cntFrames = 0; pTalkerData->cntWakes = 0; // setup the initial times U64 nowNS; CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS); // Align clock : allows for some performance gain nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS; pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND); pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND; pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS; // Clear stats openavbTalkerClearStats(pTLState); // we're good to go! pTLState->bStreaming = TRUE; AVB_TRACE_EXIT(AVB_TRACE_TL); return TRUE; }
// Called from openavbTLThreadFn() which is started from openavbTLRun() void openavbTLRunTalker(tl_state_t *pTLState) { AVB_TRACE_ENTRY(AVB_TRACE_TL); if (!pTLState) { AVB_LOG_ERROR("Invalid TLState"); AVB_TRACE_EXIT(AVB_TRACE_TL); return; } pTLState->pPvtTalkerData = calloc(1, sizeof(talker_data_t)); if (!pTLState->pPvtTalkerData) { AVB_LOG_WARNING("Failed to allocate talker data."); return; } // Create Stats Mutex { MUTEX_ATTR_HANDLE(mta); MUTEX_ATTR_INIT(mta); MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT); MUTEX_ATTR_SET_NAME(mta, "TLStatsMutex"); MUTEX_CREATE_ERR(); MUTEX_CREATE(pTLState->statsMutex, mta); MUTEX_LOG_ERR("Could not create/initialize 'TLStatsMutex' mutex"); } /* If using endpoint register talker, else register with tpsec */ pTLState->bConnected = openavbTLRunTalkerInit(pTLState); if (pTLState->bConnected) { bool bServiceIPC; // Do until we are stopped or loose connection to endpoint while (pTLState->bRunning && pTLState->bConnected) { // Talk (or just sleep if not streaming.) bServiceIPC = talkerDoStream(pTLState); // TalkerDoStream() returns TRUE once per second, // so that we can service our IPC at that low rate. if (bServiceIPC) { // Look for messages from endpoint. Don't block (timeout=0) if (!openavbEptClntService(pTLState->endpointHandle, 0)) { AVB_LOGF_WARNING("Lost connection to endpoint, will retry "STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID))); pTLState->bConnected = FALSE; pTLState->endpointHandle = 0; } } } // Stop streaming talkerStopStream(pTLState); { MUTEX_CREATE_ERR(); MUTEX_DESTROY(pTLState->statsMutex); // Destroy Stats Mutex MUTEX_LOG_ERR("Error destroying mutex"); } // withdraw our talker registration if (pTLState->bConnected) openavbEptClntStopStream(pTLState->endpointHandle, &(((talker_data_t *)pTLState->pPvtTalkerData)->streamID)); openavbTLRunTalkerFinish(pTLState); } else { AVB_LOGF_WARNING("Failed to connect to endpoint"STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID))); } if (pTLState->pPvtTalkerData) { free(pTLState->pPvtTalkerData); pTLState->pPvtTalkerData = NULL; } AVB_TRACE_EXIT(AVB_TRACE_TL); }
// Returns TRUE, to say we're connected and registers tspec with FQTSS tspec should be initialized bool openavbTLRunTalkerInit(tl_state_t *pTLState) { openavb_tl_cfg_t *pCfg = &pTLState->cfg; talker_data_t *pTalkerData = pTLState->pPvtTalkerData; //avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle); strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ); // CORE_TODO: It would be good to have some parts of endpoint moved into non-endpoint general code to handle some the stream // configuration values. // strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ); if (pCfg->stream_addr.mac) { memcpy(pTalkerData->streamID.addr, pCfg->stream_addr.mac, ETH_ALEN); }else { AVB_LOG_WARNING("Stream Address Not Set"); } pTalkerData->streamID.uniqueID = pCfg->stream_uid; if (pCfg->sr_class == SR_CLASS_A) { pTalkerData->classRate = 8000; pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ? SR_CLASS_A_DEFAULT_VID : pCfg->vlan_id; pTalkerData->vlanPCP = SR_CLASS_A_DEFAULT_PRIORITY; } else if (pCfg->sr_class == SR_CLASS_B) { pTalkerData->classRate = 4000; pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ? SR_CLASS_B_DEFAULT_VID : pCfg->vlan_id; pTalkerData->vlanPCP = SR_CLASS_B_DEFAULT_PRIORITY; } memcpy(&pTalkerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN); unsigned int maxBitrate = 0; if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) { maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ); } if (maxBitrate > 0) { if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) { pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate); } if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) { unsigned int map_intv_frames = pCfg->map_cb.map_get_max_interval_frames_cb(pTLState->pMediaQ, pTLState->cfg.sr_class); pCfg->max_interval_frames = map_intv_frames > 0 ? map_intv_frames : pCfg->max_interval_frames; } } pTalkerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames; pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ); // TODO_COREAVB : This wakeRate should also be set in the endpoint case and removed from the tasker.c start stream if (!pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) { pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor; } else { // Override the class observation interval with the one provided by the mapping module. pTalkerData->wakeRate = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor; } if_info_t ifinfo; openavbCheckInterface(pTalkerData->ifname, &ifinfo); pTalkerData->fwmark = openavbQmgrAddStream((SRClassIdx_t)pCfg->sr_class, pTalkerData->wakeRate, pTalkerData->tSpec.maxIntervalFrames, pTalkerData->tSpec.maxFrameSize); if (pTalkerData->fwmark == INVALID_FWMARK) return FALSE; AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pTalkerData->destAddr)); AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(&pTalkerData->streamID)); talkerStartStream(pTLState); return TRUE; }
/* 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); }
bool openavbTLRunTalkerInit(tl_state_t *pTLState) { openavb_tl_cfg_t *pCfg = &pTLState->cfg; talker_data_t *pTalkerData = pTLState->pPvtTalkerData; AVBStreamID_t streamID; memset(&streamID, 0, sizeof(AVBStreamID_t)); if (pCfg->stream_addr.mac) memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN); streamID.uniqueID = pCfg->stream_uid; unsigned int maxBitrate = 0; if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) { maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ); } if (maxBitrate > 0) { if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) { pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate); } if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) { unsigned int map_intv_frames = pCfg->map_cb.map_get_max_interval_frames_cb(pTLState->pMediaQ, pTLState->cfg.sr_class); pCfg->max_interval_frames = map_intv_frames > 0 ? map_intv_frames : pCfg->max_interval_frames; } } pTalkerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames; // The TSpec frame size is the L2 payload - i.e. no Ethernet headers, VLAN, FCS, etc... pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ); AVB_LOGF_INFO("Register "STREAMID_FORMAT": class: %c frame size: %d frame interval: %d", STREAMID_ARGS(&streamID), AVB_CLASS_LABEL(pCfg->sr_class), pTalkerData->tSpec.maxFrameSize, pTalkerData->tSpec.maxIntervalFrames); // Tell endpoint to register our stream. // SRP will send out talker declarations on the LAN. // If there are listeners, we'll get callback (above.) U32 transmitInterval = pTalkerData->classRate; if (pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) { // Override the class observation interval with the one provided by the mapping module. transmitInterval = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ); } return (openavbEptClntRegisterStream(pTLState->endpointHandle, &streamID, pCfg->dest_addr.mac->ether_addr_octet, pCfg->backup_dest_addr_valid, // If we have a backup dest_addr, then the current one was forced and MAAP should not be used. &pTalkerData->tSpec, pCfg->sr_class, pCfg->sr_rank, pCfg->internal_latency, transmitInterval)); }