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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #10
0
/* 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;
}
Beispiel #15
0
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;
}
Beispiel #17
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);

}
Beispiel #20
0
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 {
Beispiel #30
0
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;
}