예제 #1
0
/* Log information on all statically configured streams.
 * (Dynamically configured streams are logged by SRP.)
*/
void openavbEndPtLogAllStaticStreams(void)
{
	bool hdrDone = FALSE;

	if(x_cfg.noSrp) {
		clientStream_t **lpp;
		for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
			if ((*lpp)->clientHandle != AVB_ENDPOINT_HANDLE_INVALID) {
				if (!hdrDone) {
					AVB_LOG_INFO("Statically Configured Streams:");
					AVB_LOG_INFO("                                     |   SR  |    Destination    | ----Max Frame(s)--- |");
					AVB_LOG_INFO("   Role   |        Stream Id         | Class |      Address      | Size | Per Interval |");
					hdrDone = TRUE;
				}
				if ((*lpp)->role == clientTalker) {
					AVB_LOGF_INFO("  Talker  | %02x:%02x:%02x:%02x:%02x:%02x - %4d |   %c   | %02x:%02x:%02x:%02x:%02x:%02x | %4u |      %2u      |",
								  (*lpp)->streamID.addr[0], (*lpp)->streamID.addr[1], (*lpp)->streamID.addr[2],
								  (*lpp)->streamID.addr[3], (*lpp)->streamID.addr[4], (*lpp)->streamID.addr[5],
								  (*lpp)->streamID.uniqueID,
								  AVB_CLASS_LABEL((*lpp)->srClass),
								  (*lpp)->destAddr[0], (*lpp)->destAddr[1], (*lpp)->destAddr[2],
								  (*lpp)->destAddr[3], (*lpp)->destAddr[4], (*lpp)->destAddr[5],
								  (*lpp)->tSpec.maxFrameSize, (*lpp)->tSpec.maxIntervalFrames );
				} else if ((*lpp)->role == clientListener) {
					AVB_LOGF_INFO(" Listener | %02x:%02x:%02x:%02x:%02x:%02x - %4d |   -   | --:--:--:--:--:-- |  --  |      --      |",
								  (*lpp)->streamID.addr[0], (*lpp)->streamID.addr[1], (*lpp)->streamID.addr[2],
								  (*lpp)->streamID.addr[3], (*lpp)->streamID.addr[4], (*lpp)->streamID.addr[5],
								  (*lpp)->streamID.uniqueID );

				}
			}
		}
	}
}
예제 #2
0
/* SRP tells us about talker peer (Talker Registration or De-registration)
 */
