예제 #1
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;
	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;

		// Do until we are stopped or loose 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);
	}
	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);
}
예제 #2
0
bool startAvdecc(const char* ifname, const char **inifiles, int numfiles)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
	LOG_EAVB_CORE_VERSION();

	// Ensure that we're running as root
	//  (need to be root to use raw sockets)
	uid_t euid = geteuid();
	if (euid != (uid_t)0) {
		fprintf(stderr, "Error: needs to run as root\n\n");
		goto error;
	}

	// Get the AVDECC configuration
	memset(&gAvdeccCfg, 0, sizeof(openavb_avdecc_cfg_t));
	openavbReadAvdeccConfig(DEFAULT_AVDECC_INI_FILE, &gAvdeccCfg);

	// Determine which interface to use.
	if (ifname) {
		strncpy(gAvdeccCfg.ifname, ifname, sizeof(gAvdeccCfg.ifname));
	} else if (gAvdeccCfg.ifname[0] == '\0') {
		AVB_LOG_ERROR("No interface specified.  Use the -I flag, or add one to " DEFAULT_AVDECC_INI_FILE ".");
		goto error;
	}

	// Read the information from the supplied INI files.
	openavb_tl_data_cfg_t * prevStream = NULL, * newStream;
	U32 i1;
	for (i1 = 0; i1 < numfiles; i1++) {

		char iniFile[1024];
		snprintf(iniFile, sizeof(iniFile), "%s", inifiles[i1]);
		// Create a new item with this INI information.
		newStream = malloc(sizeof(openavb_tl_data_cfg_t));
		if (!newStream) {
			AVB_LOG_ERROR("Out of memory");
			goto error;
		}
		memset(newStream, 0, sizeof(openavb_tl_data_cfg_t));
		if (!openavbReadTlDataIniFile(iniFile, newStream)) {
			AVB_LOGF_ERROR("Error reading ini file: %s", inifiles[i1]);
			goto error;
		}
		// Append this item to the list of items.
		if (!prevStream) {
			// First item.
			streamList = newStream;
		} else {
			// Subsequent item.
			prevStream->next = newStream;
		}
		prevStream = newStream;
	}

	/* Run AVDECC in its own thread. */
	avdeccRunning = TRUE;
	avdeccInitSucceeded = FALSE;
	int err = pthread_create(&avdeccServerHandle, NULL, avdeccServerThread, NULL);
	if (err) {
		AVB_LOGF_ERROR("Failed to start AVDECC thread: %s", strerror(err));
		goto error;
	}

	/* Wait a while to see if the thread was able to start AVDECC. */
	int i;
	for (i = 0; avdeccRunning && !avdeccInitSucceeded && i < 5000; ++i) {
		SLEEP_MSEC(1);
	}
	if (!avdeccInitSucceeded) {
		goto error;
	}

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
	return true;

