> 文章列表 > spice stream多屏技术方案

spice stream多屏技术方案

spice stream多屏技术方案

目前现状

目前spice对qxl接口的云视频方案支持最好,对于扩展多屏的方案在qemu的启动配置参数可以完成,libvirt 的多屏参数配置如下:
<video>   <model type='qxl' vram='9126' heads='2'/>  </video>

通过指定heads 的数量就可以确定spice云桌面的扩展屏的数量。

spice的流方案是利用虚拟机上的spice-streaming-agent推流转发到spice server,然后通过display channel 发送到客户端,流方案的libvirt配置如下:
    <channel type='spiceport'><source channel='org.spice-space.stream.0'/><target type='virtio' name='org.spice-space.stream.0'/><address type='virtio-serial' controller='0' bus='0' port='2'/></channel>

配置一个spiceport 的虚拟串口可以产生一个云桌面窗口,但是对于扩展多屏,目前不支持这种配置。需要进一步探索流模式下的多屏方案。

spice stream 多屏方案探索

多stream-channel 方案

方案

stream 的流程如下图所示:

一个spiceport就对应一个streamdevice, 一个streamdevice就对应一个streamChannel, 相对应的客户端创建一个显示窗口。基于以上思路,可以创建两个spiceport,stream-agent 底层抓屏后,拆分成两个屏幕, 再通过两个spiceport 推出去,这样客户端就会产生两个窗口,形成多屏。

实现上是通过修改libvirt的配置如下:

    <channel type='spiceport'><source channel='org.spice-space.stream.0'/><target type='virtio' name='org.spice-space.stream.0'/><address type='virtio-serial' controller='0' bus='0' port='2'/></channel><channel type='spiceport'><source channel='org.spice-space.stream.1'/><target type='virtio' name='org.spice-space.stream.1'/><address type='virtio-serial' controller='0' bus='0' port='3'/></channel>

问题

目前这种方案实现上最容易,不需要修改任何代码,最终客户端可以出现双屏,但是在客户端上鼠标只能在主屏上生效,在扩展屏上鼠标不生效。 产生这种问题的原因是因为,两个流的显示id 都是0
,这样没办法区分两个屏幕,底层的vdagent只会处理display id 为0 的消息,这样第一个流的窗口会生效,第二个不生效。

单spice stream 多monitor的方案

多个流的方案会导致在inputchannel(鼠标输入出现覆盖),可以创建单个流多个monitor的方案,一个monitor 在客户端产生一个窗口对对应一个显示id, 这样各个窗口的显示id不会重复。方案流程如下所示:

依据moitor_config 就可以产生多个屏幕,monitor_config的配置参数如下:

typedef struct SpiceHead {uint32_t monitor_id;    //标识monitor uint32_t surface_id;    //对于扩展屏的方式只有一个surface 为0uint32_t width;         //该monitor对应显示图像的宽uint32_t height;	      //该monitor 对应显示图像的高uint32_t x;            //在surface 中的起始位置  uint32_t y;            //在surface位置uint32_t flags;
} SpiceHead;
typedef struct SpiceMsgDisplayMonitorsConfig {uint16_t count;uint16_t max_allowed;SpiceHead heads[0];
} SpiceMsgDisplayMonitorsConfig;

sql 在读取libvirt多屏配置文件后就会在spice-server 中生成monitor_config, 所以qxl 方式下多屏可以直接生成。但是sream 方式需要额外生成, 目前spice-server 系统中的moitor_config 是直接写成了固定的方式,参考spice_server 项目stream-channel.cpp的marshall_monitors_config 函数:

void
StreamChannelClient::marshall_monitors_config(StreamChannel *channel, SpiceMarshaller *m)
{struct {SpiceMsgDisplayMonitorsConfig config;SpiceHead head;} msg = {{ 1, 1, },{// monitor ID. These IDs are allocated per channel starting from 00,PRIMARY_SURFACE_ID,channel->width, channel->height,0, 0,0 // flags}};init_send_data(SPICE_MSG_DISPLAY_MONITORS_CONFIG);spice_marshall_msg_display_monitors_config(m, &msg.config);
}

以上配置中monitor_config 配置固定成了单屏方式, 显示的是整个屏幕,通过发送SPICE_MSG_DISPLAY_MONITORS_CONFIG信号通知client monitor_config 配置。

spice-server 代码中修改支持多屏

在marshall_monitors_config 直接修改成两屏模式(水平方式),代码如下:

void
StreamChannelClient::marshall_monitors_config(StreamChannel *channel, SpiceMarshaller *m)
{struct {SpiceMsgDisplayMonitorsConfig config;SpiceHead head[2];} msg = {{ 2, 2, },{// monitor ID. These IDs are allocated per channel starting from 00,PRIMARY_SURFACE_ID,channel->width/2, channel->height,0, 0,0 // flags},{// monitor ID. These IDs are allocated per channel starting from 00,PRIMARY_SURFACE_ID,channel->width、2, channel->height,channel->width/2, 0,0 // flags}};init_send_data(SPICE_MSG_DISPLAY_MONITORS_CONFIG);spice_marshall_msg_display_monitors_config(m, &msg.config);
}

通过以上的方式修改后,在spicy 客户端显示中出现出了两个屏幕,但是第二个屏幕屏幕是黑的,通过日志分析问题出现在客户端。