PP_Resource ppb_image_data_create(PP_Instance instance, PP_ImageDataFormat format, const struct PP_Size *size, PP_Bool init_to_zero) { (void)instance; PP_Resource image_data = pp_resource_allocate(PP_RESOURCE_IMAGE_DATA, instance); struct pp_image_data_s *id = pp_resource_acquire(image_data, PP_RESOURCE_IMAGE_DATA); if (!id) { trace_warning("%s, failed to create image data resource\n", __func__); return 0; } id->format = format; id->width = size->width; id->height = size->height; id->stride = id->width * 4; (void)init_to_zero; // ignore flag, always clear memory id->data = calloc(id->stride * id->height, 1); if (!id->data) { pp_resource_release(image_data); ppb_core_release_resource(image_data); trace_warning("%s, can't allocate memory for image\n", __func__); return 0; } id->cairo_surf = cairo_image_surface_create_for_data((void *)id->data, CAIRO_FORMAT_ARGB32, id->width, id->height, id->stride); pp_resource_release(image_data); return image_data; }
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; }
struct PP_Var ppb_url_util_dev_resolve_relative_to_url(struct PP_Var base_url, struct PP_Var relative_string, struct PP_URLComponents_Dev *components) { reset_components(components); struct PP_Var var = PP_MakeNull(); if (base_url.type != PP_VARTYPE_STRING) { trace_warning("%s, base_url is not a string\n", __func__); return PP_MakeNull(); } if (relative_string.type != PP_VARTYPE_STRING) { trace_warning("%s, relative_string is not a string\n", __func__); return PP_MakeNull(); } const char *s_base_url = ppb_var_var_to_utf8(base_url, NULL); const char *s_relative_string = ppb_var_var_to_utf8(relative_string, NULL); UriParserStateA ups; UriUriA uri_base, uri_rel, uri_result; ups.uri = &uri_base; if (uriParseUriA(&ups, s_base_url) != URI_SUCCESS) { trace_warning("%s, can't parse s_base_url\n", __func__); goto err_1; } ups.uri = &uri_rel; if (uriParseUriA(&ups, s_relative_string) != URI_SUCCESS) { trace_warning("%s, can't parse s_relative_string\n", __func__); goto err_2; } if (uriAddBaseUriA(&uri_result, &uri_rel, &uri_base) != URI_SUCCESS) { trace_warning("%s, can't merge base and rel\n", __func__); goto err_3; } int len; uriToStringCharsRequiredA(&uri_result, &len); len++; char *str = malloc(len); uriToStringA(str, &uri_result, len, NULL); var = ppb_var_var_from_utf8_z(str); free(str); if (components) parse_url_string(str, components); err_3: uriFreeUriMembersA(&uri_result); err_2: uriFreeUriMembersA(&uri_rel); err_1: uriFreeUriMembersA(&uri_base); return var; }
/** * \brief Send single buffer data through DMA */ static void _usart_dma_tx(const uint8_t* buffer, uint32_t len ) { struct _buffer tx = { .data = (unsigned char*)buffer, .size = len }; usartd_transfert(&usart_desc, 0, &tx, _us_dma_tx_callback, 0); } /** * Callback invoked when data has been received on the USB. */ static void _usb_data_received(void *read, uint8_t status, uint32_t received, uint32_t remaining) { /* Check that data has been received successfully */ if (status == USBD_STATUS_SUCCESS) { *(uint8_t *)read = 1; /* Send back CDC data */ if (is_cdc_echo_on){ cdcd_serial_driver_write(usb_buffer, received, 0, 0); } /* Send data through USART */ if (is_cdc_serial_on) { _usart_dma_tx( usb_buffer, received ); } /* Check if bytes have been discarded */ if ((received == DATAPACKETSIZE) && (remaining > 0)) { trace_warning( "_usb_data_received: %u bytes discarded\n\r", (unsigned int)remaining); } } else { trace_warning( "_usb_data_received: Transfer error\n\r"); } } /** * console help dump */ static void _debug_help(void) { printf("-- ESC to Enable/Disable ECHO on cdc serial --\n\r"); printf("-- Press 't' to test trasfer --\n\r"); }
static void handle_tcp_connect_stage1(struct async_network_task_s *task) { struct evdns_request *req; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); if (inet_pton(AF_INET, task->host, &sai.sin_addr) == 1) { // already a valid IP address handle_tcp_connect_stage2(DNS_ERR_NONE, DNS_IPv4_A, 1, 300, &sai.sin_addr, task); return; } // queue DNS request req = evdns_base_resolve_ipv4(evdns_b, task->host, DNS_QUERY_NO_SEARCH, handle_tcp_connect_stage2, task); // TODO: what about ipv6? if (!req) { trace_warning("%s, early dns resolution failure (%s:%u)\n", __func__, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_NAME_NOT_RESOLVED, 0, __func__); task_destroy(task); return; } }
/** * Handles composite-specific USB requests sent by the host, and forwards * standard ones to the USB device driver. * \param request Pointer to a USBGenericRequest instance. */ void dual_cdcd_driver_request_handler(const USBGenericRequest *request) { CDCDSerialPort *p_cdcd = 0; uint32_t rc, i; LIBUSB_TRACE("NewReq "); for (i = 0; i < NUM_PORTS; i ++) { p_cdcd = &dual_cdcd_driver.cdcd_serial_port[i]; rc = cdcd_serial_port_request_handler(p_cdcd, request); if (rc == USBRC_SUCCESS) break; } /* Not handled by CDC Serial */ if (rc != USBRC_SUCCESS) { if (usb_generic_request_get_type(request) == USBGenericRequest_STANDARD) { usbd_driver_request_handler(request); } else { trace_warning("dual_cdcd_driver_request_handler: Unsupported request (%d,%d)\n\r", usb_generic_request_get_type(request), usb_generic_request_get_request(request)); usbd_stall(0); } } }
static void handle_tcp_connect_stage4(int sock, short event_flags, void *arg) { struct async_network_task_s *task = arg; struct pp_tcp_socket_s *ts = pp_resource_acquire(task->resource, PP_RESOURCE_TCP_SOCKET); if (!ts) { trace_warning("%s, tcp socket resource was closed during request (%s:%u)\n", __func__, task->host, (unsigned int)task->port); free(task->addr); task_destroy(task); return; } char buf[200]; socklen_t len = sizeof(buf); if (event_flags & EV_TIMEOUT) ts->is_connected = 0; else ts->is_connected = (getpeername(ts->sock, (struct sockaddr *)buf, &len) == 0); if (ts->is_connected) { ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_OK, 0, __func__); pp_resource_release(task->resource); free(task->addr); task_destroy(task); return; } // try other addresses, one by one task->addr_ptr++; if (task->addr_ptr < task->addr_count) { pp_resource_release(task->resource); handle_tcp_connect_stage3(task); return; } // no addresses left, fail gracefully trace_warning("%s, connection failed to all addresses (%s:%u)\n", __func__, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, get_pp_errno(), 0, __func__); pp_resource_release(task->resource); free(task->addr); task_destroy(task); }
PP_Resource ppb_graphics2d_create(PP_Instance instance, const struct PP_Size *size, PP_Bool is_always_opaque) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } PP_Resource graphics_2d = pp_resource_allocate(PP_RESOURCE_GRAPHICS2D, pp_i); struct pp_graphics2d_s *g2d = pp_resource_acquire(graphics_2d, PP_RESOURCE_GRAPHICS2D); if (!g2d) { trace_error("%s, can't create graphics2d resource\n", __func__); return 0; } g2d->is_always_opaque = is_always_opaque; g2d->scale = config.device_scale; g2d->width = size->width; g2d->height = size->height; g2d->stride = 4 * size->width; g2d->scaled_width = g2d->width * g2d->scale + 0.5; g2d->scaled_height = g2d->height * g2d->scale + 0.5; g2d->scaled_stride = 4 * g2d->scaled_width; g2d->data = calloc(g2d->stride * g2d->height, 1); g2d->second_buffer = calloc(g2d->scaled_stride * g2d->scaled_height, 1); if (!g2d->data || !g2d->second_buffer) { trace_warning("%s, can't allocate memory\n", __func__); free_and_nullify(g2d->data); free_and_nullify(g2d->second_buffer); pp_resource_release(graphics_2d); ppb_core_release_resource(graphics_2d); return 0; } g2d->cairo_surf = cairo_image_surface_create_for_data((unsigned char *)g2d->data, CAIRO_FORMAT_ARGB32, g2d->width, g2d->height, g2d->stride); g2d->task_list = NULL; if (pp_i->is_transparent) { // we need XRender picture (which in turn requires X Pixmap) to alpha blend // our images with existing pixmap provided by the browser. This is only needed // is instance is transparent, therefore depth is always 32-bit. pthread_mutex_lock(&display.lock); g2d->pixmap = XCreatePixmap(display.x, DefaultRootWindow(display.x), g2d->scaled_width, g2d->scaled_height, 32); XFlush(display.x); g2d->xr_pict = XRenderCreatePicture(display.x, g2d->pixmap, display.pictfmt_argb32, 0, 0); g2d->gc = XCreateGC(display.x, g2d->pixmap, 0, 0); XFlush(display.x); pthread_mutex_unlock(&display.lock); } pp_resource_release(graphics_2d); return graphics_2d; }
int32_t ppb_tcp_socket_read(PP_Resource tcp_socket, char *buffer, int32_t bytes_to_read, struct PP_CompletionCallback callback) { if (bytes_to_read <= 0) { trace_error("%s, bytes_to_read <= 0\n", __func__); return PP_ERROR_BADARGUMENT; } struct pp_tcp_socket_s *ts = pp_resource_acquire(tcp_socket, PP_RESOURCE_TCP_SOCKET); if (!ts) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (!ts->is_connected) { trace_warning("%s, not connected\n", __func__); pp_resource_release(tcp_socket); return PP_ERROR_FAILED; } if (ts->seen_eof) { trace_warning("%s, seen eof\n", __func__); pp_resource_release(tcp_socket); return PP_ERROR_FAILED; } if (bytes_to_read > 1024 * 1024) bytes_to_read = 1024 * 1024; struct async_network_task_s *task = async_network_task_create(); task->type = ASYNC_NETWORK_TCP_READ; task->resource = tcp_socket; task->buffer = buffer; task->bufsize = bytes_to_read; task->callback = callback; pp_resource_release(tcp_socket); async_network_task_push(task); return PP_OK_COMPLETIONPENDING; }
PP_Bool ppb_instance_bind_graphics(PP_Instance instance, PP_Resource device) { PP_Bool retval; struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return PP_FALSE; } if (device == 0) { // unbind pthread_mutex_lock(&pp_i->lock); pp_i->graphics = 0; pthread_mutex_unlock(&pp_i->lock); return PP_TRUE; } struct pp_graphics2d_s *g2d = pp_resource_acquire(device, PP_RESOURCE_GRAPHICS2D); struct pp_graphics3d_s *g3d = pp_resource_acquire(device, PP_RESOURCE_GRAPHICS3D); if (g2d) { if (pp_i != g2d->instance) { retval = PP_FALSE; goto done; } pthread_mutex_lock(&pp_i->lock); pp_i->graphics = device; pthread_mutex_unlock(&pp_i->lock); retval = PP_TRUE; } else if (g3d) { if (pp_i != g3d->instance) { retval = PP_FALSE; goto done; } pthread_mutex_lock(&pp_i->lock); pp_i->graphics = device; pthread_mutex_unlock(&pp_i->lock); pp_resource_release(device); retval = PP_TRUE; } else { trace_warning("%s, unsupported graphics resource %d on instance %d\n", __func__, device, instance); retval = PP_FALSE; } done: pp_resource_release(device); return retval; }
PP_Resource pp_resource_ref(PP_Resource resource) { pthread_mutex_lock(&res_tbl_lock); struct pp_resource_generic_s *ptr = g_hash_table_lookup(res_tbl, GINT_TO_POINTER(resource)); if (ptr) { ptr->ref_cnt ++; } else { trace_warning("%s, no such resource %d\n", __func__, resource); } pthread_mutex_unlock(&res_tbl_lock); return resource; }
static void deactivate_xscreensaver(Display *dpy) { Window xssw = find_xscreensaver_window(dpy); if (!xssw) { trace_warning("%s, no XScreenSaver's window found\n", __func__); return; } if (is_xscreensaver_active(dpy)) { // XScreenSaver already active, deactivating timer makes no sense return; } XEvent ev; Status status; Atom XA_SCREENSAVER = XInternAtom(dpy, "SCREENSAVER", False); Atom XA_DEACTIVATE = XInternAtom(dpy, "DEACTIVATE", False); ev.xany.type = ClientMessage; ev.xclient.display = dpy; ev.xclient.window = xssw; ev.xclient.message_type = XA_SCREENSAVER; ev.xclient.format = 32; memset(&ev.xclient.data, 0, sizeof(ev.xclient.data)); ev.xclient.data.l[0] = XA_DEACTIVATE; ev.xclient.data.l[1] = 0; ev.xclient.data.l[2] = 0; status = XSendEvent(dpy, xssw, False, 0, &ev); if (status == 0) { trace_warning("%s, can't send event to XScreenSaver's window\n", __func__); return; } }
/** * Callback invoked when data has been received on the USB. * For USB CDC Serial Port 1 */ static void _usb_data_received1(void *read, uint8_t status, uint32_t received, uint32_t remaining) { /* Check that data has been received successfully */ if (status == USBD_STATUS_SUCCESS) { *(uint8_t *)read = 1; /* Send data through USBSerial 0 */ while (cdcd_serial_port_write(dual_cdcd_driver_get_serialport(0), usb_serial_buffer1, received, 0, 0) != USBD_STATUS_SUCCESS); /* Check if bytes have been discarded */ if ((received == DATABUFFERSIZE) && (remaining > 0)) { trace_warning( "_usb_data_received1: %u bytes discarded\n\r", (unsigned int)remaining); } } else { trace_warning( "_usb_data_received1: Transfer error\n\r"); } }
int32_t ppb_video_decoder_decode(PP_Resource video_decoder, const struct PP_VideoBitstreamBuffer_Dev *bitstream_buffer, struct PP_CompletionCallback callback) { struct pp_video_decoder_s *vd = pp_resource_acquire(video_decoder, PP_RESOURCE_VIDEO_DECODER); if (!vd) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (vd->failed_state) { trace_warning("%s, there were errors before, giving up\n", __func__); pp_resource_release(video_decoder); return PP_ERROR_FAILED; } void *rawdata = ppb_buffer_map(bitstream_buffer->data); if (!rawdata) { trace_error("%s, bad bitstream buffer\n", __func__); pp_resource_release(video_decoder); return PP_ERROR_FAILED; } uint8_t *inbuf = rawdata; size_t inbuf_sz = bitstream_buffer->size; while (inbuf_sz > 0) { uint8_t *outbuf = NULL; int outbuf_sz = 0; int len = av_parser_parse2(vd->avparser, vd->avctx, &outbuf, &outbuf_sz, inbuf, inbuf_sz, 0, 0, AV_NOPTS_VALUE); if (outbuf_sz > 0) decode_frame(vd, outbuf, outbuf_sz, vd->last_consumed_bitstream_buffer_id); inbuf += len; inbuf_sz -= len; } vd->last_consumed_bitstream_buffer_id = bitstream_buffer->id; ppb_buffer_unmap(bitstream_buffer->data); pp_resource_release(video_decoder); ppb_core_call_on_main_thread(0, callback, PP_OK); return PP_OK_COMPLETIONPENDING; }
PP_Resource ppb_ime_input_event_create(PP_Instance instance, PP_InputEvent_Type type, PP_TimeTicks time_stamp, struct PP_Var text, uint32_t segment_number, const uint32_t segment_offsets[], int32_t target_segment, uint32_t selection_start, uint32_t selection_end) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } if (type != PP_INPUTEVENT_TYPE_IME_COMPOSITION_START && type != PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE && type != PP_INPUTEVENT_TYPE_IME_COMPOSITION_END && type != PP_INPUTEVENT_TYPE_IME_TEXT) { trace_warning("%s, wrong type=%d\n", __func__, type); return 0; } PP_Resource input_event = pp_resource_allocate(PP_RESOURCE_INPUT_EVENT, pp_i); struct pp_input_event_s *ie = pp_resource_acquire(input_event, PP_RESOURCE_INPUT_EVENT); if (!ie) { trace_error("%s, can't allocate memory\n", __func__); return 0; } ie->event_class = PP_INPUTEVENT_CLASS_IME; ie->type = type; ie->time_stamp = time_stamp; ie->text = ppb_var_add_ref2(text); ie->segment_number = segment_number; ie->segment_offsets = NULL; if (segment_number > 0) { ie->segment_offsets = malloc((segment_number + 1) * sizeof(uint32_t)); memcpy(ie->segment_offsets, segment_offsets, (segment_number + 1) * sizeof(uint32_t)); } ie->target_segment = target_segment; ie->selection_start = selection_start; ie->selection_end = selection_end; pp_resource_release(input_event); return input_event; }
PP_Resource ppb_graphics2d_create(PP_Instance instance, const struct PP_Size *size, PP_Bool is_always_opaque) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } PP_Resource graphics_2d = pp_resource_allocate(PP_RESOURCE_GRAPHICS2D, pp_i); struct pp_graphics2d_s *g2d = pp_resource_acquire(graphics_2d, PP_RESOURCE_GRAPHICS2D); if (!g2d) { trace_error("%s, can't create graphics2d resource\n", __func__); return 0; } g2d->is_always_opaque = is_always_opaque; g2d->scale = 1.0; g2d->width = size->width; g2d->height = size->height; g2d->stride = 4 * size->width; g2d->scaled_width = g2d->width; g2d->scaled_height = g2d->height; g2d->scaled_stride = g2d->stride; g2d->data = calloc(g2d->stride * g2d->height, 1); g2d->second_buffer = calloc(g2d->scaled_stride * g2d->scaled_height, 1); if (!g2d->data || !g2d->second_buffer) { trace_warning("%s, can't allocate memory\n", __func__); free_and_nullify(g2d, data); free_and_nullify(g2d, second_buffer); pp_resource_release(graphics_2d); ppb_core_release_resource(graphics_2d); return 0; } g2d->cairo_surf = cairo_image_surface_create_for_data((unsigned char *)g2d->data, CAIRO_FORMAT_ARGB32, g2d->width, g2d->height, g2d->stride); g2d->task_list = NULL; pp_resource_release(graphics_2d); return graphics_2d; }
PP_Bool ppb_tcp_socket_get_remote_address(PP_Resource tcp_socket, struct PP_NetAddress_Private *remote_addr) { struct pp_tcp_socket_s *ts = pp_resource_acquire(tcp_socket, PP_RESOURCE_TCP_SOCKET); if (!ts) { trace_error("%s, bad resource\n", __func__); return PP_FALSE; } if (!ts->is_connected) { trace_warning("%s, not connected\n", __func__); pp_resource_release(tcp_socket); return PP_FALSE; } socklen_t len = sizeof(remote_addr->data); int ret = getpeername(ts->sock, (struct sockaddr *)remote_addr->data, &len); remote_addr->size = len; pp_resource_release(tcp_socket); return ret == 0 ? PP_TRUE : PP_FALSE; }
static void handle_tcp_connect_stage2(int result, char type, int count, int ttl, void *addresses, void *arg) { struct async_network_task_s *task = arg; if (result != DNS_ERR_NONE || count < 1) { trace_warning("%s, evdns returned code %d, count = %d (%s:%u)\n", __func__, result, count, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_NAME_NOT_RESOLVED, 0, __func__); task_destroy(task); return; } evutil_make_socket_nonblocking(task->sock); task->addr_count = count; task->addr_ptr = 0; task->addr_type = type; if (type == DNS_IPv4_A) { task->addr = malloc(4 * count); memcpy(task->addr, addresses, 4 * count); } else if (type == DNS_IPv6_AAAA) { task->addr = malloc(16 * count); memcpy(task->addr, addresses, 16 * count); } else { trace_error("%s, bad evdns type %d (%s:%u)\n", __func__, type, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_FAILED, 0, __func__); task_destroy(task); return; } handle_tcp_connect_stage3(task); }
static Cursor create_cursor_from_image_data_resource(Display *dpy, Window wnd, PP_Resource image_data, int hotspot_x, int hotspot_y) { struct pp_image_data_s *id = pp_resource_acquire(image_data, PP_RESOURCE_IMAGE_DATA); if (!id) { trace_warning("%s, bad resource\n", __func__); return None; } XcursorImage *cursor_image = XcursorImageCreate(id->width, id->height); cursor_image->xhot = hotspot_x; cursor_image->yhot = hotspot_y; memcpy(cursor_image->pixels, id->data, id->stride * id->height); Cursor cursor = XcursorImageLoadCursor(dpy, cursor_image); XcursorImageDestroy(cursor_image); pp_resource_release(image_data); return cursor; }
PP_Resource ppb_graphics3d_create(PP_Instance instance, PP_Resource share_context, const int32_t attrib_list[]) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return 0; } GLXContext share_glc = (share_context == 0) ? NULL : peek_gl_context(share_context); // check for required GLX extensions #if HAVE_GLES2 if (!display.glx_arb_create_context || !display.glx_arb_create_context_profile || !display.glx_ext_create_context_es2_profile) { trace_warning("%s, some of GLX_ARB_create_context, GLX_ARB_create_context_profile, " "GLX_EXT_create_context_es2_profile missing\n", __func__); return 0; } if (!display.glXCreateContextAttribsARB) { trace_warning("%s, no glXCreateContextAttribsARB found\n", __func__); return 0; } #endif PP_Resource context = pp_resource_allocate(PP_RESOURCE_GRAPHICS3D, pp_i); struct pp_graphics3d_s *g3d = pp_resource_acquire(context, PP_RESOURCE_GRAPHICS3D); if (!g3d) { trace_error("%s, can't create context\n", __func__); return 0; } int attrib_len = 0; while (attrib_list[attrib_len] != PP_GRAPHICS3DATTRIB_NONE) { attrib_len += 2; } attrib_len ++; int *cfg_attrs = calloc(attrib_len + 3 * 2, sizeof(int)); int k2 = 0; cfg_attrs[k2++] = GLX_X_RENDERABLE; cfg_attrs[k2++] = True; cfg_attrs[k2++] = GLX_DRAWABLE_TYPE; cfg_attrs[k2++] = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; int done = 0; int k1 = 0; while (!done) { switch (attrib_list[k1]) { case PP_GRAPHICS3DATTRIB_HEIGHT: g3d->height = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_WIDTH: g3d->width = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE: case PP_GRAPHICS3DATTRIB_SWAP_BEHAVIOR: // TODO: save these values k1 += 2; break; case PP_GRAPHICS3DATTRIB_NONE: cfg_attrs[k2++] = None; done = 1; break; case PP_GRAPHICS3DATTRIB_ALPHA_SIZE: cfg_attrs[k2++] = GLX_ALPHA_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_BLUE_SIZE: cfg_attrs[k2++] = GLX_BLUE_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_GREEN_SIZE: cfg_attrs[k2++] = GLX_GREEN_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_RED_SIZE: cfg_attrs[k2++] = GLX_RED_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_DEPTH_SIZE: cfg_attrs[k2++] = GLX_DEPTH_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_STENCIL_SIZE: cfg_attrs[k2++] = GLX_STENCIL_SIZE; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLES: cfg_attrs[k2++] = GLX_SAMPLES; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS: cfg_attrs[k2++] = GLX_SAMPLE_BUFFERS; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case GLX_Y_INVERTED_EXT: cfg_attrs[k2++] = GLX_Y_INVERTED_EXT; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; case GLX_BIND_TO_TEXTURE_RGBA_EXT: cfg_attrs[k2++] = GLX_BIND_TO_TEXTURE_RGBA_EXT; cfg_attrs[k2++] = attrib_list[k1 + 1]; k1 += 2; break; default: // skip unknown attribute trace_error("%s, unknown attribute 0x%x\n", __func__, attrib_list[k1]); k1 += 1; break; } } pthread_mutex_lock(&display.lock); int screen = DefaultScreen(display.x); int nconfigs = 0; GLXFBConfig *fb_cfgs = glXChooseFBConfig(display.x, screen, cfg_attrs, &nconfigs); free(cfg_attrs); if (!fb_cfgs) { trace_error("%s, glXChooseFBConfig returned NULL\n", __func__); goto err; } trace_info_f("%s, glXChooseFBConfig returned %d configs, choosing first one\n", __func__, nconfigs); g3d->fb_config = fb_cfgs[0]; XFree(fb_cfgs); #if HAVE_GLES2 // create context implementing OpenGL ES 2.0 const int ctx_attrs[] = { GLX_RENDER_TYPE, GLX_RGBA_TYPE, GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, None, }; #else // create context implementing OpenGL 2.0 // OpenGL ES 2.0 will be emulated with help of shader translator const int ctx_attrs[] = { GLX_RENDER_TYPE, GLX_RGBA_TYPE, GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None, }; #endif if (display.glXCreateContextAttribsARB) { g3d->glc = display.glXCreateContextAttribsARB(display.x, g3d->fb_config, share_glc, True, ctx_attrs); if (!g3d->glc) trace_warning("%s, glXCreateContextAttribsARB returned NULL\n", __func__); } else { g3d->glc = NULL; } if (!g3d->glc) { // if glXCreateContextAttribsARB is not present or returned NULL, // request any GL context g3d->glc = glXCreateNewContext(display.x, g3d->fb_config, GLX_RGBA_TYPE, share_glc, True); if (!g3d->glc) { trace_error("%s, glXCreateNewContext returned NULL\n", __func__); goto err; } } g3d->depth = pp_i->is_transparent ? 32 : DefaultDepth(display.x, screen); switch (g3d->depth) { case 24: g3d->xr_pictfmt = display.pictfmt_rgb24; break; case 32: g3d->xr_pictfmt = display.pictfmt_argb32; break; default: trace_error("%s, unsupported g3d->depth (%d)\n", __func__, g3d->depth); goto err; } g3d->pixmap = XCreatePixmap(display.x, DefaultRootWindow(display.x), g3d->width, g3d->height, g3d->depth); g3d->glx_pixmap = glXCreatePixmap(display.x, g3d->fb_config, g3d->pixmap, NULL); if (g3d->glx_pixmap == None) { trace_error("%s, failed to create GLX pixmap\n", __func__); goto err; } XFlush(display.x); g3d->xr_pict = XRenderCreatePicture(display.x, g3d->pixmap, g3d->xr_pictfmt, 0, 0); int ret = glXMakeCurrent(display.x, g3d->glx_pixmap, g3d->glc); if (!ret) { trace_error("%s, glXMakeCurrent failed\n", __func__); goto err; } // clear surface glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glXMakeCurrent(display.x, None, NULL); g3d->sub_maps = g_hash_table_new(g_direct_hash, g_direct_equal); pthread_mutex_unlock(&display.lock); pp_resource_release(context); return context; err: pthread_mutex_unlock(&display.lock); pp_resource_release(context); pp_resource_expunge(context); return 0; }
static void parse_url_string(const char *s, struct PP_URLComponents_Dev *components) { UriParserStateA ups; UriUriA uri; ups.uri = &uri; if (uriParseUriA(&ups, s) != URI_SUCCESS) { uriFreeUriMembersA(&uri); trace_warning("failure at %s\n", __func__); return; } components->scheme.begin = 0; components->scheme.len = -1; components->username.begin = 0; components->username.len = -1; components->password.begin = 0; components->password.len = -1; components->host.begin = 0; components->host.len = -1; components->port.begin = 0; components->port.len = -1; components->path.begin = 0; components->path.len = -1; components->query.begin = 0; components->query.len = -1; components->ref.begin = 0; components->ref.len = -1; #define C_PARSE(c1, c2) \ components->c1.begin = uri.c2.first ? uri.c2.first - s + 1 : 0; \ components->c1.len = uri.c2.first ? uri.c2.afterLast - uri.c2.first : -1; C_PARSE(scheme, scheme); C_PARSE(username, userInfo); C_PARSE(password, userInfo); if (components->username.begin > 0) { const char *first = s + components->username.begin - 1; const char *last = first + components->username.len; const char *ptr = first; while (ptr < last) { if (*ptr == ':') { components->username.len = ptr - first; components->password.begin += ptr - first + 1; components->password.len -= ptr - first + 1; if (components->username.len == 0) { components->username.begin = 0; components->username.len = -1; } if (components->password.len == 0) { components->password.begin = 0; components->password.len = -1; } break; } ptr ++; } } C_PARSE(host, hostText); C_PARSE(port, portText); components->path.begin = uri.pathHead ? uri.pathHead->text.first - s + 1 : 0; components->path.len = uri.pathHead ? uri.pathTail->text.afterLast - uri.pathHead->text.first : -1; if (components->path.begin > 0) { components->path.begin -= 1; components->path.len += 1; } C_PARSE(query, query); C_PARSE(ref, fragment); #undef C_PARSE uriFreeUriMembersA(&uri); }
static void request_buffers(struct pp_video_decoder_s *vd) { const PP_Instance instance = vd->instance->id; const struct PP_Size dimensions = { .width = vd->avctx->width, .height = vd->avctx->height }; pp_resource_release(vd->self_id); // TODO: how many surfaces do we need? vd->ppp_video_decoder_dev->ProvidePictureBuffers(instance, vd->self_id, 21, &dimensions, GL_TEXTURE_2D); pp_resource_acquire(vd->self_id, PP_RESOURCE_VIDEO_DECODER); } static uint32_t find_free_buffer(struct pp_video_decoder_s *vd) { for (uint32_t idx = 0; idx < vd->buffer_count; idx ++) { if (!vd->buffers[idx].used) { vd->buffers[idx].used = 1; return idx; } } return (uint32_t)-1; } static void issue_frame(struct pp_video_decoder_s *vd) { AVFrame *frame = vd->avframe; uint32_t idx = find_free_buffer(vd); int32_t bitstream_buffer_id = (int32_t)frame->pkt_pts; if (idx == (uint32_t)-1) { trace_warning("%s, no free buffer available\n", __func__); return; } struct pp_graphics3d_s *g3d = pp_resource_acquire(vd->graphics3d, PP_RESOURCE_GRAPHICS3D); if (!g3d) { trace_error("%s, bad resource\n", __func__); return; } VASurfaceID va_surf = GPOINTER_TO_SIZE(frame->data[3]); pthread_mutex_lock(&display.lock); glXMakeCurrent(display.x, g3d->glx_pixmap, g3d->glc); glBindTexture(GL_TEXTURE_2D, vd->buffers[idx].texture_id); display.glXBindTexImageEXT(display.x, vd->buffers[idx].glx_pixmap, GLX_FRONT_EXT, NULL); XFlush(display.x); vaPutSurface(display.va, va_surf, vd->buffers[idx].pixmap, 0, 0, frame->width, frame->height, 0, 0, frame->width, frame->height, NULL, 0, VA_FRAME_PICTURE); XFlush(display.x); glXMakeCurrent(display.x, None, NULL); pthread_mutex_unlock(&display.lock); pp_resource_release(vd->graphics3d); const PP_Instance instance = vd->instance->id; const struct PP_Picture_Dev picture = { .picture_buffer_id = vd->buffers[idx].id, .bitstream_buffer_id = bitstream_buffer_id, }; pp_resource_release(vd->self_id); vd->ppp_video_decoder_dev->PictureReady(instance, vd->self_id, &picture); pp_resource_acquire(vd->self_id, PP_RESOURCE_VIDEO_DECODER); } static void decode_frame(struct pp_video_decoder_s *vd, uint8_t *data, size_t data_len, int32_t bitstream_buffer_id) { AVPacket packet; av_init_packet(&packet); packet.data = data; packet.size = data_len; packet.pts = bitstream_buffer_id; // libavcodec can call hw functions, which in turn can call Xlib functions, // therefore we need to lock pthread_mutex_lock(&display.lock); int got_frame = 0; int len = avcodec_decode_video2(vd->avctx, vd->avframe, &got_frame, &packet); pthread_mutex_unlock(&display.lock); if (len < 0) { trace_error("%s, error %d while decoding frame\n", __func__, len); return; } if (got_frame) { if (!vd->buffers_were_requested) { request_buffers(vd); vd->buffers_were_requested = 1; } issue_frame(vd); } }
PP_Bool ppb_url_request_info_set_property(PP_Resource request, PP_URLRequestProperty property, struct PP_Var value) { const char *tmp, *tmp2; PP_Bool retval = PP_TRUE; struct pp_url_request_info_s *ri = pp_resource_acquire(request, PP_RESOURCE_URL_REQUEST_INFO); if (!ri) { trace_error("%s, bad resource\n", __func__); return PP_FALSE; } #define ENSURE_TYPE(vartype) if (value.type != vartype) { retval = PP_FALSE; break; } switch (property) { case PP_URLREQUESTPROPERTY_URL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->url); tmp = ppb_var_var_to_utf8(value, NULL); tmp2 = ltrim(tmp); ri->url = strdup(tmp2); ri->is_immediate_javascript = (strncasecmp(tmp2, "javascript:", strlen("javascript:"))==0); break; case PP_URLREQUESTPROPERTY_METHOD: ENSURE_TYPE(PP_VARTYPE_STRING); tmp = ppb_var_var_to_utf8(value, NULL); if (strcmp(tmp, "GET") == 0) { ri->method = PP_METHOD_GET; } else if (strcmp(tmp, "POST") == 0) { ri->method = PP_METHOD_POST; } else { trace_warning("%s, unknown method %s\n", __func__, tmp); ri->method = PP_METHOD_UNKNOWN; } break; case PP_URLREQUESTPROPERTY_HEADERS: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->headers); ri->headers = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_STREAMTOFILE: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->stream_to_file = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->follow_redirects = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_download_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_upload_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_referrer_url); ri->custom_referrer_url = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_cross_origin_requests = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_credentials = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_content_transfer_encoding); ri->custom_content_transfer_encoding = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_upper_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_lower_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_user_agent); ri->custom_user_agent = strdup(ppb_var_var_to_utf8(value, NULL)); break; default: trace_error("%s, unknown url request property %d\n", __func__, property); retval = PP_FALSE; break; } pp_resource_release(request); return retval; }
/* Check that pointer is either a tag, a global, or a current heap value */ static int show_field(int show, Field_t fieldType, ptr_t primary, ptr_t replica, int i, int ri, Heap_t** legalHeaps, Bitmap_t** legalStarts) { int isNonheapPointer; ptr_t primaryField, replicaField; double primaryDoubleField, replicaDoubleField; if(fieldType==DoubleField){ primaryDoubleField = ((double *)primary)[i]; if(replica) replicaDoubleField = ((double *)replica)[ri]; } else{ primaryField = (ptr_t)primary[i]; if(replica) replicaField = (ptr_t)replica[ri]; } isNonheapPointer = (fieldType == PointerField) && (IsTagData(primaryField) || IsGlobalData(primaryField) || primaryField == (ptr_t)uninit_val); switch(fieldType){ case PointerField: case OldPointerField: if(show){ char* type = fieldType == PointerField ? "P" : "O"; printf("%s(%5lx) ", type, (long)primaryField); } if(isNonheapPointer || fieldType == OldPointerField || inHeaps(primaryField,legalHeaps,legalStarts)) ; else{ if(inHeaps(primaryField,legalHeaps,NULL)) trace_error("bad pointer (in range) %lx at %lx[%d]", (long)primaryField, (long)primary, i); else trace_error("bad pointer (out of range) %lx at %lx[%d]", (long)primaryField, (long)primary, i); return 0; } if(replica){ if(isNonheapPointer){ if(primaryField != replicaField){ trace_error("replica mismatch: %lx[%d] = *%lx*" " and %lx[%d] = *%lx*", (long)primary, i, (long)primaryField, (long)replica, ri, (long)replicaField); return 0; } } else{ /* Primary and replica may share in a generational collector. */ if(primaryField != replicaField && (ptr_t)primaryField[-1] != replicaField){ trace_error("ptr replica mismatch: %lx[%d] = %lx -> *%d*" " and %lx[%d] = *%lx*", (long)primary, i, (long)primaryField, primaryField[-1], (long)replica, ri, (long)replicaField); return 0; } } } break; case IntField: if(show) printf("I(%5lx) ", (long)primaryField); if(inHeaps(primaryField,legalHeaps,legalStarts)) trace_warning("suspicious int %ld at %lx[%d]\n", (long)primaryField,(long)primary,i); if(replica && primaryField != replicaField){ trace_error("int replica mismatch: %lx[%d] = *%lx*" " and %lx[%d] = *%lx*", (long)primary,i,(long)primaryField, (long)replica,ri,(long)replicaField); return 0; } break; case DoubleField: if(show) printf("R(%10g) ", primaryDoubleField); if(replica && !(isnan(primaryDoubleField) && isnan(replicaDoubleField)) && primaryDoubleField != replicaDoubleField){ trace_error("double replica mismatch: %lx[%d] = *%g*" " and %lx[%d] = *%g*", (long)primary,i,primaryDoubleField, (long)replica,ri,replicaDoubleField); return 0; } break; default: DIE("bad field type in show_field"); } return 1; }
static void handle_disconnect_stage1(struct async_network_task_s *task) { struct event *ev = evtimer_new(event_b, handle_disconnect_stage2, task); struct timeval timeout = {.tv_sec = 0}; add_event_mapping(task, ev); event_add(ev, &timeout); } static void handle_udp_recv_stage2(int sock, short event_flags, void *arg) { struct async_network_task_s *task = arg; struct pp_udp_socket_s *us = pp_resource_acquire(task->resource, PP_RESOURCE_UDP_SOCKET); if (!us) { trace_error("%s, bad resource\n", __func__); task_destroy(task); return; } socklen_t len = sizeof(task->addr_from->data); int32_t retval = recvfrom(sock, task->buffer, task->bufsize, 0, (struct sockaddr *)task->addr_from->data, &len); task->addr_from->size = len; if (task->addr_from_resource) pp_resource_unref(task->addr_from_resource); if (retval < 0) retval = get_pp_errno(); else if (retval == 0) { us->seen_eof = 1; // TODO: is it needed? } pp_resource_release(task->resource); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, retval, 0, __func__); task_destroy(task); } static void handle_udp_recv_stage1(struct async_network_task_s *task) { struct pp_udp_socket_s *us = pp_resource_acquire(task->resource, PP_RESOURCE_UDP_SOCKET); if (!us) { trace_error("%s, bad resource\n", __func__); task_destroy(task); return; } memset(task->addr_from, 0, sizeof(*task->addr_from)); struct event *ev = event_new(event_b, us->sock, EV_READ, handle_udp_recv_stage2, task); pp_resource_release(task->resource); add_event_mapping(task, ev); event_add(ev, NULL); } static void handle_udp_send_stage2(int sock, short event_flags, void *arg) { struct async_network_task_s *task = arg; int retval = sendto(sock, task->buffer, task->bufsize, MSG_NOSIGNAL, (struct sockaddr *)task->netaddr.data, task->netaddr.size); if (retval < 0) retval = get_pp_errno(); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, retval, 0, __func__); task_destroy(task); } static void handle_udp_send_stage1(struct async_network_task_s *task) { struct pp_udp_socket_s *us = pp_resource_acquire(task->resource, PP_RESOURCE_UDP_SOCKET); if (!us) { trace_error("%s, bad resource\n", __func__); task_destroy(task); return; } // try to send immediately, but don't wait int retval = sendto(us->sock, task->buffer, task->bufsize, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)task->netaddr.data, task->netaddr.size); pp_resource_release(task->resource); if (retval >= 0) { // successfully sent ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, retval, 0, __func__); task_destroy(task); return; } // need to wait struct event *ev = event_new(event_b, us->sock, EV_WRITE, handle_udp_send_stage2, task); add_event_mapping(task, ev); event_add(ev, NULL); } static void handle_host_resolve_stage2(int result, char type, int count, int ttl, void *addresses, void *arg) { struct async_network_task_s *task = arg; if (result != DNS_ERR_NONE || count < 1) { trace_warning("%s, evdns returned code %d, count = %d (%s:%u)\n", __func__, result, count, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_NAME_NOT_RESOLVED, 0, __func__); task_destroy(task); return; } struct pp_host_resolver_s *hr = pp_resource_acquire(task->resource, PP_RESOURCE_HOST_RESOLVER); if (!hr) { trace_error("%s, bad resource\n", __func__); task_destroy(task); return; } hr->addr_count = count; hr->addrs = calloc(count, sizeof(struct PP_NetAddress_Private)); if (type == DNS_IPv4_A) { struct in_addr *ipv4_addrs = addresses; for (int k = 0; k < count; k ++) { struct sockaddr_in sai = { .sin_family = AF_INET, .sin_port = htons(task->port), }; memcpy(&sai.sin_addr, &ipv4_addrs[k], sizeof(struct in_addr)); hr->addrs[k].size = sizeof(struct sockaddr_in); memcpy(hr->addrs[k].data, &sai, sizeof(sai)); } ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_OK, 0, __func__); } else if (type == DNS_IPv6_AAAA) { struct in6_addr *ipv6_addrs = addresses; for (int k = 0; k < count; k ++) { struct sockaddr_in6 sai6 = { .sin6_family = AF_INET6, .sin6_port = htons(task->port), }; memcpy(&sai6.sin6_addr, &ipv6_addrs[k], sizeof(struct in6_addr)); hr->addrs[k].size = sizeof(struct sockaddr_in6); memcpy(hr->addrs[k].data, &sai6, sizeof(sai6)); } ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_OK, 0, __func__); } else { trace_error("%s, bad evdns type %d (%s:%u)\n", __func__, type, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_FAILED, 0, __func__); } pp_resource_release(task->resource); task_destroy(task); } static void handle_host_resolve_stage1(struct async_network_task_s *task) { struct evdns_request *req; // queue DNS request req = evdns_base_resolve_ipv4(evdns_b, task->host, DNS_QUERY_NO_SEARCH, handle_host_resolve_stage2, task); // TODO: what about ipv6? if (!req) { trace_warning("%s, early dns resolution failure (%s:%u)\n", __func__, task->host, (unsigned int)task->port); ppb_message_loop_post_work_with_result(task->callback_ml, task->callback, 0, PP_ERROR_NAME_NOT_RESOLVED, 0, __func__); task_destroy(task); return; } } static void * network_worker_thread(void *param) { event_base_dispatch(event_b); event_base_free(event_b); trace_error("%s, thread terminated\n", __func__); return NULL; }
static void * audio_thread(void *param) { struct pollfd *fds = NULL; nfds_t nfds = 0; static char buf[16 * 1024]; ppb_message_loop_mark_thread_unsuitable(); nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; while (1) { if (g_atomic_int_get(&terminate_thread)) goto quit; int res = poll(fds, nfds, 10 * 1000); if (res == -1) { if (errno == EINTR) continue; trace_error("%s, poll, errno=%d\n", __func__, errno); continue; } if (res == 0 || fds == NULL) continue; if (fds[0].revents) drain_wakeup_pipe(fds[0].fd); if (g_atomic_int_get(&rebuild_fds)) { nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; } for (uintptr_t k = 1; k < nfds; k ++) { unsigned short revents = 0; audio_stream *as = g_hash_table_lookup(stream_by_fd_ht, GINT_TO_POINTER(fds[k].fd)); // check if stream was deleted if (!as) continue; snd_pcm_poll_descriptors_revents(as->pcm, &fds[k], 1, &revents); if (revents & (~(POLLIN | POLLOUT))) { trace_warning("%s, revents have unexpected flags set (%u)\n", __func__, (unsigned int)revents); recover_pcm(as->pcm); } if (revents & (POLLIN | POLLOUT)) { int paused = g_atomic_int_get(&as->paused); snd_pcm_sframes_t frame_count = snd_pcm_avail(as->pcm); if (revents & POLLIN) { // POLLIN const size_t frame_size = 1 * sizeof(int16_t); // mono 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_read; const size_t segment_length = MIN(to_process, max_segment_length); frames_read = snd_pcm_readi(as->pcm, buf, segment_length / frame_size); if (frames_read < 0) { trace_warning("%s, snd_pcm_readi error %d\n", __func__, (int)frames_read); recover_pcm(as->pcm); continue; } if (!paused && as->capture_cb) as->capture_cb(buf, frames_read * frame_size, 0, as->cb_user_data); to_process -= frames_read * frame_size; } } else { // POLLOUT const size_t frame_size = 2 * sizeof(int16_t); // stereo 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_written; const size_t segment_length = MIN(to_process, max_segment_length); if (paused || !as->playback_cb) memset(buf, 0, segment_length); else as->playback_cb(buf, segment_length, 0, as->cb_user_data); frames_written = snd_pcm_writei(as->pcm, buf, segment_length / frame_size); if (frames_written < 0) { trace_warning("%s, snd_pcm_writei error %d\n", __func__, (int)frames_written); recover_pcm(as->pcm); continue; } to_process -= frames_written * frame_size; } } } } } quit: free(fds); return NULL; }
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); if (np_initialize_was_called) { trace_warning("NP_Initialize was called more than once\n"); return NPERR_NO_ERROR; } np_initialize_was_called = 1; // 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 (aNPNFuncs->version < NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) { config.quirks.plugin_missing = 1; config.quirks.incompatible_npapi_version = 1; } load_ppp_module(); if (tables_open_display() != 0) return NPERR_GENERIC_ERROR; 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; }