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 客户端显示中出现出了两个屏幕,但是第二个屏幕屏幕是黑的,通过日志分析问题出现在客户端。