1、SPICE_DISABLE_CHANNELS:禁止其他通道的消息处理
const char *disabled = g_getenv("SPICE_DISABLE_CHANNELS");
if (disabled && strstr(disabled, desc))
c->disable_channel_msg = TRUE;
2、SPICE_AGENT_LOG_RECORDS:开启日志显示
static void recorder_trace_entry(recorder_info *info, recorder_entry *entry, ...)
// ----------------------------------------------------------------------------
// Show a recorder entry when a trace is enabled
// ----------------------------------------------------------------------------
{
va_list args;
if (strchr(entry->format, '\n') != NULL) {
g_critical("Agent records cannot contain '\n' char ... (%s)", entry->where);
return;
}
// send info/entry to the socket
g_mutex_lock(&mutex_socket);
if (communication_f == NULL) {
g_mutex_unlock(&mutex_socket);
return;
}
va_start(args, entry);
do_send_entry(communication_f, info, entry, args);
va_end(args);
if (g_strcmp0(g_getenv("SPICE_AGENT_LOG_RECORDS"), "1") == 0) {
va_start(args, entry);
do_send_entry(stderr, info, entry, args);
va_end(args);
}
g_mutex_unlock(&mutex_socket);
}
3、SPICE_DISABLE_ADAPTIVE_STREAMING:是否开启自适应视频
static void spice_display_channel_init(SpiceDisplayChannel *channel)
{
SpiceDisplayChannelPrivate *c;
c = channel->priv = spice_display_channel_get_instance_private(channel);
c->surfaces = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_surface);
c->image_cache.ops = &image_cache_ops;
c->palette_cache.ops = &palette_cache_ops;
c->image_surfaces.ops = &image_surfaces_ops;
c->monitors_max = 1;
c->scanout.fd = -1;
if (g_getenv("SPICE_DISABLE_ADAPTIVE_STREAMING")) {
SPICE_DEBUG("adaptive video disabled");
c->enable_adaptive_streaming = FALSE;
} else {
c->enable_adaptive_streaming = TRUE;
}
}
/* coroutine context */
static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
{
...
if (c->enable_adaptive_streaming) {
display_update_stream_report(SPICE_DISPLAY_CHANNEL(channel), op->id, op->multi_media_time, margin_report);
if (st->playback_sync_drops_seq_len >= STREAM_PLAYBACK_SYNC_DROP_SEQ_LEN_LIMIT) {
spice_session_sync_playback_latency(spice_channel_get_session(channel));
st->playback_sync_drops_seq_len = 0;
}
}
}
static void spice_display_channel_set_capabilities(SpiceChannel *channel)
{
SpiceSession *s = spice_channel_get_session(channel);
guint i;
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_SIZED_STREAM);
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_COMPOSITE);
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_A8_SURFACE);
#ifdef USE_LZ4
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_LZ4_COMPRESSION);
#endif
if (SPICE_DISPLAY_CHANNEL(channel)->priv->enable_adaptive_streaming) {
spice_channel_set_capability(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
}
...
}
4、SPICE_MAX_CLIPBOARD:剪切板最大字符数
case PROP_MAX_CLIPBOARD:
g_value_set_int(value, spice_main_get_max_clipboard(self));
break;
5、SPICE_MIG_HOST
/* main context */
static gboolean migrate_connect(spice_migrate *mig)
{
int port, sport;
const char *host;
g_return_val_if_fail(mig != NULL, FALSE);
g_return_val_if_fail(mig->nchannels == 0, FALSE);
g_return_val_if_fail(mig->session != NULL, FALSE);
spice_session_set_migration_state(mig->session, SPICE_SESSION_MIGRATION_CONNECTING);
SpiceMigrationDstInfo *info = &mig->info;
SPICE_DEBUG("migrate_begin %u %s %d %d",info->host_size, info->host_data, info->port, info->sport);
port = info->port;
sport = info->sport;
host = (char*)info->host_data;
if (info->cert_subject_data == NULL ||
strlen((const char*)info->cert_subject_data) == 0) {
/* only verify hostname if no cert subject */
g_object_set(mig->session, "verify", SPICE_SESSION_VERIFY_HOSTNAME, NULL);
} else {
// session data are already copied
g_object_set(mig->session,
"cert-subject", info->cert_subject_data,
"verify", SPICE_SESSION_VERIFY_SUBJECT,
NULL);
}
if (g_getenv("SPICE_MIG_HOST"))
host = g_getenv("SPICE_MIG_HOST");
...
}
6、SPICE_DISABLE_OPUS:禁用播放通道和录音通道的opus编码
static void spice_playback_channel_set_capabilities(SpiceChannel *channel)
{
if (!g_getenv("SPICE_DISABLE_OPUS"))
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_PLAYBACK_CAP_OPUS);
spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_PLAYBACK_CAP_VOLUME);
spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_PLAYBACK_CAP_LATENCY);
}
static void spice_record_channel_set_capabilities(SpiceChannel *channel)
{
if (!g_getenv("SPICE_DISABLE_OPUS"))
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_RECORD_CAP_OPUS);
spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_RECORD_CAP_VOLUME);
}
7、SPICE_GST_AUDIOSINK:使用环境变量的播放声音的pipeline
static void playback_start(SpicePlaybackChannel *channel, gint format, gint channels,
gint frequency, gpointer data)
{
SpiceGstaudio *gstaudio = data;
SpiceGstaudioPrivate *p = gstaudio->priv;
...
if (!p->playback.pipe) {
GError *error = NULL;
gchar *audio_caps = g_strdup_printf("audio/x-raw,format=\"S16LE\",channels=%d,rate=%d,layout=interleaved", channels, frequency);
gchar *pipeline = g_strdup (g_getenv("SPICE_GST_AUDIOSINK"));
if (pipeline == NULL)
pipeline = g_strdup_printf("appsrc is-live=1 do-timestamp=0 format=time caps=\"%s\" name=\"appsrc\" ! queue ! "
"audioconvert ! audioresample ! autoaudiosink name=\"audiosink\"", audio_caps);
...
}
8、HOME:获取工作主目录
void spice_set_session_option(SpiceSession *session)
{
g_return_if_fail(SPICE_IS_SESSION(session));
if (ca_file == NULL) {
const char *homedir = g_getenv("HOME");
if (!homedir)
homedir = g_get_home_dir();
ca_file = g_build_filename(homedir, ".spicec", "spice_truststore.pem", NULL);
if (!g_file_test(ca_file, G_FILE_TEST_IS_REGULAR))
g_clear_pointer(&ca_file, g_free);
}
...
}
9、SPICE_PROXY:设置网络代理
static void update_proxy(SpiceSession *self, const gchar *str)
{
SpiceSessionPrivate *s = self->priv;
SpiceURI *proxy = NULL;
GError *error = NULL;
if (str == NULL)
str = g_getenv("SPICE_PROXY");
if (str == NULL || *str == 0) {
g_clear_object(&s->proxy);
return;
}
proxy = spice_uri_new();
if (!spice_uri_parse(proxy, str, &error))
g_clear_object(&proxy);
if (error) {
g_warning("%s", error->message);
g_clear_error(&error);
}
if (proxy != NULL) {
g_clear_object(&s->proxy);
s->proxy = proxy;
}
}
10、SPICE_DISABLE_GL_SCANOUT:禁用opengl-es显示
/**
* SpiceSession:gl-scanout:
*
* Whether to enable gl-scanout (Unix only). Set to TRUE by
* default on EGL-enabled host, unless SPICE_DISABLE_GL_SCANOUT
* environment variable is set.
*
* Since: 0.36
**/
g_object_class_install_property
(gobject_class, PROP_GL_SCANOUT,
g_param_spec_boolean("gl-scanout",
"Enable GL scanout support",
"Enable GL scanout support",
#ifdef HAVE_EGL
g_getenv("SPICE_DISABLE_GL_SCANOUT") == NULL,
G_PARAM_CONSTRUCT |
#else
false,
#endif
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
11、G_MESSAGES_DEBUG:打开g_debug()的输出(export G_MESSAGES_DEBUG=all)
static void spice_util_enable_debug_messages(void)
{
const gchar *doms = g_getenv("G_MESSAGES_DEBUG");
if (!doms) {
g_setenv("G_MESSAGES_DEBUG", G_LOG_DOMAIN, 1);
} else if (g_str_equal(doms, "all")) {
return;
} else if (!strstr(doms, G_LOG_DOMAIN)) {
gchar *newdoms = g_strdup_printf("%s %s", doms, G_LOG_DOMAIN);
g_setenv("G_MESSAGES_DEBUG", newdoms, 1);
g_free(newdoms);
}
}
12、SPICE_DEBUG:是否开启debug信息
static gpointer getenv_debug(gpointer data)
{
gboolean debug;
debug = (g_getenv("SPICE_DEBUG") != NULL);
if (debug)
spice_util_enable_debug_messages();
return GINT_TO_POINTER(debug);
}
13、SPICE_KEYPRESS_DELAY:显示通道设置键盘延时的时间
static void
spice_display_set_keypress_delay(SpiceDisplay *display, guint delay)
{
SpiceDisplayPrivate *d = display->priv;
const gchar *env = g_getenv("SPICE_KEYPRESS_DELAY");
if (env != NULL)
delay = strtoul(env, NULL, 10);
if (d->keypress_delay != delay) {
DISPLAY_DEBUG(display, "keypress-delay is set to %u ms", delay);
d->keypress_delay = delay;
g_object_notify(G_OBJECT(display), "keypress-delay");
}
}
14、SPICE_DEBUG_CURSOR:光标通道名称
static GdkCursor* spice_display_get_blank_cursor(SpiceDisplay *display)
{
GdkDisplay *gdk_display;
const gchar *cursor_name;
GdkWindow *gdk_window = GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(display)));
if (gdk_window == NULL)
return NULL;
gdk_display = gdk_window_get_display(gdk_window);
cursor_name = g_getenv("SPICE_DEBUG_CURSOR") ? "crosshair" : "none";
return gdk_cursor_new_from_name(gdk_display, cursor_name);
}
15、SPICE_NOGRAB:输入通道不抓取键盘和鼠标
static void try_keyboard_grab(SpiceDisplay *display)
{
GtkWidget *widget = GTK_WIDGET(display);
SpiceDisplayPrivate *d = display->priv;
GdkGrabStatus status;
if (g_getenv("SPICE_NOGRAB"))
return;
if (d->disable_inputs)
return;
...
}
static void try_mouse_grab(SpiceDisplay *display)
{
SpiceDisplayPrivate *d = display->priv;
if (g_getenv("SPICE_NOGRAB"))
return;
if (d->disable_inputs)
return;
...
}
16、DISABLE_GSTVIDEOOVERLAY:禁用视频窗口绑定
static void gst_sync_bus_call(GstBus *bus, GstMessage *msg, SpiceDisplay *display)
{
switch(GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ELEMENT: {
if (gst_is_video_overlay_prepare_window_handle_message(msg) && !g_getenv("DISABLE_GSTVIDEOOVERLAY") && GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(display));
if (window && gdk_window_ensure_native(window)) {
SpiceDisplayPrivate *d = display->priv;
GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg));
g_weak_ref_set(&d->overlay_weak_ref, overlay);
gst_video_overlay_handle_events(overlay, false);
gst_video_overlay_set_window_handle(overlay, (uintptr_t)GDK_WINDOW_XID(window));
return;
}
}
break;
}
...
}
/* This callback should pass to the widget a pointer of the pipeline
* so that we can the set GST pipeline and overlay related calls from
* here. If the pipeline pointer is NULL, the drawing area of the
* native renderer is set visible.
*/
static gboolean set_overlay(SpiceChannel *channel, void* pipeline_ptr, SpiceDisplay *display)
{
SpiceDisplayPrivate *d = display->priv;
if (pipeline_ptr == NULL) {
gtk_stack_set_visible_child_name(d->stack, "draw-area");
return true;
}
#if defined(GDK_WINDOWING_X11)
/* GstVideoOverlay is currently used only under x */
if (!g_getenv("DISABLE_GSTVIDEOOVERLAY") &&
GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
GdkWindow *window;
window = gtk_widget_get_window(GTK_WIDGET(display));
if (window && gdk_window_ensure_native(window)) {
GstBus *bus;
gtk_stack_set_visible_child_name(d->stack, "gst-area");
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_ptr));
gst_bus_enable_sync_message_emission(bus);
g_signal_connect(bus, "sync-message", G_CALLBACK(gst_sync_bus_call), display);
gst_object_unref(bus);
return true;
}
}
#endif
return false;
}
17、SPICE_USB_ACL_BINARY:ACL设备名称
G_GNUC_INTERNAL
void spice_usb_acl_helper_open_acl_async(SpiceUsbAclHelper *self,
gint busnum, gint devnum,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail(SPICE_IS_USB_ACL_HELPER(self));
SpiceUsbAclHelperPrivate *priv = self->priv;
GTask *task;
GError *err = NULL;
GIOStatus status;
GPid helper_pid;
gsize bytes_written;
const gchar *acl_helper = g_getenv("SPICE_USB_ACL_BINARY");
if (acl_helper == NULL)
acl_helper = ACL_HELPER_PATH"/spice-client-glib-usb-acl-helper";
gchar *argv[] = { (char*)acl_helper, NULL };
gint in, out;
gchar buf[128];
task = g_task_new(self, cancellable, callback, user_data);
if (priv->out_ch) {
g_task_return_new_error(task,SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,"Error acl-helper already has an acl open");
goto done;
}
...
}