event_t * event_create_action_str(const char *str) { action_type_t a = action_str2code(str); if(a == -1) return event_create_str(EVENT_DYNAMIC_ACTION, str); return event_create_action(a); }
static int pa_audio_start(audio_mode_t *am, audio_fifo_t *af) { pa_audio_mode_t *pam = (pa_audio_mode_t *)am; audio_buf_t *ab = NULL; size_t l, length; int64_t pts; media_pipe_t *mp; int r = 0; pa_threaded_mainloop_lock(mainloop); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "com.lonelycoder.hts.showtime"); pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "Showtime"); /* Create a new connection context */ pam->context = pa_context_new_with_proplist(api, "Showtime", pl); pa_proplist_free(pl); #else pam->context = pa_context_new(api, "Showtime"); #endif if(pam->context == NULL) { pa_threaded_mainloop_unlock(mainloop); return -1; } pa_context_set_state_callback(pam->context, context_state_callback, pam); /* Connect the context */ if(pa_context_connect(pam->context, NULL, 0, NULL) < 0) { TRACE(TRACE_ERROR, "PA", "pa_context_connect() failed: %s", pa_strerror(pa_context_errno(pam->context))); pa_threaded_mainloop_unlock(mainloop); return -1; } /* Need at least one packet of audio */ /* Subscribe to updates of master volume */ pam->sub_mvol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, pam, PROP_TAG_ROOT, prop_mastervol, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); /* Subscribe to updates of master volume mute */ pam->sub_mute = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_INT, set_mastermute, pam, PROP_TAG_ROOT, prop_mastermute, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); while(1) { if(ab == NULL) { pa_threaded_mainloop_unlock(mainloop); ab = af_deq2(af, 1, am); pa_threaded_mainloop_lock(mainloop); if(ab == AF_EXIT) { ab = NULL; break; } } if(pa_context_get_state(pam->context) == PA_CONTEXT_TERMINATED || pa_context_get_state(pam->context) == PA_CONTEXT_FAILED) { r = -1; break; } if(pam->stream != NULL && (pam->cur_format != ab->ab_format || pam->cur_rate != ab->ab_samplerate || pam->cur_isfloat != ab->ab_isfloat)) { stream_destroy(pam); } if(pam->stream == NULL && pa_context_get_state(pam->context) == PA_CONTEXT_READY) { /* Context is ready, but we don't have a stream yet, set it up */ stream_setup(pam, ab); } if(pam->stream == NULL) { pa_threaded_mainloop_wait(mainloop); continue; } switch(pa_stream_get_state(pam->stream)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: break; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_stream_unref(pam->stream); pam->stream = NULL; char msg[100]; snprintf(msg, sizeof(msg), "Audio stream disconnected from " "PulseAudio server -- %s.", pa_strerror(pam->stream_error)); mp_flush(ab->ab_mp, 0); mp_enqueue_event(ab->ab_mp, event_create_str(EVENT_INTERNAL_PAUSE, msg)); audio_fifo_purge(af, NULL, NULL); if(ab != NULL) { ab_free(ab); ab = NULL; } continue; } if(ab->ab_flush) { pa_operation *o; o = pa_stream_flush(pam->stream, NULL, NULL); if(o != NULL) pa_operation_unref(o); ab->ab_flush = 0; } l = pa_stream_writable_size(pam->stream); if(l == 0) { pa_threaded_mainloop_wait(mainloop); continue; } length = ab->ab_frames * pa_frame_size(&pam->ss) - ab->ab_tmp; if(l > length) l = length; if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { int64_t pts; pa_usec_t delay; pts = ab->ab_pts; ab->ab_pts = AV_NOPTS_VALUE; if(!pa_stream_get_latency(pam->stream, &delay, NULL)) { mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } pa_stream_write(pam->stream, ab->ab_data + ab->ab_tmp, l, NULL, 0LL, PA_SEEK_RELATIVE); ab->ab_tmp += l; assert(ab->ab_tmp <= ab->ab_frames * pa_frame_size(&pam->ss)); if(ab->ab_frames * pa_frame_size(&pam->ss) == ab->ab_tmp) { ab_free(ab); ab = NULL; } } prop_unsubscribe(pam->sub_mvol); prop_unsubscribe(pam->sub_mute); if(pam->stream != NULL) stream_destroy(pam); pa_threaded_mainloop_unlock(mainloop); pa_context_unref(pam->context); if(ab != NULL) { ab_free(ab); ab = NULL; } return r; }
static void * lirc_thread(void *aux) { char buf[200]; uint64_t ircode; uint32_t repeat; char keyname[100]; int i, r, fd, len, n; htsbuf_queue_t q; struct pollfd fds; event_t *e; fd = lirc_fd; htsbuf_queue_init(&q, 0); fds.fd = fd; fds.events = POLLIN; while(1) { r = poll(&fds, 1, -1); if(r > 0) { if((r = read(fd, buf, sizeof(buf))) < 1) { TRACE(TRACE_ERROR, "lircd", "Read error: %s", strerror(errno)); break; } htsbuf_append(&q, buf, r); } while((len = htsbuf_find(&q, 0xa)) != -1) { if(len >= sizeof(buf) - 1) { TRACE(TRACE_ERROR, "lircd", "Command buffer size exceeded"); goto out; } htsbuf_read(&q, buf, len); buf[len] = 0; while(len > 0 && buf[len - 1] < 32) buf[--len] = 0; htsbuf_drop(&q, 1); /* Drop the \n */ n = sscanf(buf, "%"PRIx64" %x %s", &ircode, &repeat, keyname); if(n != 3) { TRACE(TRACE_INFO, "lircd", "Invalid LIRC input: \"%s\"", buf); continue; } if(keyname[0] && keyname[1] == 0) { /* ASCII input */ e = event_create_int(EVENT_UNICODE, keyname[0]); } else { e = NULL; for(i = 0; i < sizeof(lircmap) / sizeof(lircmap[0]); i++) { if(!strcasecmp(keyname, lircmap[i].name)) { action_type_t av[3] = { lircmap[i].action1, lircmap[i].action2, }; if(av[1] != ACTION_NONE) e = event_create_action_multi(av, 2); else e = event_create_action_multi(av, 1); break; } } } if(e == NULL) { snprintf(buf, sizeof(buf), "IR+%s", keyname); e = event_create_str(EVENT_KEYDESC, buf); } event_to_ui(e); } } out: close(fd); htsbuf_queue_flush(&q); return NULL; }
static void handle_kb(glw_ps3_t *gp) { KbInfo kbinfo; KbData kbdata; int i, j; int uc; event_t *e; action_type_t av[3]; int mods; if(ioKbGetInfo(&kbinfo)) return; for(i=0; i<MAX_KEYBOARDS; i++) { if(kbinfo.status[i] == 0) { if(gp->kb_present[i]) TRACE(TRACE_INFO, "PS3", "Keyboard %d disconnected", i); } else { if(!gp->kb_present[i]) { ioKbGetConfiguration(i, &gp->kb_config[i]); TRACE(TRACE_INFO, "PS3", "Keyboard %d connected, mapping=%d, rmode=%d, codetype=%d", i, gp->kb_config[i].mapping, gp->kb_config[i].rmode, gp->kb_config[i].codetype); ioKbSetCodeType(i, KB_CODETYPE_RAW); } if(!ioKbRead(i, &kbdata)) { for(j = 0; j < kbdata.nb_keycode; j++) { if(0) TRACE(TRACE_DEBUG, "PS3", "Keystrike %x %x %x %x", gp->kb_config[i].mapping, kbdata.mkey.mkeys, kbdata.led.leds, kbdata.keycode[j]); uc = ioKbCnvRawCode(gp->kb_config[i].mapping, kbdata.mkey, kbdata.led, kbdata.keycode[j]); mods = 0; if(kbdata.mkey.l_shift || kbdata.mkey.r_shift) mods |= KB_SHIFTMASK; if(kbdata.mkey.l_alt || kbdata.mkey.r_alt) mods |= KB_ALTMASK; if(kbdata.mkey.l_ctrl || kbdata.mkey.r_ctrl) mods |= KB_CTRLMASK; for(i = 0; i < sizeof(kb2action) / sizeof(*kb2action); i++) { if(kb2action[i].code == uc && (kb2action[i].modifier == -1 || kb2action[i].modifier == mods)) { av[0] = kb2action[i].action1; av[1] = kb2action[i].action2; av[2] = kb2action[i].action3; if(kb2action[i].action3 != ACTION_NONE) e = event_create_action_multi(av, 3); else if(kb2action[i].action2 != ACTION_NONE) e = event_create_action_multi(av, 2); else if(kb2action[i].action1 != ACTION_NONE) e = event_create_action_multi(av, 1); else if(kb2action[i].sym != NULL) { char buf[128]; snprintf(buf, sizeof(buf), "%s%s%s%s", mods & KB_SHIFTMASK ? "Shift+" : "", mods & KB_ALTMASK ? "Alt+" : "", mods & KB_CTRLMASK ? "Ctrl+" : "", kb2action[i].sym); e = event_create_str(EVENT_KEYDESC, buf); } else { e = NULL; } if(e != NULL) { glw_dispatch_event(&gp->gr.gr_uii, e); event_release(e); break; } } } if(i == sizeof(kb2action) / sizeof(*kb2action) && uc < 0x8000 && uc) { e = event_create_int(EVENT_UNICODE, uc); glw_dispatch_event(&gp->gr.gr_uii, e); event_release(e); } } } } gp->kb_present[i] = kbinfo.status[i]; } }