Пример #1
0
/**
 * Synchronize thread timing with the audio sampling frequency.
 *
 * Time synchronization relies on the frame counter being linear. This counter
 * should be initialized upon transfer start and resume. With the size of this
 * counter being 32 bits, it is possible to track up to ~24 hours of playback,
 * with the sampling rate of 48 kHz. If this is insufficient, one can switch
 * to 64 bits, which would be sufficient to play for 12 million years. */
static int io_thread_time_sync(struct io_sync *io_sync, uint32_t frames) {

	const uint16_t sampling = io_sync->sampling;
	struct timespec ts_audio;
	struct timespec ts_clock;
	struct timespec ts;

	if (sampling == 0)
		return 0;

	/* calculate the playback duration of given frames */
	unsigned int sec = frames / sampling;
	unsigned int res = frames % sampling;
	int duration = 1000000 * sec + 1000000 / sampling * res;

	io_sync->frames += frames;
	frames = io_sync->frames;

	/* keep transfer 10ms ahead */
	unsigned int overframes = sampling / 100;
	frames = frames > overframes ? frames - overframes : 0;

	ts_audio.tv_sec = frames / sampling;
	ts_audio.tv_nsec = 1000000000 / sampling * (frames % sampling);

	gettimestamp(&ts_clock);

	/* Calculate delay since the last sync. Note, that we are not taking whole
	 * seconds into account, because if the delay is greater than one second,
	 * we are screwed anyway... */
	difftimespec(&io_sync->ts, &ts_clock, &ts);
	io_sync->delay = ts.tv_nsec / 100000;

	/* maintain constant bit rate */
	difftimespec(&io_sync->ts0, &ts_clock, &ts_clock);
	if (difftimespec(&ts_clock, &ts_audio, &ts) > 0)
		nanosleep(&ts, NULL);

	gettimestamp(&io_sync->ts);
	return duration;
}
Пример #2
0
int main(int argc, const char **argv){
  char buffer[4096]; /* According to http://stackoverflow.com/a/2879610/167486 POSIX suggests a line length of 4096 */
  double interval = 1.0;
  char *pend = NULL;
  int c = 0;
  const char *freqs = NULL;
  double freq = 0;
#ifdef USE_TIMESPEC
  struct timespec last;
  struct timespec now;
#else
  time_t last = 0;
  time_t now = 0;
#endif

  for (c = 1 ; c < argc ; ++c) {
    if (strcmp(argv[c], "--version") == 0) {
      version();
      return 0;
    }
    if (strcmp(argv[c], "--help") == 0) {
      usage();
      return 0;
    }
    else if ((c < argc - 1 && (strcmp(argv[c], "-f") == 0 || strcmp(argv[c], "--frequency") == 0)) || (argv[c][0] == '-' && argv[c][1] == 'f' && argv[c][2] >= '0' && argv[c][2] <= '9')) {
      if (argv[c][2] >= '0' && argv[c][2] <= '9') {
        freqs = &argv[c][2];
      }
      else {
        freqs = argv[c + 1];
      }
      freq = strtod(freqs, &pend);
      if (freq < DBL_EPSILON) {
        fprintf(stderr, "Frequency argument %f is out of range (expected a floating-point number larger than 0)\n", freq);
        usage();
        return 1;
      }
      else if (pend == NULL || *pend != '\0') {
        fprintf(stderr, "Could not parse frequency argument %s (expected an floating-point number larger than 0)\n", argv[c + 1]);
        usage();
        return 1;
      }
      interval = 1.0 / freq;
      c += 1;
    }
    else {
      fprintf(stderr, "Unrecognized argument %s\n", argv[c]);
      usage();
      return 1;
    }
  }

  setvbuf(stdout,NULL,_IOLBF,256);
  while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
#ifdef USE_TIMESPEC
    timespec_get(&now, TIME_UTC);
    if (difftimespec(&now, &last) >= interval) {
#else
    time(&now);
    if (difftime(now, last) >= interval) {
#endif
      puts(buffer);
      last = now;
    }
  }

  return 0;
}
Пример #3
0
int
main(int argc, char *argv[])
{
	struct sigaction act;
	struct timespec start, current, diff, intspec, wait;
	size_t i, len;
	int sflag, ret;
	char status[MAXLEN];
	const char *res;

	sflag = 0;
	ARGBEGIN {
		case 's':
			sflag = 1;
			break;
		default:
			usage();
	} ARGEND

	if (argc) {
		usage();
	}

	memset(&act, 0, sizeof(act));
	act.sa_handler = terminate;
	sigaction(SIGINT,  &act, NULL);
	sigaction(SIGTERM, &act, NULL);

	if (!sflag && !(dpy = XOpenDisplay(NULL))) {
		die("XOpenDisplay: Failed to open display");
	}

	while (!done) {
		if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
			die("clock_gettime:");
		}

		status[0] = '\0';
		for (i = len = 0; i < LEN(args); i++) {
			if (!(res = args[i].func(args[i].args))) {
				res = unknown_str;
			}
			if ((ret = esnprintf(status + len, sizeof(status) - len,
			                    args[i].fmt, res)) < 0) {
				break;
			}
			len += ret;
		}

		if (sflag) {
			puts(status);
			fflush(stdout);
			if (ferror(stdout))
				die("puts:");
		} else {
			if (XStoreName(dpy, DefaultRootWindow(dpy), status)
                            < 0) {
				die("XStoreName: Allocation failed");
			}
			XFlush(dpy);
		}

		if (!done) {
			if (clock_gettime(CLOCK_MONOTONIC, &current) < 0) {
				die("clock_gettime:");
			}
			difftimespec(&diff, &current, &start);

			intspec.tv_sec = interval / 1000;
			intspec.tv_nsec = (interval % 1000) * 1E6;
			difftimespec(&wait, &intspec, &diff);

			if (wait.tv_sec >= 0) {
				if (nanosleep(&wait, NULL) < 0 &&
				    errno != EINTR) {
					die("nanosleep:");
				}
			}
		}
	}

	if (!sflag) {
		XStoreName(dpy, DefaultRootWindow(dpy), NULL);
		if (XCloseDisplay(dpy) < 0) {
			die("XCloseDisplay: Failed to close display");
		}
	}

	return 0;
}
Пример #4
0
static void thread_ghost(void)
{   int i; /* loop variable */

    MSG("INFO: Ghost thread started.\n");

    /* local timekeeping variables */
    struct timespec send_time; /* time of the pull request */
    struct timespec recv_time; /* time of return from recv socket call */

    /* data buffers */
    uint8_t buff_down[GHST_MIN_PACKETSIZE+GHST_RX_BUFFSIZE]; /* buffer to receive downstream packets */
    uint8_t buff_req[12]; /* buffer to compose pull requests */
    int msg_len;

    /* protocol variables */
    bool req_ack = false; /* keep track of whether PULL_DATA was acknowledged or not */

    /* set downstream socket RX timeout */
    i = setsockopt(sock_ghost, SOL_SOCKET, SO_RCVTIMEO, (void *)&ghost_timeout, sizeof ghost_timeout);
    if (i != 0)
    { MSG("ERROR: [down] setsockopt returned %s\n", strerror(errno));
      exit(EXIT_FAILURE); }

    /* pre-fill the pull request buffer with fixed fields */
    buff_req[0] = PROTOCOL_VERSION;
    buff_req[3] = GHOST_DATA;
    *(uint32_t *)(buff_req + 4) = 0;
    *(uint32_t *)(buff_req + 8) = 0;

    /* aux variable for data copy */
    int  next;
    bool full;

    while (ghost_run)
    {   /* send PULL request and record time */
        // TODO zend later hier de data voor de nodes, nu alleen een pullreq.
        send(sock_ghost, (void *)buff_req, sizeof buff_req, 0);
        clock_gettime(CLOCK_MONOTONIC, &send_time);
        req_ack = false;
        MSG("MAIN LOOP ");
        /* listen to packets and process them until a new PULL request must be sent */
        recv_time = send_time;
        while ((int)difftimespec(recv_time, send_time) < NODE_CALL_SECS)
        {   /* try to receive a datagram */
            msg_len = recv(sock_ghost, (void *)buff_down, (sizeof buff_down)-1, 0);
            clock_gettime(CLOCK_MONOTONIC, &recv_time);

            /* if a network message was received, reset the wait time, otherwise continue */
            if (msg_len >= 0)
            {  send_time = recv_time; }
            else
            { continue; }

            /* if the datagram does not respect protocol, just ignore it */
            if ((msg_len < 4 + GHST_MIN_PACKETSIZE) || (msg_len > 4 + GHST_RX_BUFFSIZE) || (buff_down[0] != PROTOCOL_VERSION) || ((buff_down[3] != GHOST_DATA) ))
            { MSG("WARNING: [down] ignoring invalid packet\n");
              continue; }

            /* the datagram is a GHOST_DATA */
            buff_down[msg_len] = 0; /* add string terminator, just to be safe */

            /* Determine the next pointer where data can be written and see if the circular buffer is full */
            next  =  (ghst_bgn + 1) % GHST_NM_RCV;
            pthread_mutex_lock(&cb_ghost);
            full  =  next == ghst_end;
            pthread_mutex_unlock(&cb_ghost);

            /* make a copy ot the data received to the circular buffer, and shift the write index. */
            if (full)
            {  MSG("WARNING: ghost buffer is full, dropping packet)\n"); }
            else
            {  memcpy((void *)(buffRX+ghst_bgn*GHST_RX_BUFFSIZE),buff_down+4,msg_len-3);
               pthread_mutex_lock(&cb_ghost);
               ghst_bgn = next;
               pthread_mutex_unlock(&cb_ghost);
               MSG("RECEIVED, ghst_bgn = %i \n", ghst_bgn); } } }

    MSG("\nINFO: End of ghost thread\n");
}