openavbRC strmRegCb(void *pv,
						  openavbSrpAttribType_t tlkrDecl,
						  U8 destAddr[],
						  AVBTSpec_t *tSpec,
						  SRClassIdx_t srClass,
						  U32 accumLatency,
						  openavbSrpFailInfo_t *failInfo)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	clientStream_t *ps = (clientStream_t*)pv;
	AVB_LOGF_INFO("SRP listener callback uid=%d: tlkrDecl=%x", ps->streamID.uniqueID, tlkrDecl);

	openavbEptSrvrNotifyLstnrOfSrpCb(ps->clientHandle,
								&ps->streamID,
								x_cfg.ifname,
								destAddr,
								tlkrDecl,
								tSpec,
								srClass,
								accumLatency,
								failInfo);

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return OPENAVB_SUCCESS;
}
예제 #3
0
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;
}
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));
}
예제 #5
0
static bool openMapLib(tl_state_t *pTLState)
{
// OpenAVB using static mapping plugins therefore don't attempt to open a library
#if 0
	// Opening library
	if (pTLState->mapLib.libName) {
		AVB_LOGF_INFO("Attempting to open library: %s", pTLState->mapLib.libName);
		pTLState->mapLib.libHandle = dlopen(pTLState->mapLib.libName, RTLD_LAZY);
		if (!pTLState->mapLib.libHandle) {
			AVB_LOG_ERROR("Unable to open the mapping library.");
			return FALSE;
		}
	}
#endif

	// Looking up function entry
	if (!pTLState->mapLib.funcName) {
		AVB_LOG_ERROR("Mapping initialize function not set.");
		return FALSE;
	}

	char *error;
	AVB_LOGF_INFO("Looking up symbol for function: %s", pTLState->mapLib.funcName);
	if (pTLState->mapLib.libHandle) {
		pTLState->cfg.pMapInitFn = dlsym(pTLState->mapLib.libHandle, pTLState->mapLib.funcName);
	}
	else {
		pTLState->cfg.pMapInitFn = dlsym(RTLD_DEFAULT, pTLState->mapLib.funcName);
	}
	if ((error = dlerror()) != NULL)  {
		AVB_LOGF_ERROR("Mapping initialize function lookup error: %s.", error);
		return FALSE;
	}

	return TRUE;
}
예제 #6
0
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);
}
예제 #7
0
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);
}
예제 #8
0
static gboolean
bus_message(GstBus *bus, GstMessage *message, void *pv)
{
	switch (GST_MESSAGE_TYPE(message))
	{
		case GST_MESSAGE_ERROR:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_error(message, &err, &dbg_info);
			AVB_LOGF_ERROR("GStreamer ERROR message from element %s: %s",
			               GST_OBJECT_NAME(message->src),
			               err->message);
			AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_WARNING:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_warning(message, &err, &dbg_info);
			AVB_LOGF_WARNING("GStreamer WARNING message from element %s: %s",
			                 GST_OBJECT_NAME(message->src),
			                 err->message);
			AVB_LOGF_WARNING("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_INFO:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_info(message, &err, &dbg_info);
			AVB_LOGF_ERROR("GStreamer INFO message from element %s: %s",
			               GST_OBJECT_NAME(message->src),
			               err->message);
			AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_STATE_CHANGED:
		{
			GstState old_state, new_state;
			gst_message_parse_state_changed(message, &old_state, &new_state, NULL);
			AVB_LOGF_DEBUG("Element %s changed state from %s to %s",
			               GST_OBJECT_NAME(message->src),
			               gst_element_state_get_name(old_state),
			               gst_element_state_get_name(new_state));
			break;
		}
		case GST_MESSAGE_STREAM_STATUS:
		{
			// not so valuable
			break;
		}
		case GST_MESSAGE_EOS:
			AVB_LOG_INFO("EOS received");
			break;
		default:
			AVB_LOGF_INFO("GStreamer '%s' message from element %s",
			              gst_message_type_get_name(GST_MESSAGE_TYPE(message)),
			              GST_OBJECT_NAME(message->src));
			break;
	}

	return TRUE;
}
예제 #9
0
bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
{
	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;
	}

	// Save the updated state.
	if (currentState != pState->lastReportedState) {
		openavbAvdeccMsgStateType_t previousState = pState->lastReportedState;
		pState->lastReportedState = currentState;
		AVB_LOGF_INFO("Notified of client %d state change from %s to %s (Last requested:  %s)",
				avdeccMsgHandle, GetStateString(previousState), GetStateString(currentState), GetStateString(pState->lastRequestedState));

		// If AVDECC did not yet set the client state, set the client state to the desired state.
		if (pState->lastRequestedState == OPENAVB_AVDECC_MSG_UNKNOWN) {
			if (pState->stream->initial_state == TL_INIT_STATE_RUNNING && pState->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
				// Have the client be running if the user explicitly requested it to be running.
				openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
			}
			else if (pState->stream->initial_state != TL_INIT_STATE_RUNNING && pState->lastReportedState == OPENAVB_AVDECC_MSG_RUNNING) {
				// Have the client not be running if the user didn't explicitly request it to be running.
				openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
			}
			else if (gAvdeccCfg.bFastConnectSupported &&
					!(pState->bTalker) &&
					pState->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
				// Listener started as not running, and is not configured to start in the running state.
				// See if we should do a fast connect using the saved state.
				openavb_tl_data_cfg_t *pCfg = pState->stream;
				if (pCfg) {
					U16 flags, talker_unique_id;
					U8 talker_entity_id[8], controller_entity_id[8];
					bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
					if (bAvailable) {
						openavbAcmpSMListenerSet_doFastConnect(pCfg, flags, talker_unique_id, talker_entity_id, controller_entity_id);
					}
				}
			}
		}
		else if (currentState == OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY) {
			if (previousState != OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY &&
					pState->lastRequestedState == OPENAVB_AVDECC_MSG_RUNNING &&
					gAvdeccCfg.bFastConnectSupported) {
				// The Talker disappeared.  Use fast connect to assist with reconnecting if it reappears.
				openavb_tl_data_cfg_t *pCfg = pState->stream;
				if (pCfg) {
					U16 flags, talker_unique_id;
					U8 talker_entity_id[8], controller_entity_id[8];
					bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
					if (bAvailable) {
						// Set the timed-out status for the Listener's descriptor.
						// The next time the Talker advertises itself, openavbAcmpSMListenerSet_talkerTestFastConnect() should try to reconnect.
						openavb_aem_descriptor_stream_io_t *pDescriptor;
						U16 listenerUniqueId;
						for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
							pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
							if (pDescriptor && pDescriptor->stream &&
									strcmp(pDescriptor->stream->friendly_name, pCfg->friendly_name) == 0) {
								// We found a match.
								AVB_LOGF_INFO("Listener %s waiting to fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
										pCfg->friendly_name,
										flags,
										talker_unique_id,
										ENTITYID_ARGS(talker_entity_id),
										ENTITYID_ARGS(controller_entity_id));
								pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
								memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
								CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
								pDescriptor->fast_connect_start_time.tv_sec += 5;	// Give the Talker some time to shutdown or stabilize
								break;
							}
						}
					}
				}
			}

			// Now that we have handled this, treat this state as a normal stop.
			pState->lastReportedState = OPENAVB_AVDECC_MSG_STOPPED;
		}
	}

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return true;
}
예제 #10
0
bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
	openavb_tl_data_cfg_t * currentStream;

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (pState) {
		// The handle was already specified.  Something has gone terribly wrong!
		AVB_LOGF_ERROR("avdeccMsgHandle %d already used", avdeccMsgHandle);
		AvdeccMsgStateListRemove(pState);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Make sure the supplied string is nil-terminated.
	friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';

	// Create a structure to hold the client information.
	pState = (avdecc_msg_state_t *) calloc(1, sizeof(avdecc_msg_state_t));
	if (!pState) {
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}
	pState->avdeccMsgHandle = avdeccMsgHandle;
	pState->bTalker = (talker != 0);
	pState->lastRequestedState = pState->lastReportedState = OPENAVB_AVDECC_MSG_UNKNOWN;

	// Find the state information matching this item.
	for (currentStream = streamList; currentStream != NULL; currentStream = currentStream->next) {
		if (strncmp(currentStream->friendly_name, friendly_name, FRIENDLY_NAME_SIZE) == 0)
		{
			break;
		}
	}
	if (!currentStream) {
		AVB_LOGF_WARNING("Ignoring unexpected client %d, friendly_name:  %s",
			avdeccMsgHandle, friendly_name);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Keep track of this new state item.
	if (!AvdeccMsgStateListAdd(pState)) {
		AVB_LOGF_ERROR("Error saving client identity information %d", avdeccMsgHandle);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Associate this Listener instance with the stream information.
	pState->stream = currentStream;
	currentStream->client = pState;

	AVB_LOGF_INFO("Client %d Detected, friendly_name:  %s",
		avdeccMsgHandle, friendly_name);

	// Enable ADP support, now that we have at least one Talker/Listener.
	openavbAdpHaveTL(true);

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return true;
}
예제 #11
0
// 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);
}
예제 #12
0
/* 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;
}
// 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;
}
예제 #14
0
// 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);
}
예제 #16
0
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
void openavbIntfMpeg2tsGstTxInitCB(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;
		}

		pPvtData->pipe = (GstElement*)NULL;
		pPvtData->appsink = (GstAppSink*)NULL;
		pPvtData->appsrc = (GstAppSrc*)NULL;
		pPvtData->bus = (GstBus*)NULL;
		pPvtData->nWaiting = 0;

		GError *error = NULL;
		pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
		if (error)
		{
			AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
			return;
		}

		AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
		pPvtData->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSINK_NAME));
		if (!pPvtData->appsink)
		{
			AVB_LOG_ERROR("Failed to find appsink element");
			return;
		}

		// create bus
		pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
		if (!pPvtData->bus)
		{
			AVB_LOG_ERROR("Failed to create bus");
			return;
		}

		/* add callback for bus messages */
		gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);

		// Setup callback function to handle new buffers delivered to sink
		GstAppSinkCallbacks cbfns;
		memset(&cbfns, 0, sizeof(GstAppSinkCallbacks));

		gst_al_set_callback(&cbfns, sinkNewBufferSample);

		gst_app_sink_set_callbacks(pPvtData->appsink, &cbfns, (gpointer)(pMediaQ), NULL);

		// Set most capabilities in pipeline (config), not code

		// Don't drop buffers
		g_object_set(pPvtData->appsink, "drop", 0, NULL);

		// Start playing
		gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
}
예제 #17
0
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
void openavbIntfMpeg2tsGstRxInitCB(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;
		}

		pPvtData->pipe = (GstElement*)NULL;
		pPvtData->appsink = (GstAppSink*)NULL;
		pPvtData->appsrc = (GstAppSrc*)NULL;
		pPvtData->bus = (GstBus*)NULL;
		pPvtData->srcPaused = FALSE;

		GError *error = NULL;
		pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
		if (error)
		{
			AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
			return;
		}

		AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
		pPvtData->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSRC_NAME));
		if (!pPvtData->appsrc)
		{
			AVB_LOG_ERROR("Failed to find appsrc element");
			return;
		}

		// Make appsrc non-blocking
		g_object_set(G_OBJECT(pPvtData->appsrc), "block", FALSE, NULL);

		// create bus
		pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
		if (!pPvtData->bus)
		{
			AVB_LOG_ERROR("Failed to create bus");
			return;
		}

		/* add callback for bus messages */
		gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);

		// Setup callback function to handle request from src to pause/start data flow
		GstAppSrcCallbacks cbfns;
		memset(&cbfns, 0, sizeof(GstAppSrcCallbacks));
		cbfns.enough_data = srcStopFeed;
		cbfns.need_data = srcStartFeed;
		gst_app_src_set_callbacks(pPvtData->appsrc, &cbfns, (gpointer)(pMediaQ), NULL);

		// Set most capabilities in pipeline (config), not code

		// Don't block
		g_object_set(pPvtData->appsrc, "block", 0, NULL);

		// PLAY
		gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
}
예제 #18
0
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;
}