ACK On Tue, 2015-11-17 at 16:37 +0000, Frediano Ziglio wrote: > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> > > --- > server/display-channel.h | 2 + > server/red_worker.c | 178 +--------------------------------------------- > - > server/stream.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ > server/stream.h | 3 + > 4 files changed, 180 insertions(+), 177 deletions(-) > > diff --git a/server/display-channel.h b/server/display-channel.h > index edbd4b9..ae8a900 100644 > --- a/server/display-channel.h > +++ b/server/display-channel.h > @@ -252,6 +252,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 */ > diff --git a/server/red_worker.c b/server/red_worker.c > index 6a331cb..5269752 100644 > --- a/server/red_worker.c > +++ b/server/red_worker.c > @@ -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 > @@ -1353,181 +1352,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; > @@ -6872,7 +6696,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); > } > > diff --git a/server/stream.c b/server/stream.c > index 406111c..27d6d36 100644 > --- a/server/stream.c > +++ b/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; > + } > +} > diff --git a/server/stream.h b/server/stream.h > index 09df31b..c2007af 100644 > --- a/server/stream.h > +++ b/server/stream.h > @@ -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 */ _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel