mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-08-12 19:18:11 +00:00
worker: move stream_agent_stop and friends
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
39e1cbe321
commit
8c750746f3
@ -246,6 +246,8 @@ void dcc_push_destroy_surface (DisplayCha
|
||||
uint32_t surface_id);
|
||||
void dcc_add_stream_agent_clip (DisplayChannelClient* dcc,
|
||||
StreamAgent *agent);
|
||||
void dcc_create_stream (DisplayChannelClient *dcc,
|
||||
Stream *stream);
|
||||
|
||||
typedef struct DrawablePipeItem {
|
||||
RingItem base; /* link for a list of pipe items held by Drawable */
|
||||
|
||||
@ -80,7 +80,6 @@
|
||||
#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
|
||||
|
||||
#define FPS_TEST_INTERVAL 1
|
||||
#define MAX_FPS 30
|
||||
|
||||
#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
|
||||
#define MIN_GLZ_SIZE_FOR_ZLIB 100
|
||||
@ -1431,181 +1430,6 @@ static Stream *display_channel_stream_try_new(DisplayChannel *display)
|
||||
return stream;
|
||||
}
|
||||
|
||||
static uint64_t red_stream_get_initial_bit_rate(DisplayChannelClient *dcc,
|
||||
Stream *stream)
|
||||
{
|
||||
char *env_bit_rate_str;
|
||||
uint64_t bit_rate = 0;
|
||||
|
||||
env_bit_rate_str = getenv("SPICE_BIT_RATE");
|
||||
if (env_bit_rate_str != NULL) {
|
||||
double env_bit_rate;
|
||||
|
||||
errno = 0;
|
||||
env_bit_rate = strtod(env_bit_rate_str, NULL);
|
||||
if (errno == 0) {
|
||||
bit_rate = env_bit_rate * 1024 * 1024;
|
||||
} else {
|
||||
spice_warning("error parsing SPICE_BIT_RATE: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (!bit_rate) {
|
||||
MainChannelClient *mcc;
|
||||
uint64_t net_test_bit_rate;
|
||||
|
||||
mcc = red_client_get_main(RED_CHANNEL_CLIENT(dcc)->client);
|
||||
net_test_bit_rate = main_channel_client_is_network_info_initialized(mcc) ?
|
||||
main_channel_client_get_bitrate_per_sec(mcc) :
|
||||
0;
|
||||
bit_rate = MAX(dcc->streams_max_bit_rate, net_test_bit_rate);
|
||||
if (bit_rate == 0) {
|
||||
/*
|
||||
* In case we are after a spice session migration,
|
||||
* the low_bandwidth flag is retrieved from migration data.
|
||||
* If the network info is not initialized due to another reason,
|
||||
* the low_bandwidth flag is FALSE.
|
||||
*/
|
||||
bit_rate = dcc->common.is_low_bandwidth ?
|
||||
RED_STREAM_DEFAULT_LOW_START_BIT_RATE :
|
||||
RED_STREAM_DEFAULT_HIGH_START_BIT_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
spice_debug("base-bit-rate %.2f (Mbps)", bit_rate / 1024.0 / 1024.0);
|
||||
/* dividing the available bandwidth among the active streams, and saving
|
||||
* (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */
|
||||
return (RED_STREAM_CHANNEL_CAPACITY * bit_rate *
|
||||
stream->width * stream->height) / DCC_TO_DC(dcc)->streams_size_total;
|
||||
}
|
||||
|
||||
static uint32_t red_stream_mjpeg_encoder_get_roundtrip(void *opaque)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
int roundtrip;
|
||||
|
||||
spice_assert(agent);
|
||||
roundtrip = red_channel_client_get_roundtrip_ms(RED_CHANNEL_CLIENT(agent->dcc));
|
||||
if (roundtrip < 0) {
|
||||
MainChannelClient *mcc = red_client_get_main(RED_CHANNEL_CLIENT(agent->dcc)->client);
|
||||
|
||||
/*
|
||||
* the main channel client roundtrip might not have been
|
||||
* calculated (e.g., after migration). In such case,
|
||||
* main_channel_client_get_roundtrip_ms returns 0.
|
||||
*/
|
||||
roundtrip = main_channel_client_get_roundtrip_ms(mcc);
|
||||
}
|
||||
|
||||
return roundtrip;
|
||||
}
|
||||
|
||||
static uint32_t red_stream_mjpeg_encoder_get_source_fps(void *opaque)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
|
||||
spice_assert(agent);
|
||||
return agent->stream->input_fps;
|
||||
}
|
||||
|
||||
static void red_display_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgent *remove_agent)
|
||||
{
|
||||
uint32_t new_max_latency = 0;
|
||||
int i;
|
||||
|
||||
if (dcc->streams_max_latency != remove_agent->client_required_latency) {
|
||||
return;
|
||||
}
|
||||
|
||||
dcc->streams_max_latency = 0;
|
||||
if (DCC_TO_DC(dcc)->stream_count == 1) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < NUM_STREAMS; i++) {
|
||||
StreamAgent *other_agent = &dcc->stream_agents[i];
|
||||
if (other_agent == remove_agent || !other_agent->mjpeg_encoder) {
|
||||
continue;
|
||||
}
|
||||
if (other_agent->client_required_latency > new_max_latency) {
|
||||
new_max_latency = other_agent->client_required_latency;
|
||||
}
|
||||
}
|
||||
dcc->streams_max_latency = new_max_latency;
|
||||
}
|
||||
|
||||
static void red_display_stream_agent_stop(DisplayChannelClient *dcc, StreamAgent *agent)
|
||||
{
|
||||
red_display_update_streams_max_latency(dcc, agent);
|
||||
if (agent->mjpeg_encoder) {
|
||||
mjpeg_encoder_destroy(agent->mjpeg_encoder);
|
||||
agent->mjpeg_encoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void red_stream_update_client_playback_latency(void *opaque, uint32_t delay_ms)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
DisplayChannelClient *dcc = agent->dcc;
|
||||
|
||||
red_display_update_streams_max_latency(dcc, agent);
|
||||
|
||||
agent->client_required_latency = delay_ms;
|
||||
if (delay_ms > agent->dcc->streams_max_latency) {
|
||||
agent->dcc->streams_max_latency = delay_ms;
|
||||
}
|
||||
spice_debug("resetting client latency: %u", agent->dcc->streams_max_latency);
|
||||
main_dispatcher_set_mm_time_latency(RED_CHANNEL_CLIENT(agent->dcc)->client, agent->dcc->streams_max_latency);
|
||||
}
|
||||
|
||||
static void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
|
||||
{
|
||||
StreamAgent *agent = &dcc->stream_agents[get_stream_id(DCC_TO_DC(dcc), stream)];
|
||||
|
||||
stream->refs++;
|
||||
spice_assert(region_is_empty(&agent->vis_region));
|
||||
if (stream->current) {
|
||||
agent->frames = 1;
|
||||
region_clone(&agent->vis_region, &stream->current->tree_item.base.rgn);
|
||||
region_clone(&agent->clip, &agent->vis_region);
|
||||
} else {
|
||||
agent->frames = 0;
|
||||
}
|
||||
agent->drops = 0;
|
||||
agent->fps = MAX_FPS;
|
||||
agent->dcc = dcc;
|
||||
|
||||
if (dcc->use_mjpeg_encoder_rate_control) {
|
||||
MJpegEncoderRateControlCbs mjpeg_cbs;
|
||||
uint64_t initial_bit_rate;
|
||||
|
||||
mjpeg_cbs.get_roundtrip_ms = red_stream_mjpeg_encoder_get_roundtrip;
|
||||
mjpeg_cbs.get_source_fps = red_stream_mjpeg_encoder_get_source_fps;
|
||||
mjpeg_cbs.update_client_playback_delay = red_stream_update_client_playback_latency;
|
||||
|
||||
initial_bit_rate = red_stream_get_initial_bit_rate(dcc, stream);
|
||||
agent->mjpeg_encoder = mjpeg_encoder_new(initial_bit_rate, &mjpeg_cbs, agent);
|
||||
} else {
|
||||
agent->mjpeg_encoder = mjpeg_encoder_new(0, NULL, NULL);
|
||||
}
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &agent->create_item);
|
||||
|
||||
if (red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT)) {
|
||||
StreamActivateReportItem *report_pipe_item = spice_malloc0(sizeof(*report_pipe_item));
|
||||
|
||||
agent->report_id = rand();
|
||||
red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel, &report_pipe_item->pipe_item,
|
||||
PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
|
||||
report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc), stream);
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &report_pipe_item->pipe_item);
|
||||
}
|
||||
#ifdef STREAM_STATS
|
||||
memset(&agent->stats, 0, sizeof(StreamStats));
|
||||
if (stream->current) {
|
||||
agent->stats.start = stream->current->red_drawable->mm_time;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void display_channel_create_stream(DisplayChannel *display, Drawable *drawable)
|
||||
{
|
||||
DisplayChannelClient *dcc;
|
||||
@ -6987,7 +6811,7 @@ static void red_display_marshall_stream_end(RedChannelClient *rcc,
|
||||
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
|
||||
destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
|
||||
red_display_stream_agent_stop(dcc, agent);
|
||||
stream_agent_stop(dcc, agent);
|
||||
spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
|
||||
}
|
||||
|
||||
|
||||
174
server/stream.c
174
server/stream.c
@ -138,3 +138,177 @@ StreamClipItem *stream_clip_item_new(DisplayChannelClient* dcc, StreamAgent *age
|
||||
item->refs = 1;
|
||||
return item;
|
||||
}
|
||||
|
||||
static void dcc_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgent *remove_agent)
|
||||
{
|
||||
uint32_t new_max_latency = 0;
|
||||
int i;
|
||||
|
||||
if (dcc->streams_max_latency != remove_agent->client_required_latency) {
|
||||
return;
|
||||
}
|
||||
|
||||
dcc->streams_max_latency = 0;
|
||||
if (DCC_TO_DC(dcc)->stream_count == 1) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < NUM_STREAMS; i++) {
|
||||
StreamAgent *other_agent = &dcc->stream_agents[i];
|
||||
if (other_agent == remove_agent || !other_agent->mjpeg_encoder) {
|
||||
continue;
|
||||
}
|
||||
if (other_agent->client_required_latency > new_max_latency) {
|
||||
new_max_latency = other_agent->client_required_latency;
|
||||
}
|
||||
}
|
||||
dcc->streams_max_latency = new_max_latency;
|
||||
}
|
||||
|
||||
static uint64_t red_stream_get_initial_bit_rate(DisplayChannelClient *dcc,
|
||||
Stream *stream)
|
||||
{
|
||||
char *env_bit_rate_str;
|
||||
uint64_t bit_rate = 0;
|
||||
|
||||
env_bit_rate_str = getenv("SPICE_BIT_RATE");
|
||||
if (env_bit_rate_str != NULL) {
|
||||
double env_bit_rate;
|
||||
|
||||
errno = 0;
|
||||
env_bit_rate = strtod(env_bit_rate_str, NULL);
|
||||
if (errno == 0) {
|
||||
bit_rate = env_bit_rate * 1024 * 1024;
|
||||
} else {
|
||||
spice_warning("error parsing SPICE_BIT_RATE: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (!bit_rate) {
|
||||
MainChannelClient *mcc;
|
||||
uint64_t net_test_bit_rate;
|
||||
|
||||
mcc = red_client_get_main(RED_CHANNEL_CLIENT(dcc)->client);
|
||||
net_test_bit_rate = main_channel_client_is_network_info_initialized(mcc) ?
|
||||
main_channel_client_get_bitrate_per_sec(mcc) :
|
||||
0;
|
||||
bit_rate = MAX(dcc->streams_max_bit_rate, net_test_bit_rate);
|
||||
if (bit_rate == 0) {
|
||||
/*
|
||||
* In case we are after a spice session migration,
|
||||
* the low_bandwidth flag is retrieved from migration data.
|
||||
* If the network info is not initialized due to another reason,
|
||||
* the low_bandwidth flag is FALSE.
|
||||
*/
|
||||
bit_rate = dcc->common.is_low_bandwidth ?
|
||||
RED_STREAM_DEFAULT_LOW_START_BIT_RATE :
|
||||
RED_STREAM_DEFAULT_HIGH_START_BIT_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
spice_debug("base-bit-rate %.2f (Mbps)", bit_rate / 1024.0 / 1024.0);
|
||||
/* dividing the available bandwidth among the active streams, and saving
|
||||
* (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */
|
||||
return (RED_STREAM_CHANNEL_CAPACITY * bit_rate *
|
||||
stream->width * stream->height) / DCC_TO_DC(dcc)->streams_size_total;
|
||||
}
|
||||
|
||||
static uint32_t red_stream_mjpeg_encoder_get_roundtrip(void *opaque)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
int roundtrip;
|
||||
|
||||
roundtrip = red_channel_client_get_roundtrip_ms(RED_CHANNEL_CLIENT(agent->dcc));
|
||||
if (roundtrip < 0) {
|
||||
MainChannelClient *mcc = red_client_get_main(RED_CHANNEL_CLIENT(agent->dcc)->client);
|
||||
|
||||
/*
|
||||
* the main channel client roundtrip might not have been
|
||||
* calculated (e.g., after migration). In such case,
|
||||
* main_channel_client_get_roundtrip_ms returns 0.
|
||||
*/
|
||||
roundtrip = main_channel_client_get_roundtrip_ms(mcc);
|
||||
}
|
||||
|
||||
return roundtrip;
|
||||
}
|
||||
|
||||
static uint32_t red_stream_mjpeg_encoder_get_source_fps(void *opaque)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
|
||||
return agent->stream->input_fps;
|
||||
}
|
||||
|
||||
static void red_stream_update_client_playback_latency(void *opaque, uint32_t delay_ms)
|
||||
{
|
||||
StreamAgent *agent = opaque;
|
||||
DisplayChannelClient *dcc = agent->dcc;
|
||||
|
||||
dcc_update_streams_max_latency(dcc, agent);
|
||||
|
||||
agent->client_required_latency = delay_ms;
|
||||
if (delay_ms > agent->dcc->streams_max_latency) {
|
||||
agent->dcc->streams_max_latency = delay_ms;
|
||||
}
|
||||
spice_debug("resetting client latency: %u", agent->dcc->streams_max_latency);
|
||||
main_dispatcher_set_mm_time_latency(RED_CHANNEL_CLIENT(agent->dcc)->client, agent->dcc->streams_max_latency);
|
||||
}
|
||||
|
||||
void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
|
||||
{
|
||||
StreamAgent *agent = &dcc->stream_agents[get_stream_id(DCC_TO_DC(dcc), stream)];
|
||||
|
||||
spice_return_if_fail(region_is_empty(&agent->vis_region));
|
||||
|
||||
stream->refs++;
|
||||
if (stream->current) {
|
||||
agent->frames = 1;
|
||||
region_clone(&agent->vis_region, &stream->current->tree_item.base.rgn);
|
||||
region_clone(&agent->clip, &agent->vis_region);
|
||||
} else {
|
||||
agent->frames = 0;
|
||||
}
|
||||
agent->drops = 0;
|
||||
agent->fps = MAX_FPS;
|
||||
agent->dcc = dcc;
|
||||
|
||||
if (dcc->use_mjpeg_encoder_rate_control) {
|
||||
MJpegEncoderRateControlCbs mjpeg_cbs;
|
||||
uint64_t initial_bit_rate;
|
||||
|
||||
mjpeg_cbs.get_roundtrip_ms = red_stream_mjpeg_encoder_get_roundtrip;
|
||||
mjpeg_cbs.get_source_fps = red_stream_mjpeg_encoder_get_source_fps;
|
||||
mjpeg_cbs.update_client_playback_delay = red_stream_update_client_playback_latency;
|
||||
|
||||
initial_bit_rate = red_stream_get_initial_bit_rate(dcc, stream);
|
||||
agent->mjpeg_encoder = mjpeg_encoder_new(initial_bit_rate, &mjpeg_cbs, agent);
|
||||
} else {
|
||||
agent->mjpeg_encoder = mjpeg_encoder_new(0, NULL, NULL);
|
||||
}
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &agent->create_item);
|
||||
|
||||
if (red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT)) {
|
||||
StreamActivateReportItem *report_pipe_item = spice_malloc0(sizeof(*report_pipe_item));
|
||||
|
||||
agent->report_id = rand();
|
||||
red_channel_pipe_item_init(RED_CHANNEL_CLIENT(dcc)->channel, &report_pipe_item->pipe_item,
|
||||
PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
|
||||
report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc), stream);
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &report_pipe_item->pipe_item);
|
||||
}
|
||||
#ifdef STREAM_STATS
|
||||
memset(&agent->stats, 0, sizeof(StreamStats));
|
||||
if (stream->current) {
|
||||
agent->stats.start = stream->current->red_drawable->mm_time;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void stream_agent_stop(DisplayChannelClient *dcc, StreamAgent *agent)
|
||||
{
|
||||
dcc_update_streams_max_latency(dcc, agent);
|
||||
if (agent->mjpeg_encoder) {
|
||||
mjpeg_encoder_destroy(agent->mjpeg_encoder);
|
||||
agent->mjpeg_encoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
#define RED_STREAM_CLIENT_REPORT_TIMEOUT 1000 // milliseconds
|
||||
#define RED_STREAM_DEFAULT_HIGH_START_BIT_RATE (10 * 1024 * 1024) // 10Mbps
|
||||
#define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // 2.5Mbps
|
||||
#define MAX_FPS 30
|
||||
|
||||
/* move back to display_channel once struct private */
|
||||
typedef struct DisplayChannel DisplayChannel;
|
||||
@ -143,5 +144,7 @@ void stream_unref (DisplayChan
|
||||
void stream_agent_unref (DisplayChannel *display,
|
||||
StreamAgent *agent);
|
||||
void stream_agent_stats_print (StreamAgent *agent);
|
||||
void stream_agent_stop (DisplayChannelClient *dcc,
|
||||
StreamAgent *agent);
|
||||
|
||||
#endif /* STREAM_H */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user