/** * 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; }
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; }
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, ¤t) < 0) { die("clock_gettime:"); } difftimespec(&diff, ¤t, &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; }
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"); }