enum AVPixelFormat get_format(struct AVCodecContext *s, const enum AVPixelFormat *fmt) { struct pp_video_decoder_s *vd = s->opaque; int have_vaapi = 0; int have_vdpau = 0; for (int k = 0; fmt[k] != AV_PIX_FMT_NONE; k ++) { if (fmt[k] == AV_PIX_FMT_VAAPI_VLD) have_vaapi = display.va_available; if (fmt[k] == AV_PIX_FMT_VDPAU) have_vdpau = 1; } trace_info_f(" VDPAU: %s\n", have_vdpau ? "present" : "not present"); trace_info_f(" VA-API: %s\n", have_vaapi ? "present" : "not present"); if (have_vaapi) { return prepare_vaapi_context(vd, s->width, s->height); } (void)have_vdpau; // TODO: VDPAU support // nothing found, using default return fmt[0]; }
APULSE_EXPORT char * pa_get_binary_name(char *s, size_t len) { trace_info_f("F %s s=%p, len=%d\n", __func__, s, (int)len); if (len == 0) return NULL; char fullpath[PATH_MAX]; ssize_t flen = readlink("/proc/self/exe", fullpath, sizeof(fullpath) - 1); if (flen < 0) return NULL; // ensure fullpath ends with '\0' flen = MIN(flen, sizeof(fullpath) - 1); fullpath[flen] = 0; char *name = basename(fullpath); size_t name_len = strlen(name); // copy no more than len bytes to s name_len = MIN(name_len, len - 1); memcpy(s, name, name_len); s[name_len] = 0; return s; }
char * NP_GetPluginVersion(void) { trace_info_f("[NP] %s\n", __func__); load_ppp_module(); return module_version; }
APULSE_EXPORT const char * pa_stream_get_device_name(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return "apulse"; }
APULSE_EXPORT int pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream) { gchar *s_attr = trace_pa_buffer_attr_as_string(attr); trace_info_f("P %s s=%p, dev=%s, attr=%s, flags=0x%x, volume=%p, sync_stream=%p\n", __func__, s, dev, s_attr, flags, volume, sync_stream); g_free(s_attr); s->direction = PA_STREAM_PLAYBACK; if (attr) { s->buffer_attr = *attr; } else { s->buffer_attr.maxlength = (uint32_t)-1; s->buffer_attr.tlength = (uint32_t)-1; s->buffer_attr.prebuf = (uint32_t)-1; s->buffer_attr.minreq = (uint32_t)-1; s->buffer_attr.fragsize = (uint32_t)-1; } if (do_connect_pcm(s, SND_PCM_STREAM_PLAYBACK) != 0) goto err; g_atomic_int_set(&s->paused, !!(flags & PA_STREAM_START_CORKED)); return 0; err: return -1; }
APULSE_EXPORT int pa_stream_is_corked(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return g_atomic_int_get(&s->paused); }
APULSE_EXPORT uint32_t pa_context_get_protocol_version(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); return PA_PROTOCOL_VERSION; }
char * NP_GetPluginVersion(void) { trace_info_f("%s\n", __func__); // hope browser won't write to the value return (char *)fpp_config_get_default_plugin_version(); }
NPError NPP_New(NPMIMEType pluginType, NPP npp, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { trace_info_f("%s\n", __func__); NPObject *np_plugin_element_obj; int err = npn.getvalue(npp, NPNVPluginElementNPObject, &np_plugin_element_obj); if (err != NPERR_NO_ERROR) { trace_warning("%s, NPN_GetValue returned %d\n", __func__, err); goto done; } NPVariant result; NPString script = { .UTF8Characters = resource_text_libpdf_frontend_js, .UTF8Length = strlen(resource_text_libpdf_frontend_js), }; if (!npn.evaluate(npp, np_plugin_element_obj, &script, &result)) { trace_warning("%s, NPN_Evaluate failed\n", __func__); } done: return NPERR_NO_ERROR; }
APULSE_EXPORT int pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { gchar *s_attr = trace_pa_buffer_attr_as_string(attr); trace_info_f("P %s s=%p, dev=%s, attr=%s, flags=0x%x\n", __func__, s, dev, s_attr, flags); g_free(s_attr); s->direction = PA_STREAM_RECORD; if (attr) { s->buffer_attr = *attr; } else { s->buffer_attr.maxlength = (uint32_t)-1; s->buffer_attr.tlength = (uint32_t)-1; s->buffer_attr.prebuf = (uint32_t)-1; s->buffer_attr.minreq = (uint32_t)-1; s->buffer_attr.fragsize = (uint32_t)-1; } if (do_connect_pcm(s, SND_PCM_STREAM_CAPTURE) != 0) goto err; snd_pcm_start(s->ph); return 0; err: return -1; }
APULSE_EXPORT int pa_stream_write(pa_stream *s, const void *data, size_t nbytes, pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek) { trace_info_f("F %s s=%p, data=%p, nbytes=%zu, free_cb=%p, offset=%"PRId64", seek=%u\n", __func__, s, data, nbytes, free_cb, offset, seek); if (offset != 0) trace_error("%s, offset != 0\n", __func__); if (seek != PA_SEEK_RELATIVE) trace_error("%s, seek != PA_SEEK_RELATIVE\n", __func__); size_t written = ringbuffer_write(s->rb, data, nbytes); s->timing_info.since_underrun += written; s->timing_info.write_index += written; if (data == s->write_buffer) { free(s->write_buffer); s->write_buffer = NULL; } else { if (free_cb) free_cb((void *)data); } return 0; }
APULSE_EXPORT size_t pa_stream_readable_size(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return ringbuffer_readable_size(s->rb); }
NPError NP_Initialize(NPNetscapeFuncs *aNPNFuncs, NPPluginFuncs *aNPPFuncs) { trace_info_f("[NP] %s aNPNFuncs=%p, aNPPFuncs=%p, browser API version = %u\n", __func__, aNPNFuncs, aNPPFuncs, aNPNFuncs->version); // set logging-only error handler. // Ignore a previous one, we have no plans to restore it (void)XSetErrorHandler(x_error_handler); (void)XSetIOErrorHandler(x_io_error_hanlder); memset(&npn, 0, sizeof(npn)); memcpy(&npn, aNPNFuncs, sizeof(npn) < aNPNFuncs->size ? sizeof(npn) : aNPNFuncs->size); NPPluginFuncs pf; memset(&pf, 0, sizeof(NPPluginFuncs)); pf.size = MIN(aNPPFuncs->size, sizeof(NPPluginFuncs)); // browser is supposed to fill .size and .version pf.newp = NPP_New; pf.destroy = NPP_Destroy; pf.setwindow = NPP_SetWindow; pf.newstream = NPP_NewStream; pf.destroystream = NPP_DestroyStream; pf.asfile = NPP_StreamAsFile; pf.writeready = NPP_WriteReady; pf.write = NPP_Write; pf.print = NPP_Print; pf.event = NPP_HandleEvent; pf.urlnotify = NPP_URLNotify; pf.getvalue = NPP_GetValue; pf.setvalue = NPP_SetValue; pf.gotfocus = NPP_GotFocus; pf.lostfocus = NPP_LostFocus; pf.urlredirectnotify = NPP_URLRedirectNotify; pf.clearsitedata = NPP_ClearSiteData; pf.getsiteswithdata = NPP_GetSitesWithData; pf.didComposite = NPP_DidComposite; memcpy(aNPPFuncs, &pf, pf.size); if (tables_open_display() != 0) return NPERR_GENERIC_ERROR; if (aNPNFuncs->version < NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) { config.quirks.plugin_missing = 1; config.quirks.incompatible_npapi_version = 1; } load_ppp_module(); int res = call_plugin_init_module(); if (res != 0) { trace_error("%s, PPP_InitializeModule returned %d\n", __func__, res); return NPERR_GENERIC_ERROR; } return NPERR_NO_ERROR; }
APULSE_EXPORT const pa_sample_spec * pa_stream_get_sample_spec(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return &s->ss; }
APULSE_EXPORT void pa_context_disconnect(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); pai_context_set_state(c, PA_CONTEXT_TERMINATED); }
APULSE_EXPORT void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pthread_mutex_lock(&m->lock); }
APULSE_EXPORT int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return pthread_equal(pthread_self(), m->t); }
APULSE_EXPORT pa_mainloop_api * pa_threaded_mainloop_get_api(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return &m->m->api; }
APULSE_EXPORT uint32_t pa_stream_get_index(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return s->idx; }
APULSE_EXPORT pa_operation * pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); return pa_operation_new(s->c->mainloop_api, PAOP_STREAM_TRIGGER, s, NULL, cb, userdata); }
APULSE_EXPORT const pa_buffer_attr * pa_stream_get_buffer_attr(pa_stream *s) { trace_info_f("F %s\n", __func__); return &s->buffer_attr; }
APULSE_EXPORT pa_operation * pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); return pa_operation_new(s->c->mainloop_api, PAOP_STREAM_UPD_TIMING_INFO, s, NULL, cb, userdata); }
APULSE_EXPORT pa_stream_state_t pa_stream_get_state(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return s->state; }
APULSE_EXPORT int pa_stream_is_suspended(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); // ALSA sink is never suspended return 0; }
APULSE_EXPORT const char * pa_strerror(int error) { trace_info_f("P %s error=%d\n", __func__, error); return "Oops."; }
APULSE_EXPORT void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pthread_cond_wait(&m->cond, &m->lock); }
APULSE_EXPORT const char * pa_get_library_version(void) { trace_info_f("F %s (void)\n", __func__); return pa_get_headers_version(); }
NPError NPP_Destroy(NPP npp, NPSavedData **save) { trace_info_f("%s\n", __func__); if (save) *save = NULL; return NPERR_NO_ERROR; }
APULSE_EXPORT uint32_t pa_stream_get_device_index(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); // apulse uses only one sink -- ALSA device, so index is always 0 return 0; }
static uintptr_t do_load_ppp_module(const char *fname) { tried_files = g_list_prepend(tried_files, g_strdup(fname)); module_dl_handler = dlopen(fname, RTLD_LAZY); if (!module_dl_handler) { trace_info_f("%s, can't open %s\n", __func__, fname); return 1; } int32_t (*ppp_initialize_module)(PP_Module module_id, PPB_GetInterface get_browser_interface); ppp_initialize_module = dlsym(module_dl_handler, "PPP_InitializeModule"); ppp_get_interface = dlsym(module_dl_handler, "PPP_GetInterface"); if (!ppp_initialize_module || !ppp_get_interface) { trace_error("%s, one of required PPP_* is missing\n", __func__); if (module_dl_handler) dlclose(module_dl_handler); module_dl_handler = NULL; return 1; } module_file_name = g_strdup(fname); if (!fpp_config_plugin_has_manifest()) { use_fallback_version_strings(); return 0; } // try to read manifest.json file (only for those who can have it) char *manifest_dir = strdup(fname); gchar *manifest_path = g_strdup_printf("%s/manifest.json", dirname(manifest_dir)); free(manifest_dir); JSON_Value *root_val = json_parse_file(manifest_path); g_free(manifest_path); if (!root_val) { use_fallback_version_strings(); return 0; } JSON_Object *root_obj = json_value_get_object(root_val); const char *version = json_object_get_string(root_obj, "version"); if (version) { int v1 = 0, v2 = 0, v3 = 0, v4 = 0; module_version = g_strdup(version); (void)sscanf(module_version, "%9d.%9d.%9d.%9d", &v1, &v2, &v3, &v4); module_descr = g_strdup_printf("%s %d.%d r%d", fpp_config_get_plugin_name(), v1, v2, v3); } else { use_fallback_version_strings(); } json_value_free(root_val); return 0; }