summaryrefslogtreecommitdiffstats
path: root/server/stream.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2015-11-13 10:29:17 -0600
committerFrediano Ziglio <fziglio@redhat.com>2015-11-18 14:10:45 +0000
commit8c750746f33a3c562cd96471f5ffc9c49aa1869f (patch)
treeb88fc3cdc63c1d2f14d375eeb10084663a354365 /server/stream.c
parent39e1cbe3211b06bca6e5d906ffb4d0582440c5cc (diff)
downloadspice-8c750746f33a3c562cd96471f5ffc9c49aa1869f.tar.gz
spice-8c750746f33a3c562cd96471f5ffc9c49aa1869f.tar.xz
spice-8c750746f33a3c562cd96471f5ffc9c49aa1869f.zip
worker: move stream_agent_stop and friends
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
Diffstat (limited to 'server/stream.c')
-rw-r--r--server/stream.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/server/stream.c b/server/stream.c
index 406111c2..27d6d36e 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;
+ }
+}