static void ch_close(struct senseye_ch* ch) { if (!ch || !ch->in_pr) return; ch_flush(ch); struct senseye_priv* chp = ch->in_pr; arcan_shmif_drop(&chp->cont); ch->in->free(&ch->in); chp->running = false; }
int main(int argc, char** argv) { struct arg_arr* aarr; struct arcan_shmif_cont cont = arcan_shmif_open( SEGID_APPLICATION, SHMIF_ACQUIRE_FATALFAIL, &aarr); arcan_event ev = { .ext.kind = ARCAN_EVENT(CLOCKREQ), .ext.clock.rate = 2, .ext.clock.dynamic = (argc > 1 && strcmp(argv[1], "dynamic") == 0) }; arcan_shmif_enqueue(&cont, &ev); ev.ext.clock.dynamic = false; int tbl[] = {20, 40, 42, 44, 60, 80, 86, 88, 100, 120}; int step = 0; for (size_t i=0; i < sizeof(tbl)/sizeof(tbl[0]); i++){ ev.ext.clock.once = true; ev.ext.clock.rate = tbl[i]; ev.ext.clock.id = i + 2; /* 0 index and 1 is reserved */ arcan_shmif_enqueue(&cont, &ev); } while(arcan_shmif_wait(&cont, &ev) != 0){ if (ev.category == EVENT_TARGET) switch(ev.tgt.kind){ case TARGET_COMMAND_STEPFRAME: printf("step: %d, source: %d\n", ev.tgt.ioevs[0].iv, ev.tgt.ioevs[1].iv); if (ev.tgt.ioevs[1].iv > 1){ if (step == ev.tgt.ioevs[1].iv-2) printf("custom timer %d OK\n", step); else printf("timer out of synch, expected %d got %d\n", step, ev.tgt.ioevs[1].iv-2); step++; } break; case TARGET_COMMAND_EXIT: goto done; /* break(1), please */ default: break; } } done: arcan_shmif_drop(&cont); return EXIT_SUCCESS; }
int a12helper_a12srv_shmifcl( struct a12_state* S, const char* cp, int fd_in, int fd_out) { if (!cp) cp = getenv("ARCAN_CONNPATH"); else setenv("ARCAN_CONNPATH", cp, 1); if (!cp){ debug_print(1, "No connection point was specified"); return -ENOENT; } /* Channel - connection mapping */ struct cl_state cl_state = {}; /* Open / set the primary connection */ cl_state.wnd[0] = arcan_shmif_open(SEGID_UNKNOWN, SHMIF_NOACTIVATE, NULL); if (!cl_state.wnd[0].addr){ debug_print(1, "Couldn't connect to an arcan display server"); return -ENOENT; } cl_state.n_segments = 1; debug_print(1, "Segment connected"); a12_set_destination(S, &cl_state.wnd[0], 0); /* set to non-blocking */ int flags = fcntl(fd_in, F_GETFL); fcntl(fd_in, F_SETFL, flags | O_NONBLOCK); uint8_t* outbuf; size_t outbuf_sz = 0; debug_print(1, "got proxy connection, waiting for source"); int status; while (-1 != (status = a12helper_poll_triple( cl_state.wnd[0].epipe, fd_in, outbuf_sz ? fd_out : -1, 4))){ if (status & A12HELPER_WRITE_OUT){ if (outbuf_sz || (outbuf_sz = a12_channel_flush(S, &outbuf))){ ssize_t nw = write(fd_out, outbuf, outbuf_sz); if (nw > 0){ outbuf += nw; outbuf_sz -= nw; } } } if (status & A12HELPER_DATA_IN){ uint8_t inbuf[9000]; ssize_t nr = read(fd_in, inbuf, 9000); if (-1 == nr && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){ debug_print(1, "failed to read from input: %d", errno); break; } debug_print(2, "unpack %zd bytes", nr); a12_channel_unpack(S, inbuf, nr, NULL, on_cl_event); } /* 1 client can have multiple segments */ for (size_t i = 0, count = cl_state.n_segments; i < 256 && count; i++){ if (!cl_state.wnd[i].addr) continue; count--; struct arcan_event newev; int sc; while (( sc = arcan_shmif_poll(&cl_state.wnd[i], &newev)) > 0){ /* we got a descriptor passing event, some of these we could/should discard, * while others need to be forwarded as a binary- chunk stream and kept out- * of order on the other side */ if (arcan_shmif_descrevent(&newev)){ debug_print(1, "(cl:%zu) ign-descr-event: %s", i, arcan_shmif_eventstr(&newev, NULL, 0)); } else { debug_print(2, "enqueue %s", arcan_shmif_eventstr(&newev, NULL, 0)); a12_channel_enqueue(S, &newev); } } } /* we might have gotten data to flush, so use that as feedback */ if (!outbuf_sz){ outbuf_sz = a12_channel_flush(S, &outbuf); if (outbuf_sz) debug_print(2, "output buffer size: %zu", outbuf_sz); } } /* though a proper cleanup would cascade, it doesn't help being careful */ for (size_t i = 0, count = cl_state.n_segments; i < 256 && count; i++){ if (!cl_state.wnd[i].addr) continue; arcan_shmif_drop(&cl_state.wnd[i]); cl_state.wnd[i].addr = NULL; } return 0; }