static gboolean mjpeg_decoder_queue_frame(VideoDecoder *video_decoder, SpiceFrame *frame, int32_t latency) { MJpegDecoder *decoder = (MJpegDecoder*)video_decoder; SpiceFrame *last_frame; last_frame = g_queue_peek_tail(decoder->msgq); if (last_frame) { if (spice_mmtime_diff(frame->mm_time, last_frame->mm_time) < 0) { /* This should really not happen */ SPICE_DEBUG("new-frame-time < last-frame-time (%u < %u):" " resetting stream", frame->mm_time, last_frame->mm_time); mjpeg_decoder_drop_queue(decoder); } } /* Dropped MJPEG frames don't impact the ones that come after. * So drop late frames as early as possible to save on processing time. */ if (latency < 0) { SPICE_DEBUG("dropping a late MJPEG frame"); frame->free(frame); return TRUE; } frame->ref_data(frame->data_opaque); g_queue_push_tail(decoder->msgq, frame); mjpeg_decoder_schedule(decoder); return TRUE; }
static gboolean spice_win_usb_driver_send_request(SpiceWinUsbDriver *self, guint16 op, guint16 vid, guint16 pid, GError **err) { USBClerkDriverOp req; GOutputStream *ostream; SpiceWinUsbDriverPrivate *priv; gsize bytes; gboolean ret; SPICE_DEBUG("sending a request to usbclerk service (op=%d vid=0x%04x pid=0x%04x", op, vid, pid); g_return_val_if_fail(SPICE_IS_WIN_USB_DRIVER(self), FALSE); priv = self->priv; memset(&req, 0, sizeof(req)); req.hdr.magic = USB_CLERK_MAGIC; req.hdr.version = USB_CLERK_VERSION; req.hdr.type = op; req.hdr.size = sizeof(req); req.vid = vid; req.pid = pid; ostream = g_win32_output_stream_new(priv->handle, FALSE); ret = g_output_stream_write_all(ostream, &req, sizeof(req), &bytes, NULL, err); g_warn_if_fail(g_output_stream_close(ostream, NULL, NULL)); g_object_unref(ostream); SPICE_DEBUG("write_all request returned %d written bytes %"G_GSIZE_FORMAT " expecting %"G_GSIZE_FORMAT, ret, bytes, sizeof(req)); return ret; }
SpiceUsbDevice* SpiceGlibGlue_GetNextUsbDevice(char* devName, char* devId, int32_t* isShared, int32_t* isEnabled, int32_t* opPending) { g_debug(" %s:%d:%s()", __FILE__, __LINE__, __func__); // When we get past the end of the list, free the list if (!device) { SPICE_DEBUG("USB: No more devices."); devName[0]= '\0'; if (devices) { g_slist_free_full(devices, g_free); devices= NULL; } return (void *)NULL; } else { UsbDeviceInfo *dev = device->data; strncpy(devName, dev->name, MAX_USB_DEVICE_NAME_SIZE); strncpy(devId, dev->id, MAX_USB_DEVICE_ID_SIZE); *isShared = dev->isShared; *isEnabled = dev->isEnabled; *opPending = dev->isOpPending; SPICE_DEBUG("USB: Returning devName %s, isShared= %d, isEnabled = %d, isOpPending = %d", devName, dev->isShared, dev->isEnabled, dev->isOpPending); device = g_slist_next(device); return dev->device; } }
gboolean clipboard_grabByGuest(SpiceMainChannel *main, guint selection, guint32* types, guint32 num_types, gpointer user_data) { gint i; SPICE_DEBUG("CB: clipboard_grabByGuest(sel %d)", selection); if (!enableClipboardToClient) { SPICE_DEBUG("CB: enableClipboardToClient set to false. Doing nothing."); return TRUE; } if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) { g_warning("CB: discarded clipboard request of unsupported selection %d",selection); return FALSE; } for (i = 0; i < num_types; i++) { SPICE_DEBUG("CB: checking type(%d)",types[i]); if (types[i] == VD_AGENT_CLIPBOARD_UTF8_TEXT){ SPICE_DEBUG("CB: IT IS UTF8"); clipboardOwner = CB_OWNER_GUEST; } } return TRUE; }
static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) { struct spice_context *ctx = data; int id; g_object_get(channel, "channel-id", &id, NULL); ctx->channels++; SPICE_DEBUG("new channel (#%d)", id); g_signal_connect(channel, "open-fd", G_CALLBACK(channel_open_fd), ctx); if (SPICE_IS_MAIN_CHANNEL(channel)) { SPICE_DEBUG("new main channel"); g_signal_connect(channel, "channel-event", G_CALLBACK(main_channel_event), ctx); } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (ctx->display != NULL) return; SPICE_DEBUG("new display channel (#%d)", id); ctx->display = spice_display_new(ctx, id); ctx->display_channel = id; } if (SPICE_IS_PLAYBACK_CHANNEL(channel)) { SPICE_DEBUG("new audio channel"); spice_audio_get(s, NULL); } }
static gboolean create_pipeline(SpiceGstDecoder *decoder) { gchar *desc; gboolean auto_enabled; guint opt; GstAppSinkCallbacks appsink_cbs = { NULL }; GError *err = NULL; GstBus *bus; auto_enabled = (g_getenv("SPICE_GSTVIDEO_AUTO") != NULL); if (auto_enabled || !VALID_VIDEO_CODEC_TYPE(decoder->base.codec_type)) { SPICE_DEBUG("Trying %s for codec type %d %s", gst_opts[0].dec_name, decoder->base.codec_type, (auto_enabled) ? "(SPICE_GSTVIDEO_AUTO is set)" : ""); opt = 0; } else { opt = decoder->base.codec_type; } /* - We schedule the frame display ourselves so set sync=false on appsink * so the pipeline decodes them as fast as possible. This will also * minimize the risk of frames getting lost when we rebuild the * pipeline. * - Set max-bytes=0 on appsrc so it does not drop frames that may be * needed by those that follow. */ desc = g_strdup_printf("appsrc name=src is-live=true format=time max-bytes=0 block=true " "%s ! %s ! videoconvert ! appsink name=sink " "caps=video/x-raw,format=BGRx sync=false drop=false", gst_opts[opt].dec_caps, gst_opts[opt].dec_name); SPICE_DEBUG("GStreamer pipeline: %s", desc); decoder->pipeline = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &err); g_free(desc); if (!decoder->pipeline) { spice_warning("GStreamer error: %s", err->message); g_clear_error(&err); return FALSE; } decoder->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "src")); decoder->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "sink")); appsink_cbs.new_sample = new_sample; gst_app_sink_set_callbacks(decoder->appsink, &appsink_cbs, decoder, NULL); bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipeline)); gst_bus_add_watch(bus, handle_pipeline_message, decoder); gst_object_unref(bus); decoder->clock = gst_pipeline_get_clock(GST_PIPELINE(decoder->pipeline)); if (gst_element_set_state(decoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { SPICE_DEBUG("GStreamer error: Unable to set the pipeline to the playing state."); free_pipeline(decoder); return FALSE; } return TRUE; }
/* coroutine context */ static int spice_channel_read_wire(SpiceChannel *channel, void *data, size_t len) { spice_channel *c = channel->priv; int ret; GIOCondition cond; reread: if (c->has_error) return 0; /* has_error is set by disconnect(), return no error */ cond = 0; if (c->tls) { ret = SSL_read(c->ssl, data, len); if (ret < 0) { ret = SSL_get_error(c->ssl, ret); if (ret == SSL_ERROR_WANT_READ) cond |= G_IO_IN; if (ret == SSL_ERROR_WANT_WRITE) cond |= G_IO_OUT; ret = -1; } } else { GError *error = NULL; ret = g_socket_receive(c->sock, data, len, NULL, &error); if (ret < 0) { if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { cond = G_IO_IN; } else { SPICE_DEBUG("Read error %s", error->message); } g_clear_error(&error); ret = -1; } } if (ret == -1) { if (cond != 0) { if (c->wait_interruptable) { if (!g_io_wait_interruptable(&c->wait, c->sock, cond)) { // SPICE_DEBUG("Read blocking interrupted %d", priv->has_error); return -EAGAIN; } } else { g_io_wait(c->sock, cond); } goto reread; } else { c->has_error = TRUE; return -errno; } } if (ret == 0) { SPICE_DEBUG("Closing the connection: spice_channel_read() - ret=0"); c->has_error = TRUE; return 0; } return ret; }
/* coroutine context */ static void spice_channel_flush_wire(SpiceChannel *channel, const void *data, size_t datalen) { spice_channel *c = channel->priv; const char *ptr = data; size_t offset = 0; GIOCondition cond; while (offset < datalen) { int ret; if (c->has_error) return; cond = 0; if (c->tls) { ret = SSL_write(c->ssl, ptr+offset, datalen-offset); if (ret < 0) { ret = SSL_get_error(c->ssl, ret); if (ret == SSL_ERROR_WANT_READ) cond |= G_IO_IN; if (ret == SSL_ERROR_WANT_WRITE) cond |= G_IO_OUT; ret = -1; } } else { GError *error = NULL; ret = g_socket_send(c->sock, ptr+offset, datalen-offset, NULL, &error); if (ret < 0) { if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { cond = G_IO_OUT; } else { SPICE_DEBUG("Send error %s", error->message); exit(1); } g_clear_error(&error); ret = -1; } } if (ret == -1) { if (cond != 0) { SPICE_DEBUG("g_io_waiting"); g_io_wait(c->sock, cond); } else { SPICE_DEBUG("Closing the channel: spice_channel_flush %d", errno); c->has_error = TRUE; return; } } if (ret == 0) { SPICE_DEBUG("Closing the connection: spice_channel_flush"); c->has_error = TRUE; return; } offset += ret; } }
/* coroutine context */ static void spice_channel_recv_link_msg(SpiceChannel *channel) { spice_channel *c = channel->priv; int rc, num_caps, i; g_return_if_fail(channel != NULL); rc = spice_channel_read(channel, (uint8_t*)c->peer_msg + c->peer_pos, c->peer_hdr.size - c->peer_pos); c->peer_pos += rc; if (c->peer_pos != c->peer_hdr.size) { g_critical("%s: %s: incomplete link reply (%d/%d)", c->name, __FUNCTION__, rc, c->peer_hdr.size); emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK); return; } switch (c->peer_msg->error) { case SPICE_LINK_ERR_OK: /* nothing */ break; case SPICE_LINK_ERR_NEED_SECURED: c->tls = true; SPICE_DEBUG("%s: switching to tls", c->name); SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel); spice_channel_connect(channel); return; default: g_warning("%s: %s: unhandled error %d", c->name, __FUNCTION__, c->peer_msg->error); SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel); emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK); return; } num_caps = c->peer_msg->num_channel_caps + c->peer_msg->num_common_caps; SPICE_DEBUG("%s: %s: %d caps", c->name, __FUNCTION__, num_caps); /* see original spice/client code: */ /* g_return_if_fail(c->peer_msg + c->peer_msg->caps_offset * sizeof(uint32_t) > c->peer_msg + c->peer_hdr.size); */ uint32_t *caps = (uint32_t *)((uint8_t *)c->peer_msg + c->peer_msg->caps_offset); g_array_set_size(c->remote_common_caps, c->peer_msg->num_common_caps); for (i = 0; i < c->peer_msg->num_common_caps; i++, caps++) { g_array_index(c->remote_common_caps, uint32_t, i) = *caps; SPICE_DEBUG("got caps %u %u", i, *caps); } g_array_set_size(c->remote_caps, c->peer_msg->num_channel_caps); for (i = 0; i < c->peer_msg->num_channel_caps; i++, caps++) { g_array_index(c->remote_caps, uint32_t, i) = *caps; SPICE_DEBUG("got caps %u %u", i, *caps); } c->state = SPICE_CHANNEL_STATE_AUTH; spice_channel_send_auth(channel); }
/* spice_gst_decoder_queue_frame() queues the SpiceFrame for decoding and * displaying. The steps it goes through are as follows: * * 1) A SpiceGstFrame is created to keep track of SpiceFrame and some additional * metadata. The SpiceGstFrame is then pushed to the decoding_queue. * 2) frame->data, which contains the compressed frame data, is reffed and * wrapped in a GstBuffer which is pushed to the GStreamer pipeline for * decoding. * 3) As soon as the GStreamer pipeline no longer needs the compressed frame it * will call frame->unref_data() to free it. * 4) Once the decompressed frame is available the GStreamer pipeline calls * new_sample() in the GStreamer thread. * 5) new_sample() then matches the decompressed frame to a SpiceGstFrame from * the decoding queue using the GStreamer timestamp information to deal with * dropped frames. The SpiceGstFrame is popped from the decoding_queue. * 6) new_sample() then attaches the decompressed frame to the SpiceGstFrame, * pushes it to the display_queue and calls schedule_frame(). * 7) schedule_frame() then uses gstframe->frame->mm_time to arrange for * display_frame() to be called, in the main thread, at the right time for * the next frame. * 8) display_frame() pops the first SpiceGstFrame from the display_queue and * calls stream_display_frame(). * 9) display_frame() then frees the SpiceGstFrame, which frees the SpiceFrame * and decompressed frame with it. */ static gboolean spice_gst_decoder_queue_frame(VideoDecoder *video_decoder, SpiceFrame *frame, int latency) { SpiceGstDecoder *decoder = (SpiceGstDecoder*)video_decoder; if (frame->size == 0) { SPICE_DEBUG("got an empty frame buffer!"); frame->free(frame); return TRUE; } if (frame->mm_time < decoder->last_mm_time) { SPICE_DEBUG("new-frame-time < last-frame-time (%u < %u):" " resetting stream", frame->mm_time, decoder->last_mm_time); /* Let GStreamer deal with the frame anyway */ } decoder->last_mm_time = frame->mm_time; if (latency < 0 && decoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG) { /* Dropping MJPEG frames has no impact on those that follow and * saves CPU so do it. */ SPICE_DEBUG("dropping a late MJPEG frame"); frame->free(frame); return TRUE; } if (decoder->pipeline == NULL) { /* An error occurred, causing the GStreamer pipeline to be freed */ spice_warning("An error occurred, stopping the video stream"); return FALSE; } /* ref() the frame data for the buffer */ frame->ref_data(frame->data_opaque); GstBuffer *buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS, frame->data, frame->size, 0, frame->size, frame->data_opaque, frame->unref_data); GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_PTS(buffer) = gst_clock_get_time(decoder->clock) - gst_element_get_base_time(decoder->pipeline) + ((uint64_t)MAX(0, latency)) * 1000 * 1000; g_mutex_lock(&decoder->queues_mutex); g_queue_push_tail(decoder->decoding_queue, create_gst_frame(buffer, frame)); g_mutex_unlock(&decoder->queues_mutex); if (gst_app_src_push_buffer(decoder->appsrc, buffer) != GST_FLOW_OK) { SPICE_DEBUG("GStreamer error: unable to push frame of size %u", frame->size); stream_dropped_frame_on_playback(decoder->base.stream); } return TRUE; }
int SpiceGlibGlue_ReleaseGuestClipboard() { SPICE_DEBUG("CB: ReleaseGuestClipboard"); if (!enableClipboardToGuest) { SPICE_DEBUG("CB: enableClipboardToGuest set to false. Doing nothing."); return 0; } g_idle_add(release_guest_clipboard, NULL); return 0; }
void android_send_task(int task) { while(!android_task_ready); SPICE_DEBUG("send task:%d\n",task); pthread_mutex_lock(&android_mutex); android_task_ready = 0; android_task = task; pthread_cond_signal(&android_cond); pthread_mutex_unlock(&android_mutex); while(android_task); SPICE_DEBUG("send task done:%d\n",task); }
int SpiceGlibGlue_GrabGuestClipboard() { SPICE_DEBUG("CB: GrabGuestClipboard grabbing %d", VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD); if (!enableClipboardToGuest) { SPICE_DEBUG("CB: enableClipboardToGuest set to false. Doing nothing."); return 0; } g_idle_add(grab_guest_clipboard, NULL); return 0; }
int SpiceGlibGlue_ClipboardGetData() { SPICE_DEBUG("CB: ClipboardGetData"); if (clipboardOwner != CB_OWNER_GUEST) { SPICE_DEBUG("CB: Guest has not grabbed CB, returning false"); return 0; } g_idle_add(clipboard_get_data, NULL); return 1; }
static void clipboard_received_cb(GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer user_data) { WeakRef *weakref = user_data; SpiceGtkSession *self = (SpiceGtkSession*)weakref->object; weak_unref(weakref); if (self == NULL) return; g_return_if_fail(SPICE_IS_GTK_SESSION(self)); SpiceGtkSessionPrivate *s = self->priv; gint len = 0, m; guint32 type = VD_AGENT_CLIPBOARD_NONE; gchar* name; GdkAtom atom; int selection; selection = get_selection_from_clipboard(s, clipboard); g_return_if_fail(selection != -1); len = gtk_selection_data_get_length(selection_data); if (len == -1) { SPICE_DEBUG("empty clipboard"); len = 0; } else if (len == 0) { SPICE_DEBUG("TODO: what should be done here?"); } else { atom = gtk_selection_data_get_data_type(selection_data); name = gdk_atom_name(atom); for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) { if (strcasecmp(name, atom2agent[m].xatom) == 0) { break; } } if (m >= SPICE_N_ELEMENTS(atom2agent)) { g_warning("clipboard_received for unsupported type: %s", name); } else { type = atom2agent[m].vdagent; } g_free(name); } spice_main_clipboard_selection_notify(s->main, selection, type, gtk_selection_data_get_data(selection_data), len); }
int android_spice_output() { int sockfd, newsockfd, servlen; socklen_t clilen; struct sockaddr_un cli_addr, serv_addr; if ((sockfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0) error("creating socket"); memset((char *) &serv_addr,0, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; char* sock = "/data/data/com.keqisoft.android.spice/spice-output.socket"; remove(sock); strcpy(serv_addr.sun_path, sock); servlen=strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); if(bind(sockfd,(struct sockaddr *)&serv_addr,servlen)<0) error("binding socket"); listen(sockfd,5); clilen = sizeof(cli_addr); newsockfd = accept( sockfd,(struct sockaddr *)&cli_addr,&clilen); if (newsockfd < 0) error("accepting"); int over = 0; while(!over) { pthread_mutex_lock(&android_mutex); android_task_ready = 1; pthread_cond_wait(&android_cond,&android_mutex); SPICE_DEBUG("got task:%d\n",android_task); if(android_task == ANDROID_TASK_SHOW) { if(msg_send_handle(newsockfd)) { over = 1; } android_task = ANDROID_TASK_IDLE; } else if(android_task == ANDROID_TASK_OVER) { over =1; android_task = ANDROID_TASK_IDLE; } pthread_mutex_unlock(&android_mutex); SPICE_DEBUG("got task done:%d\n",android_task); } close(newsockfd); close(sockfd); SPICE_DEBUG("android output over\n"); return 0; }
/* main loop or GStreamer streaming thread */ static void schedule_frame(SpiceGstDecoder *decoder) { guint32 now = stream_get_time(decoder->base.stream); g_mutex_lock(&decoder->queues_mutex); while (!decoder->timer_id) { SpiceGstFrame *gstframe = g_queue_peek_head(decoder->display_queue); if (!gstframe) { break; } if (now < gstframe->frame->mm_time) { decoder->timer_id = g_timeout_add(gstframe->frame->mm_time - now, display_frame, decoder); } else if (g_queue_get_length(decoder->display_queue) == 1) { /* Still attempt to display the least out of date frame so the * video is not completely frozen for an extended period of time. */ decoder->timer_id = g_timeout_add(0, display_frame, decoder); } else { SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping", __FUNCTION__, now - gstframe->frame->mm_time, gstframe->frame->mm_time, now); stream_dropped_frame_on_playback(decoder->base.stream); g_queue_pop_head(decoder->display_queue); free_gst_frame(gstframe); } } g_mutex_unlock(&decoder->queues_mutex); }
static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer data) { SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int id; g_object_get(channel, "channel-id", &id, NULL); SPICE_DEBUG("channel_destroy %d", id); if (SPICE_IS_MAIN_CHANNEL(channel)) { disconnect_main(display); return; } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (id != d->channel_id) return; disconnect_display(display); return; } if (SPICE_IS_CURSOR_CHANNEL(channel)) { if (id != d->channel_id) return; disconnect_cursor(display); return; } if (SPICE_IS_INPUTS_CHANNEL(channel)) { d->inputs = NULL; return; } }
gboolean clipboard_releaseByGuest(SpiceMainChannel *main, guint selection, guint32* types, guint32 num_types, gpointer user_data) { SPICE_DEBUG("CB: clipboard_releaseByGuest(sel %d) not implemented in this platform", selection); }
static void connect_cb(GObject *gobject, GAsyncResult *res, gpointer user_data) { SpiceUsbDeviceManager *manager = SPICE_USB_DEVICE_MANAGER(gobject); connect_cb_data *data = user_data; SpiceUsbDeviceWidget *self = data->self; SpiceUsbDeviceWidgetPrivate *priv = self->priv; SpiceUsbDevice *device; GError *err = NULL; gchar *desc; spice_usb_device_manager_connect_device_finish(manager, res, &err); if (err) { device = g_object_get_data(G_OBJECT(data->check), "usb-device"); desc = spice_usb_device_get_description(device, priv->device_format_string); g_prefix_error(&err, "Could not redirect %s: ", desc); g_free(desc); SPICE_DEBUG("%s", err->message); g_signal_emit(self, signals[CONNECT_FAILED], 0, device, err); g_error_free(err); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->check), FALSE); spice_usb_device_widget_update_status(self); } g_object_unref(data->check); g_object_unref(data->self); g_free(data); }
spice_connection *connection_new(void) { spice_connection *conn; SpiceUsbDeviceManager *manager; conn = g_new0(spice_connection, 1); conn->session = spice_session_new(); //conn->gtk_session = spice_gtk_session_get(conn->session); g_signal_connect(conn->session, "channel-new", G_CALLBACK(channel_new), conn); g_signal_connect(conn->session, "channel-destroy", G_CALLBACK(channel_destroy), conn); g_signal_connect(conn->session, "notify::migration-state", G_CALLBACK(migration_state), conn); manager = spice_usb_device_manager_get(conn->session, NULL); if (manager) { g_signal_connect(manager, "auto-connect-failed", G_CALLBACK(usb_auto_connect_failed), NULL); g_signal_connect(manager, "device-error", G_CALLBACK(usb_device_error), NULL); g_signal_connect(manager, "device-added", G_CALLBACK(usb_device_added), NULL); g_signal_connect(manager, "device-removed", G_CALLBACK(usb_device_removed), NULL); } connections++; SPICE_DEBUG("%s (%d)", __FUNCTION__, connections); return conn; }
int android_spice_input() { int sockfd, newsockfd, servlen; socklen_t clilen; struct sockaddr_un cli_addr, serv_addr; char buf[16]; if ((sockfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0) error("creating socket"); memset((char *) &serv_addr,0, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; char* sock = "/data/data/com.keqisoft.android.spice/spice-input.socket"; remove(sock); strcpy(serv_addr.sun_path, sock); servlen=strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); if(bind(sockfd,(struct sockaddr *)&serv_addr,servlen)<0) error("binding socket"); listen(sockfd,5); clilen = sizeof(cli_addr); newsockfd = accept( sockfd,(struct sockaddr *)&cli_addr,&clilen); if (newsockfd < 0) error("accepting"); while(1) { if(msg_recv_handle(newsockfd,buf)) break; } close(newsockfd); close(sockfd); SPICE_DEBUG("android input over\n"); return 0; }
gboolean SpiceGlibGlue_InitClipboard( int16_t enableClipboardToGuestP, int16_t enableClipboardToClientP, uint32_t *guestClipboardP, uint32_t *hostClipboardP) { SPICE_DEBUG("CB SpiceGlibGlue_InitClipboard (%d, %d)", enableClipboardToGuestP, enableClipboardToClientP); enableClipboardToGuest = enableClipboardToGuestP; enableClipboardToClient = enableClipboardToClientP; guestClipboard = guestClipboardP; hostClipboard = hostClipboardP; SPICE_DEBUG("CB: guestClipboard 0x%x\n", guestClipboard); SPICE_DEBUG("CB: hostClipboard 0x%x\n", hostClipboard); return FALSE; }
static void spice_display_dispose(GObject *obj) { SpiceDisplay *display = SPICE_DISPLAY(obj); SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); SPICE_DEBUG("spice display dispose"); disconnect_main(display); disconnect_display(display); //disconnect_cursor(display); //if (d->clipboard) { // g_signal_handlers_disconnect_by_func(d->clipboard, G_CALLBACK(clipboard_owner_change), // display); // d->clipboard = NULL; //} //if (d->clipboard_primary) { // g_signal_handlers_disconnect_by_func(d->clipboard_primary, G_CALLBACK(clipboard_owner_change), // display); // d->clipboard_primary = NULL; //} if (d->session) { g_signal_handlers_disconnect_by_func(d->session, G_CALLBACK(channel_new), display); g_signal_handlers_disconnect_by_func(d->session, G_CALLBACK(channel_destroy), display); g_object_unref(d->session); d->session = NULL; } }
/** * spice_display_new: * @session: a #SpiceSession * @id: the display channel ID to associate with #SpiceDisplay * * Returns: a new #SpiceDisplay widget. **/ SpiceDisplay *spice_display_new(SpiceSession *session, int id) { SpiceDisplay *display; SpiceDisplayPrivate *d; GList *list; GList *it; display = g_object_new(SPICE_TYPE_DISPLAY, NULL); d = SPICE_DISPLAY_GET_PRIVATE(display); d->session = g_object_ref(session); d->channel_id = id; SPICE_DEBUG("channel_id:%d",d->channel_id); g_signal_connect(session, "channel-new", G_CALLBACK(channel_new), display); g_signal_connect(session, "channel-destroy", G_CALLBACK(channel_destroy), display); list = spice_session_get_channels(session); for (it = g_list_first(list); it != NULL; it = g_list_next(it)) { channel_new(session, it->data, (gpointer*)display); } g_list_free(list); return display; }
/* coroutine context */ G_GNUC_INTERNAL void spice_channel_handle_migrate(SpiceChannel *channel, spice_msg_in *in) { spice_msg_out *out; spice_msg_in *data = NULL; SpiceMsgMigrate *mig = spice_msg_in_parsed(in); spice_channel *c = channel->priv; SPICE_DEBUG("%s: channel %s flags %u", __FUNCTION__, c->name, mig->flags); if (mig->flags & SPICE_MIGRATE_NEED_FLUSH) { /* iterate_write is blocking and flushing all pending write */ SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel); out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MIGRATE_FLUSH_MARK); spice_msg_out_send_internal(out); spice_msg_out_unref(out); SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel); } if (mig->flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) { spice_channel_recv_msg(channel, get_msg_handler, &data); if (!data || data->header.type != SPICE_MSG_MIGRATE_DATA) { g_warning("expected SPICE_MSG_MIGRATE_DATA, got %d", data->header.type); } } spice_session_channel_migrate(c->session, channel); if (mig->flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) { out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MIGRATE_DATA); spice_marshaller_add(out->marshaller, data->data, data->header.size); spice_msg_out_send_internal(out); spice_msg_out_unref(out); } }
static void mjpeg_decoder_schedule(MJpegDecoder *decoder) { if (decoder->timer_id) { return; } guint32 time = stream_get_time(decoder->base.stream); SpiceFrame *frame = decoder->cur_frame; decoder->cur_frame = NULL; do { if (frame) { if (spice_mmtime_diff(time, frame->mm_time) <= 0) { guint32 d = frame->mm_time - time; decoder->cur_frame = frame; decoder->timer_id = g_timeout_add(d, mjpeg_decoder_decode_frame, decoder); break; } SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping ", __FUNCTION__, time - frame->mm_time, frame->mm_time, time); stream_dropped_frame_on_playback(decoder->base.stream); free_spice_frame(frame); } frame = g_queue_pop_head(decoder->msgq); } while (frame); }
/* coroutine context */ G_GNUC_INTERNAL void spice_channel_handle_notify(SpiceChannel *channel, spice_msg_in *in) { spice_channel *c = channel->priv; static const char* severity_strings[] = {"info", "warn", "error"}; static const char* visibility_strings[] = {"!", "!!", "!!!"}; SpiceMsgNotify *notify = spice_msg_in_parsed(in); const char *severity = "?"; const char *visibility = "?"; const char *message_str = NULL; if (notify->severity <= SPICE_NOTIFY_SEVERITY_ERROR) { severity = severity_strings[notify->severity]; } if (notify->visibilty <= SPICE_NOTIFY_VISIBILITY_HIGH) { visibility = visibility_strings[notify->visibilty]; } if (notify->message_len && notify->message_len <= in->dpos - sizeof(*notify)) { message_str = (char*)notify->message; } SPICE_DEBUG("%s: channel %s -- %s%s #%u%s%.*s", __FUNCTION__, c->name, severity, visibility, notify->what, message_str ? ": " : "", notify->message_len, message_str ? message_str : ""); }
static void clipboard_got_from_guest(SpiceMainChannel *main, guint selection, guint type, const guchar *data, guint size, gpointer user_data) { RunInfo *ri = user_data; SpiceGtkSessionPrivate *s = ri->self->priv; gchar *conv = NULL; g_return_if_fail(selection == ri->selection); SPICE_DEBUG("clipboard got data"); if (atom2agent[ri->info].vdagent == VD_AGENT_CLIPBOARD_UTF8_TEXT) { /* on windows, gtk+ would already convert to LF endings, but not on unix */ if (spice_main_agent_test_capability(s->main, VD_AGENT_CAP_GUEST_LINEEND_CRLF)) { GError *err = NULL; conv = spice_dos2unix((gchar*)data, size, &err); if (err) { g_warning("Failed to convert text line ending: %s", err->message); g_clear_error(&err); goto end; } size = strlen(conv); } gtk_selection_data_set_text(ri->selection_data, conv ?: (gchar*)data, size); } else {
static gboolean spice_usbutil_load_usbids(void) { gboolean success = FALSE; g_mutex_lock(&usbids_load_mutex); if (usbids_vendor_count) { success = usbids_vendor_count > 0; goto leave; } #ifdef WITH_USBIDS success = spice_usbutil_parse_usbids(USB_IDS); #else { const gchar * const *dirs = g_get_system_data_dirs(); gchar *path = NULL; int i; for (i = 0; dirs[i]; ++i) { path = g_build_filename(dirs[i], "hwdata", "usb.ids", NULL); success = spice_usbutil_parse_usbids(path); SPICE_DEBUG("loading %s success: %s", path, spice_yes_no(success)); g_free(path); if (success) goto leave; } } #endif leave: g_mutex_unlock(&usbids_load_mutex); return success; }