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 openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle); if (!pState) { AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return false; } openavb_tl_data_cfg_t *pCfg = pState->stream; if (!pCfg) { AVB_LOGF_ERROR("avdeccMsgHandle %d stream not valid", avdeccMsgHandle); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return false; } // Update the stream information supplied by the client. pCfg->sr_class = sr_class; memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6); pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid. pCfg->stream_uid = stream_uid; memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6); pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid. pCfg->vlan_id = stream_vlan_id; AVB_LOGF_DEBUG("Talker-supplied sr_class: %u", pCfg->sr_class); AVB_LOGF_DEBUG("Talker-supplied stream_id: " ETH_FORMAT "/%u", ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid); AVB_LOGF_DEBUG("Talker-supplied dest_addr: " ETH_FORMAT, ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet)); AVB_LOGF_DEBUG("Talker-supplied vlan_id: %u", pCfg->vlan_id); // Notify the state machine that we received this information. openavbAcmpSMTalker_updateStreamInfo(pCfg); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return true; }
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; }
/* Find a stream in the list of streams we're handling */ clientStream_t* findStream(AVBStreamID_t *streamID) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); clientStream_t* ps = NULL; // Check for default stream MAC address, and fill it in with // interface MAC so that if the talker didn't fill in // the stream MAC, we use the one that the endpoint is // configured to use. // // Listener should never pass a default MAC in, // because the config code forces the listener to specify MAC in // its configuration. Talker may send a default (empty) MAC in // the stream ID, in which case we fill it in. // // TODO: This is sketchy - it would probably be better to force every // client to send fully populated stream IDs. I think the reason // I didn't do that is that it would cause duplicate configuration // (in the talker and in the endpoint.) Perhaps the filling in of // the MAC could happen in the endpoint function which calls // findstream for the talker. // static const U8 emptyMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; if (memcmp(streamID->addr, emptyMAC, ETH_ALEN) == 0) { memcpy(streamID->addr, x_cfg.ifmac, ETH_ALEN); AVB_LOGF_DEBUG("Replaced default streamID MAC with interface MAC "ETH_FORMAT, ETH_OCTETS(streamID->addr)); } clientStream_t **lpp; for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) { if (memcmp(streamID->addr, (*lpp)->streamID.addr, ETH_ALEN) == 0 && streamID->uniqueID == (*lpp)->streamID.uniqueID) { ps = *lpp; break; } } AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return ps; }
// 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 client registers a stream */ bool openavbEptSrvrRegisterStream(int h, AVBStreamID_t *streamID, U8 destAddr[], AVBTSpec_t *tSpec, U8 srClass, U8 srRank, U32 latency) { openavbRC rc = OPENAVB_SUCCESS; AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); clientStream_t *ps = findStream(streamID); if (ps && ps->clientHandle != h) { AVB_LOGF_ERROR("Error registering talker; multiple clients for stream %d", streamID->uniqueID); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } ps = addStream(h, streamID); if (!ps) { AVB_LOGF_ERROR("Error registering talker; unable to add client stream %d", streamID->uniqueID); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } ps->role = clientTalker; ps->tSpec = *tSpec; ps->srClass = (SRClassIdx_t)srClass; ps->srRank = srRank; ps->latency = latency; ps->fwmark = INVALID_FWMARK; if (memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) { // no client-supplied address, use MAAP struct ether_addr addr; ps->hndMaap = openavbMaapAllocate(1, &addr); if (ps->hndMaap) { memcpy(ps->destAddr, addr.ether_addr_octet, ETH_ALEN); strmAttachCb((void*)ps, openavbSrp_LDSt_Stream_Info); // Inform talker about MAAP } else { AVB_LOG_ERROR("Error registering talker: MAAP failed to allocate MAC address"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); delStream(ps); return FALSE; } } else { // client-supplied destination MAC address memcpy(ps->destAddr, destAddr, ETH_ALEN); ps->hndMaap = NULL; } // Do SRP talker register AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, da="ETH_FORMAT"", ps, streamID->uniqueID, tSpec->maxFrameSize, tSpec->maxIntervalFrames, ps->srClass, ps->srRank, ps->latency, ETH_OCTETS(ps->destAddr)); if(x_cfg.noSrp) { // we are operating in a mode supporting preconfigured streams; SRP is not in use, // so, as a proxy for SRP, which would normally make this call after establishing // the stream, call the callback from here strmAttachCb((void*)ps, openavbSrp_LDSt_Ready); } else { // normal SRP operation rc = openavbSrpRegisterStream((void*)ps, &ps->streamID, ps->destAddr, &ps->tSpec, ps->srClass, ps->srRank, ps->latency); if (!IS_OPENAVB_SUCCESS(rc)) { if (ps->hndMaap) openavbMaapRelease(ps->hndMaap); delStream(ps); } } openavbEndPtLogAllStaticStreams(); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return IS_OPENAVB_SUCCESS(rc); }