error:
	AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
	return false;
}
예제 #3
0
// callback function - called for each name/value pair by ini parsing library
static int openavbIniCfgCallback(void *user, const char *tlSection, const char *name, const char *value)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);

	openavb_tl_data_cfg_t *pCfg = (openavb_tl_data_cfg_t *)user;

	AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);

	bool valOK = FALSE;
	char *pEnd;

	if (MATCH(name, "role")) {
		if (MATCH(value, "talker")) {
			pCfg->role = AVB_ROLE_TALKER;
			valOK = TRUE;
		}
		else if (MATCH(value, "listener")) {
			pCfg->role = AVB_ROLE_LISTENER;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "initial_state")) {
		if (MATCH(value, "running")) {
			pCfg->initial_state = TL_INIT_STATE_RUNNING;
			valOK = TRUE;
		}
		else if (MATCH(value, "stopped")) {
			pCfg->initial_state = TL_INIT_STATE_STOPPED;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "dest_addr")) {
		valOK = parse_mac(value, &pCfg->dest_addr);
	}
	else if (MATCH(name, "stream_addr")) {
		valOK = parse_mac(value, &pCfg->stream_addr);
	}
	else if (MATCH(name, "stream_uid")) {
		errno = 0;
		pCfg->stream_uid = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->stream_uid <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_interval_frames")) {
		errno = 0;
		pCfg->max_interval_frames = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_interval_frames <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_frame_size")) {
		errno = 0;
		pCfg->max_frame_size = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_interval_frames <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "sr_class")) {
		if (strlen(value) == 1) {
			if (tolower(value[0]) == 'a') {
				pCfg->sr_class = SR_CLASS_A;
				valOK = TRUE;
			}
			else if (tolower(value[0]) == 'b') {
				pCfg->sr_class = SR_CLASS_B;
				valOK = TRUE;
			}
		}
	}
	else if (MATCH(name, "sr_rank")) {
		if (strlen(value) == 1) {
			if (value[0] == '1') {
				pCfg->sr_rank = SR_RANK_REGULAR;
				valOK = TRUE;
			}
			else if (value[0] == '0') {
				pCfg->sr_rank = SR_RANK_EMERGENCY;
				valOK = TRUE;
			}
		}
	}
	else if (MATCH(name, "max_transit_usec")) {
		errno = 0;
		pCfg->max_transit_usec = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_transit_usec <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_transmit_deficit_usec")) {
		errno = 0;
		pCfg->max_transmit_deficit_usec = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_transmit_deficit_usec <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "internal_latency")) {
		errno = 0;
		pCfg->internal_latency = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->internal_latency <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "batch_factor")) {
		errno = 0;
		pCfg->batch_factor = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->batch_factor > 0
			&& pCfg->batch_factor <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_stale")) {
		errno = 0;
		pCfg->max_stale = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_stale >= 0
			&& pCfg->max_stale <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "raw_tx_buffers")) {
		errno = 0;
		pCfg->raw_tx_buffers = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->raw_tx_buffers <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "raw_rx_buffers")) {
		errno = 0;
		pCfg->raw_rx_buffers = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->raw_rx_buffers <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "report_seconds")) {
		errno = 0;
		pCfg->report_seconds = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& (int)pCfg->report_seconds >= 0
			&& pCfg->report_seconds <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "start_paused")) {
		// ignore this item - tl_host doesn't use it because
		// it pauses before reading any of its streams.
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& tmp >= 0
			&& tmp <= 1) {
			pCfg->start_paused = (tmp == 1);
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "vlan_id")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		// vlanID is 12 bit field
		if (*pEnd == '\0' && errno == 0
			&& tmp >= 0x0
			&& tmp <= 0xFFF) {
			pCfg->vlan_id = tmp;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "fixed_timestamp")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		if (*pEnd == '\0' && errno == 0) {
			pCfg->fixed_timestamp = tmp;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "spin_wait")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		if (*pEnd == '\0' && errno == 0) {
			pCfg->spin_wait = (tmp == 1);
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "tx_blocking_in_intf")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		if (*pEnd == '\0' && errno == 0) {
			pCfg->tx_blocking_in_intf = tmp;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "thread_rt_priority")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		if (*pEnd == '\0' && errno == 0) {
			pCfg->thread_rt_priority = tmp;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "thread_affinity")) {
		errno = 0;
		unsigned long tmp;
		tmp = strtoul(value, &pEnd, 0);
		if (*pEnd == '\0' && errno == 0) {
			pCfg->thread_affinity = tmp;
			valOK = TRUE;
		}
	}

	else if (MATCH(name, "friendly_name")) {
		strncpy(pCfg->friendly_name, value, FRIENDLY_NAME_SIZE - 1);
		valOK = TRUE;
	}

	else if (MATCH(name, "current_sampling_rate")) {
		errno = 0;
		pCfg->current_sampling_rate = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->current_sampling_rate <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "sampling_rates")) {
		errno = 0;
		memset(pCfg->sampling_rates,0,sizeof(pCfg->sampling_rates));
		char *rate, *copy;
		copy = strdup(value);
		rate = strtok(copy,",");
		int i = 0,break_flag = 0;
		while (rate != NULL )
		{
			pCfg->sampling_rates[i] = strtol(rate,&pEnd, 10);
			if (*pEnd != '\0' || errno != 0
				|| pCfg->sampling_rates[i] > UINT32_MAX)
			{
				break_flag = 1;
				break;
			}
			rate = strtok(NULL,",");
			i++;
		}
		if (break_flag != 1)
		{
			valOK = TRUE;
			pCfg->sampling_rates_count = i;
		}
	}
	else if (strcmp(name, "intf_nv_audio_rate") == 0) {
		long int val = strtol(value, &pEnd, 10);
		if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
			pCfg->audioRate = val;
			valOK = TRUE;
		}
		else {
			AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
			pCfg->audioRate = AVB_AUDIO_RATE_44_1KHZ;
		}
	}
	else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
		long int val = strtol(value, &pEnd, 10);
		if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
			pCfg->audioBitDepth = val;
			valOK = TRUE;
		}
		else {
			AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
			pCfg->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
		}
	}
	else if (strcmp(name, "intf_nv_audio_channels") == 0) {
		long int val = strtol(value, &pEnd, 10);
		if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
			pCfg->audioChannels = val;
			valOK = TRUE;
		}
		else {
			AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
			pCfg->audioChannels = AVB_AUDIO_CHANNELS_2;
		}
	}
	else if (MATCH(name, "map_fn")) {
		errno = 0;
		memset(pCfg->map_fn,0,sizeof(pCfg->map_fn));
		strncpy(pCfg->map_fn,value,sizeof(pCfg->map_fn)-1);
		valOK = TRUE;
	}

	else {
		// Ignored item.
		AVB_LOGF_DEBUG("Unhandled configuration item: name=%s, value=%s", name, value);

		// Don't abort for this item.
		valOK = TRUE;
	}

	if (!valOK) {
		// bad value
		AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
		return 0;
	}

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC);

	return 1; // OK
}
예제 #4
0
static inline bool listenerDoStream(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;
	listener_data_t *pListenerData = pTLState->pPvtListenerData;
	bool bRet = FALSE;

	if (pTLState->bStreaming) {
		U64 nowNS;

		pListenerData->nReportCalls++;

		// Try to receive a frame
		if (IS_OPENAVB_SUCCESS(openavbAvtpRx(pListenerData->avtpHandle))) {
			pListenerData->nReportFrames++;
		}

		CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);

		if (pCfg->report_seconds > 0) {
			if (nowNS > pListenerData->nextReportNS) {
			  
				U64 lost = openavbAvtpLost(pListenerData->avtpHandle);
				U64 bytes = openavbAvtpBytes(pListenerData->avtpHandle);
				U32 rxbuf = openavbAvtpRxBufferLevel(pListenerData->avtpHandle);
				U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
				U32 mqrdy = openavbMediaQCountItems(pTLState->pMediaQ, FALSE);
			
				AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "RX UID:%d, ", LOG_RT_DATATYPE_U16, &pListenerData->streamID.uniqueID);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportCalls);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportFrames);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "lost=%lld, ", LOG_RT_DATATYPE_U64, &lost);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "rxbuf=%d, ", LOG_RT_DATATYPE_U32, &rxbuf);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqrdy=%d", LOG_RT_DATATYPE_U32, &mqrdy);

				openavbListenerAddStat(pTLState, TL_STAT_RX_CALLS, pListenerData->nReportCalls);
				openavbListenerAddStat(pTLState, TL_STAT_RX_FRAMES, pListenerData->nReportFrames);
				openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, lost);
				openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, bytes);

				pListenerData->nReportCalls = 0;
				pListenerData->nReportFrames = 0;
				pListenerData->nextReportNS += (pCfg->report_seconds * NANOSECONDS_PER_SECOND);  
			}
		}

		if (nowNS > pListenerData->nextSecondNS) {
			pListenerData->nextSecondNS += NANOSECONDS_PER_SECOND;
			bRet = TRUE;
		}
	}
	else {
            SLEEP(1);
            bRet = TRUE;
	}

	AVB_TRACE_EXIT(AVB_TRACE_TL);
	return bRet;
}
예제 #5
0
int avbEndpointLoop(void)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	int retVal = -1;
	openavbRC rc = OPENAVB_SUCCESS;
	do {

		if (!x_cfg.bypassAsCapableCheck && (startPTP() < 0)) {
			// make sure ptp, a separate process, starts and is using the same interface as endpoint
			AVB_LOG_ERROR("PTP failed to start - Exiting");
			break;
		} else if(x_cfg.bypassAsCapableCheck) {
			AVB_LOG_WARNING(" ");
			AVB_LOG_WARNING("Configuration 'gptp_asCapable_not_required = 1' is set.");
			AVB_LOG_WARNING("This configuration bypasses the requirement for gPTP");
			AVB_LOG_WARNING("and openavb_gptp is not started automatically.");
			AVB_LOG_WARNING("An appropriate ptp MUST be started separately.");
			AVB_LOG_WARNING("Any network which does not use ptp to synchronize time");
			AVB_LOG_WARNING("on each and every network device is NOT an AVB network.");
			AVB_LOG_WARNING("Such a network WILL NOT FUNCTION PROPERLY.");
			AVB_LOG_WARNING(" ");
		}

		x_streamList = NULL;

		if (!openavbQmgrInitialize(x_cfg.fqtss_mode, x_cfg.ifindex, x_cfg.ifname, x_cfg.mtu, x_cfg.link_kbit, x_cfg.nsr_kbit)) {
			AVB_LOG_ERROR("Failed to initialize QMgr");
			break;
		}

		if (!openavbMaapInitialize(x_cfg.ifname, x_cfg.maapPort, &(x_cfg.maap_preferred), maapRestartCallback)) {
			AVB_LOG_ERROR("Failed to initialize MAAP");
			openavbQmgrFinalize();
			break;
		}

		if (!openavbShaperInitialize(x_cfg.ifname, x_cfg.shaperPort)) {
			AVB_LOG_ERROR("Failed to initialize Shaper");
			openavbMaapFinalize();
			openavbQmgrFinalize();
			break;
		}

		if(!x_cfg.noSrp) {
			// Initialize SRP
			rc = openavbSrpInitialize(strmAttachCb, strmRegCb, x_cfg.ifname, x_cfg.link_kbit, x_cfg.bypassAsCapableCheck);
		} else {
			rc = OPENAVB_SUCCESS;
			AVB_LOG_WARNING(" ");
			AVB_LOG_WARNING("Configuration 'preconfigured = 1' is set.");
			AVB_LOG_WARNING("SRP is disabled. Streams MUST be configured manually");
			AVB_LOG_WARNING("on each and every device in the network, without exception.");
			AVB_LOG_WARNING("AN AVB NETWORK WILL NOT FUNCTION AS EXPECTED UNLESS ALL");
			AVB_LOG_WARNING("STREAMS ARE PROPERLY CONFIGURED ON ALL NETWORK DEVICES.");
			AVB_LOG_WARNING(" ");
		}

		if (!IS_OPENAVB_SUCCESS(rc)) {
			AVB_LOG_ERROR("Failed to initialize SRP");
			openavbShaperFinalize();
			openavbMaapFinalize();
			openavbQmgrFinalize();
			break;
		}

		if (openavbEndpointServerOpen()) {

			retVal = 0;

			while (endpointRunning) {
				openavbEptSrvrService();
			}

			openavbEndpointServerClose();
		}

		if(!x_cfg.noSrp) {
			// Shutdown SRP
			openavbSrpShutdown();
		}

		openavbShaperFinalize();
		openavbMaapFinalize();
		openavbQmgrFinalize();

	} while (0);

	if (!x_cfg.bypassAsCapableCheck && (stopPTP() < 0)) {
		AVB_LOG_WARNING("Failed to execute PTP stop command: killall -s SIGINT openavb_gptp");
	}

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return retVal;
}
/* 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);
}
예제 #7
0
static int cfgCallback(void *user, const char *section, const char *name, const char *value)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	if (!user || !section || !name || !value) {
		AVB_LOG_ERROR("Config: invalid arguments passed to callback");
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return 0;
	}
	
	openavb_endpoint_cfg_t *pCfg = (openavb_endpoint_cfg_t*)user;
	
	AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);

	bool valOK = FALSE;
	char *pEnd;

	if (MATCH(section, "network"))
	{
		if (MATCH(name, "ifname"))
		{
			if_info_t ifinfo;
			if (openavbCheckInterface(value, &ifinfo)) {
				strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
				memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
				pCfg->ifindex = ifinfo.index;
				pCfg->mtu = ifinfo.mtu;
				valOK = TRUE;
			}
		}
		else if (MATCH(name, "link_kbit")) {
			errno = 0;
			pCfg->link_kbit = strtoul(value, &pEnd, 10);
			if (*pEnd == '\0' && errno == 0)
				valOK = TRUE;
		}
		else if (MATCH(name, "nsr_kbit")) {
			errno = 0;
			pCfg->nsr_kbit = strtoul(value, &pEnd, 10);
			if (*pEnd == '\0' && errno == 0)
				valOK = TRUE;
		}
		else {
			// unmatched item, fail
			AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return 0;
		}
	}
	else if (MATCH(section, "ptp"))
	{
		if (MATCH(name, "start_options")) {
			pCfg->ptp_start_opts = strdup(value);
			valOK = TRUE;
		}
		else {
			// unmatched item, fail
			AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return 0;
		}
	}
	else if (MATCH(section, "fqtss"))
	{
		if (MATCH(name, "mode")) {
			errno = 0;
			pCfg->fqtss_mode = strtoul(value, &pEnd, 10);
			if (*pEnd == '\0' && errno == 0)
				valOK = TRUE;
		}
		else {
			// unmatched item, fail
			AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return 0;
		}
	}
	else if (MATCH(section, "srp"))
	{
		if (MATCH(name, "preconfigured")) {
			errno = 0;
			unsigned temp = strtoul(value, &pEnd, 10);
			if (*pEnd == '\0' && errno == 0) {
				valOK = TRUE;
				if (temp == 1)
					pCfg->noSrp = TRUE;
				else
					pCfg->noSrp = FALSE;
			}
		}
		else if (MATCH(name, "gptp_asCapable_not_required")) {
			errno = 0;
			unsigned temp = strtoul(value, &pEnd, 10);
			if (*pEnd == '\0' && errno == 0) {
				valOK = TRUE;
				if (temp == 1)
					pCfg->bypassAsCapableCheck = TRUE;
				else
					pCfg->bypassAsCapableCheck = FALSE;
			}
		}
		else {
			// unmatched item, fail
			AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return 0;
		}
	}
	else {
		// unmatched item, fail
		AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return 0;
	}

	if (!valOK) {
		cfgValErr(section, name, value);
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return 0;
	}

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return 1; // OK
}
예제 #8
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;
}
예제 #9
0
// This callback is called when acting as a listener.
bool openavbIntfViewerRxCB(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 FALSE;
		}

		media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
		if (pMediaQItem) {

		  	// The skip countdown allow the viewer modes to set a number of packets to ignore 
		  	// after logging to reduce or eliminate the logging from affecting the stats.
			if (pPvtData->skipCountdown)
				pPvtData->skipCountdown--;
		  
			if (pMediaQItem->dataLen && !pPvtData->skipCountdown) {
				pPvtData->servicedCount++;

				if (pPvtData->viewType == VIEWER_MODE_DETAIL) {
					U32 avtpTimestamp;
					U64 avtpTimestampTime;
					bool avtpTimestampValid;
					U32 nowTimestamp;
					U64 nowTimestampTime;
					bool nowTimestampValid;
					U64 nowTime;
					S32 lateNS = 0;
					U64 gapNS = 0;
					
					avtpTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
					avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
					
					openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
					nowTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
					nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
					
					CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);

					if (avtpTimestampValid && nowTimestampValid) {
						lateNS = nowTimestampTime - avtpTimestampTime;
						if (lateNS > pPvtData->maxLateNS) {
							pPvtData->maxLateNS = lateNS;
						}
						pPvtData->accumLateNS += lateNS;
						
						if (pPvtData->servicedCount > 1) {
							gapNS = nowTime - pPvtData->prevNowTime;
							if (gapNS > pPvtData->maxGapNS) {
								pPvtData->maxGapNS = gapNS;
							}
							pPvtData->accumGapNS += gapNS;
						}
						pPvtData->prevNowTime = nowTime;
						
						if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
							S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
							S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "****************************", LOG_RT_DATATYPE_CONST_STR, NULL);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Packets: %u", LOG_RT_DATATYPE_U32, &pPvtData->servicedCount);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "AVTP Timestamp: %u NS", LOG_RT_DATATYPE_U32, &avtpTimestamp);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Now Timestamp:  %u NS", LOG_RT_DATATYPE_U32, &nowTimestamp);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late: %d NS", LOG_RT_DATATYPE_S32, &lateNS);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Avg: %d NS", LOG_RT_DATATYPE_S32, &lateAvg);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Max: %d NS", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap: %u NS", LOG_RT_DATATYPE_U32, &gapNS);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Avg: %u NS", LOG_RT_DATATYPE_U32, &gapAvg);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Max: %u NS", LOG_RT_DATATYPE_U32, &pPvtData->maxGapNS);
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Data length:  %u", LOG_RT_DATATYPE_U32, &pMediaQItem->dataLen);
							
							pPvtData->accumLateNS = 0;
							pPvtData->maxLateNS = 0;
							pPvtData->accumGapNS = 0;
							pPvtData->maxGapNS = 0;
							pPvtData->prevNowTime = 0;							
							pPvtData->servicedCount = 0;
							pPvtData->skipCountdown = 10;
						}
					}
				}
				
				else if (pPvtData->viewType == VIEWER_MODE_MAPPING_AWARE) {
				}

				else if (pPvtData->viewType == VIEWER_MODE_AVTP_TIMESTAMP) {
					U64 avtpTimestampTime;
					bool avtpTimestampValid;
					S32 deltaNS = 0;
					
					avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
					
					if (avtpTimestampValid) {
						if (pPvtData->servicedCount > 1) {
							deltaNS = avtpTimestampTime - pPvtData->prevAvtpTimestampTime;
							if (deltaNS > pPvtData->maxAvtpDeltaNS) {
								pPvtData->maxAvtpDeltaNS = deltaNS;
							}
							pPvtData->accumAvtpDeltaNS += deltaNS;

							if (pPvtData->avgForJitter != 0) {
								S32 deltaJitter = pPvtData->avgForJitter - deltaNS;
								if (deltaJitter < 0) deltaJitter = -deltaJitter;
								pPvtData->jitter += (1.0/16.0) * ((float)deltaJitter - pPvtData->jitter);
							}
						}
						pPvtData->prevAvtpTimestampTime = avtpTimestampTime;

						if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
							S32 deltaAvg = pPvtData->accumAvtpDeltaNS / (pPvtData->servicedCount - 1);
							U32 jitter = (U32)(pPvtData->jitter);
							
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta: %d NS  ", LOG_RT_DATATYPE_S32, &deltaNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Avg: %d NS  ", LOG_RT_DATATYPE_S32, &deltaAvg);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Max: %d NS  ", LOG_RT_DATATYPE_S32, &pPvtData->maxAvtpDeltaNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
							
							pPvtData->accumAvtpDeltaNS = 0;
							pPvtData->maxAvtpDeltaNS = 0;
							pPvtData->servicedCount = 0;
							pPvtData->prevAvtpTimestampTime = 0;
							pPvtData->skipCountdown = 10;
							pPvtData->jitter = 0.0;
							pPvtData->avgForJitter = deltaAvg;
						}
					}
				}

				else if (pPvtData->viewType == VIEWER_MODE_LATENCY) {
					U64 avtpTimestampTime;
					bool avtpTimestampValid;
					U64 nowTimestampTime;
					bool nowTimestampValid;
					S32 lateNS = 0;
					
					avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
					
					openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
					nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);

					if (avtpTimestampValid && nowTimestampValid) {
						lateNS = nowTimestampTime - avtpTimestampTime;
						if (lateNS > pPvtData->maxLateNS) {
							pPvtData->maxLateNS = lateNS;
						}
						pPvtData->accumLateNS += lateNS;
						
						if (pPvtData->avgForJitter != 0) {
							S32 lateJitter = pPvtData->avgForJitter - lateNS;
							if (lateJitter < 0) lateJitter = -lateJitter;
							pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
						}
						
						if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
							S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
							U32 jitter = (U32)(pPvtData->jitter);
							
							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Latency: %d NS  ", LOG_RT_DATATYPE_S32, &lateNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Avg: %d NS  ", LOG_RT_DATATYPE_S32, &lateAvg);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Max: %d NS  ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
							
							pPvtData->accumLateNS = 0;
							pPvtData->maxLateNS = 0;
							pPvtData->servicedCount = 0;
							pPvtData->skipCountdown = 10;
							pPvtData->jitter = 0.0;
							pPvtData->avgForJitter = lateAvg;
						}
					}
				}
			  
				else if (pPvtData->viewType == VIEWER_MODE_SELECTIVE_TIMESTAMP) {
				}				  

				else if (pPvtData->viewType == VIEWER_MODE_LATE) {
					U64 avtpTimestampTime;
					bool avtpTimestampValid;
					U64 nowTimestampTime;
					bool nowTimestampValid;
					S32 lateNS = 0;
					
					avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
					
					openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
					nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
					nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);

					if (avtpTimestampValid && nowTimestampValid) {
						lateNS = nowTimestampTime - avtpTimestampTime;
						if (lateNS > pPvtData->maxLateNS) {
							pPvtData->maxLateNS = lateNS;
						}
						pPvtData->accumLateNS += lateNS;
						
						if (pPvtData->avgForJitter != 0) {
							S32 lateJitter = pPvtData->avgForJitter - lateNS;
							if (lateJitter < 0) lateJitter = -lateJitter;
							pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
						}
						
						if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
							S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
							U32 jitter = (U32)(pPvtData->jitter);

							AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Late: %d NS  ", LOG_RT_DATATYPE_S32, &lateNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Avg: %d NS  ", LOG_RT_DATATYPE_S32, &lateAvg);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Max: %d NS  ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
							AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
							
							pPvtData->accumLateNS = 0;
							pPvtData->maxLateNS = 0;
							pPvtData->servicedCount = 0;
							pPvtData->skipCountdown = 10;
							pPvtData->jitter = 0.0;
							pPvtData->avgForJitter = lateAvg;
						}
					}
				}
				
				else if (pPvtData->viewType == VIEWER_MODE_GAP) {
					U64 nowTime;
					U64 gapNS = 0;
					
					CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);

					if (pPvtData->servicedCount > 1) {
						gapNS = nowTime - pPvtData->prevNowTime;
						if (gapNS > pPvtData->maxGapNS) {
							pPvtData->maxGapNS = gapNS;
						}
						pPvtData->accumGapNS += gapNS;
						
						if (pPvtData->avgForJitter != 0) {
							S32 gapJitter = pPvtData->avgForJitter - gapNS;
							if (gapJitter < 0) gapJitter = -gapJitter;
							pPvtData->jitter += (1.0/16.0) * ((float)gapJitter - pPvtData->jitter);
						}
					}
					pPvtData->prevNowTime = nowTime;
						
					if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
						S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
						U32 jitter = (U32)(pPvtData->jitter);
						
						AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Gap: %d NS  ", LOG_RT_DATATYPE_S32, &gapNS);
						AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Avg: %d NS  ", LOG_RT_DATATYPE_S32, &gapAvg);
						AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Max: %d NS  ", LOG_RT_DATATYPE_S32, &pPvtData->maxGapNS);
						AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
					  
						pPvtData->accumGapNS = 0;
						pPvtData->maxGapNS = 0;
						pPvtData->prevNowTime = 0;							
						pPvtData->servicedCount = 0;
						pPvtData->skipCountdown = 10;
						pPvtData->jitter = 0.0;
						pPvtData->avgForJitter = gapAvg;
					}
				}
				
			}
			openavbMediaQTailPull(pMediaQ);
		}
	}
	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
	return TRUE;
}
예제 #10
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=%lu, data-rate=%lu, frames=%u, size=%u, batch=%u, sleep=%" PRId64 ", sr-Kbps=%d, data-Kbps=%d",
		STREAMID_ARGS(&pTalkerData->streamID), (unsigned long)(pTalkerData->classRate), (unsigned long)(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;
}
예제 #11
0
// 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);
}
예제 #12
0
static inline bool talkerDoStream(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;
	bool bRet = FALSE;

	if (pTLState->bStreaming) {
		U64 nowNS;

		if (!pCfg->tx_blocking_in_intf) {

			// sleep until the next interval
			SLEEP_UNTIL_NSEC(pTalkerData->nextCycleNS);

			//AVB_DBG_INTERVAL(8000, TRUE);

			// send the frames for this interval
			int i;
			for (i = pTalkerData->wakeFrames; i > 0; i--) {
					if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, i == 1, pCfg->tx_blocking_in_intf)))
					pTalkerData->cntFrames++;
				else break;
				}
			}
		else {
			// Interface module block option
			if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, TRUE, pCfg->tx_blocking_in_intf)))
				pTalkerData->cntFrames++;
		}

		if (pTalkerData->cntWakes++ % pTalkerData->wakeRate == 0) {
			// time to service the endpoint IPC
			bRet = TRUE;
		}

		CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);

		if (pCfg->report_seconds > 0) {
			if (nowNS > pTalkerData->nextReportNS) {
			  
				S32 late = pTalkerData->wakesPerReport - pTalkerData->cntWakes;
				U64 bytes = openavbAvtpBytes(pTalkerData->avtpHandle);
				if (late < 0) late = 0;
				U32 txbuf = openavbAvtpTxBufferLevel(pTalkerData->avtpHandle);
				U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
			
				AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "TX UID:%d, ", LOG_RT_DATATYPE_U16, &pTalkerData->streamID.uniqueID);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntWakes);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntFrames);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "late=%d, ", LOG_RT_DATATYPE_U32, &late);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "txbuf=%d, ", LOG_RT_DATATYPE_U32, &txbuf);
				AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);

				openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes);
				openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames);
				openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, late);
				openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, bytes);

				pTalkerData->cntFrames = 0;
				pTalkerData->cntWakes = 0;
				pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);  
			}
		}

		if (nowNS > pTalkerData->nextSecondNS) {
			pTalkerData->nextSecondNS += NANOSECONDS_PER_SECOND;
			bRet = TRUE;
		}

		if (!pCfg->tx_blocking_in_intf) {
			pTalkerData->nextCycleNS += pTalkerData->intervalNS;

			if ((pTalkerData->nextCycleNS + (pCfg->max_transmit_deficit_usec * 1000)) < nowNS) {
				// Hit max deficit time. Something must be wrong. Reset the cycle timer.	
				// Align clock : allows for some performance gain
				nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS;
				pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS;
			}				
		}
	}
	else {
            SLEEP(1);
	    // time to service the endpoint IPC
	    bRet = TRUE;
	}

	AVB_TRACE_EXIT(AVB_TRACE_TL);
	return bRet;
}
예제 #13
0
/**********************************************
 * main
 */
int main(int argc, char *argv[])
{
	AVB_TRACE_ENTRY(AVB_TRACE_HOST);

	int iniIdx = 0;
	char *programName;
	char *optIfnameGlobal = NULL;

	programName = strrchr(argv[0], '/');
	programName = programName ? programName + 1 : argv[0];

	if (argc < 2) {
		openavbTlHostUsage(programName);
		exit(-1);
	}

	tl_handle_t *tlHandleList = NULL;
	int i1;

	// Process command line
	bool optDone = FALSE;
	while (!optDone) {
		int opt = getopt(argc, argv, "hI:");
		if (opt != EOF) {
			switch (opt) {
				case 'I':
					optIfnameGlobal = strdup(optarg);
					break;
				case 'h':
				default:
					openavbTlHostUsage(programName);
					exit(-1);
			}
		}
		else {
			optDone = TRUE;
		}
	}

	osalAVBInitialize(optIfnameGlobal);

	iniIdx = optind;
	U32 tlCount = argc - iniIdx;

	if (!openavbTLInitialize(tlCount)) {
		AVB_LOG_ERROR("Unable to initialize talker listener library");
		osalAVBFinalize();
		exit(-1);
	}

	// Setup signal handler
	// We catch SIGINT and shutdown cleanly
	bool err;
	struct sigaction sa;
	sa.sa_handler = openavbTLSigHandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	err = sigaction(SIGINT, &sa, NULL);
	if (err)
	{
		AVB_LOG_ERROR("Failed to setup SIGINT handler");
		osalAVBFinalize();
		exit(-1);
	}
	err = sigaction(SIGUSR1, &sa, NULL);
	if (err)
	{
		AVB_LOG_ERROR("Failed to setup SIGUSR1 handler");
		osalAVBFinalize();
		exit(-1);
	}

	registerStaticMapModule(openavbMapPipeInitialize);
	registerStaticMapModule(openavbMapAVTPAudioInitialize);
	registerStaticMapModule(openavbMapCtrlInitialize);
	registerStaticMapModule(openavbMapH264Initialize);
	registerStaticMapModule(openavbMapMjpegInitialize);
	registerStaticMapModule(openavbMapMpeg2tsInitialize);
	registerStaticMapModule(openavbMapNullInitialize);
	registerStaticMapModule(openavbMapUncmpAudioInitialize);

	registerStaticIntfModule(openavbIntfEchoInitialize);
	registerStaticIntfModule(openavbIntfCtrlInitialize);
	registerStaticIntfModule(openavbIntfLoggerInitialize);
	registerStaticIntfModule(openavbIntfNullInitialize);
	//registerStaticIntfModule(openavbIntfToneGenInitialize);
	registerStaticIntfModule(openavbIntfViewerInitialize);
	registerStaticIntfModule(openavbIntfAlsaInitialize);
	registerStaticIntfModule(openavbIntfMjpegGstInitialize);
	registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
	registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
	registerStaticIntfModule(openavbIntfWavFileInitialize);
	registerStaticIntfModule(openavbIntfH264RtpGstInitialize);

	tlHandleList = calloc(1, sizeof(tl_handle_t) * tlCount);

	// Open all streams
	for (i1 = 0; i1 < tlCount; i1++) {
		tlHandleList[i1] = openavbTLOpen();
	}

	// Parse ini and configure all streams
	for (i1 = 0; i1 < tlCount; i1++) {
		openavb_tl_cfg_t cfg;
		openavb_tl_cfg_name_value_t NVCfg;
		char iniFile[1024];

		snprintf(iniFile, sizeof(iniFile), "%s", argv[i1 + iniIdx]);

		if (optIfnameGlobal && !strcasestr(iniFile, ",ifname=")) {
			snprintf(iniFile + strlen(iniFile), sizeof(iniFile), ",ifname=%s", optIfnameGlobal);
		}

		openavbTLInitCfg(&cfg);
		memset(&NVCfg, 0, sizeof(NVCfg));

		if (!openavbTLReadIniFileOsal(tlHandleList[i1], iniFile, &cfg, &NVCfg)) {
			AVB_LOGF_ERROR("Error reading ini file: %s\n", argv[i1 + 1]);
			osalAVBFinalize();
			exit(-1);
		}
		if (!openavbTLConfigure(tlHandleList[i1], &cfg, &NVCfg)) {
			AVB_LOGF_ERROR("Error configuring: %s\n", argv[i1 + 1]);
			osalAVBFinalize();
			exit(-1);
		}

		int i2;
		for (i2 = 0; i2 < NVCfg.nLibCfgItems; i2++) {
			free(NVCfg.libCfgNames[i2]);
			free(NVCfg.libCfgValues[i2]);
		}
	}

#ifdef AVB_FEATURE_GSTREAMER
	// If we're supporting the interface modules which use GStreamer,
	// initialize GStreamer here to avoid errors.
	gst_init(0, NULL);
#endif

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLRun(tlHandleList[i1]);
	}

	while (bRunning) {
		sleep(1);
	}

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLStop(tlHandleList[i1]);
	}

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLClose(tlHandleList[i1]);
	}

	openavbTLCleanup();

#ifdef AVB_FEATURE_GSTREAMER
	// If we're supporting the interface modules which use GStreamer,
	// De-initialize GStreamer to clean up resources.
	gst_deinit();
#endif

	osalAVBFinalize();

	AVB_TRACE_EXIT(AVB_TRACE_HOST);
	exit(0);
}