diff options
Diffstat (limited to 'src/spice-stream.cpp')
-rw-r--r-- | src/spice-stream.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/spice-stream.cpp b/src/spice-stream.cpp new file mode 100644 index 0000000..3aa951c --- /dev/null +++ b/src/spice-stream.cpp @@ -0,0 +1,162 @@ +/* Utility to manage registration of plugins compiled statically + * + * \copyright + * Copyright 2017 Red Hat Inc. All rights reserved. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <syslog.h> +#include <string.h> +#include <memory> +#include <spice/stream-device.h> +#include <spice/enums.h> + +#include "spice-stream.hpp" + +// FIXME +extern int streaming_requested; + +using namespace SpiceStreamingAgent; + +struct SpiceStreamFormatMessage +{ + StreamDevHeader hdr; + StreamMsgFormat msg; +}; + +struct SpiceStreamDataMessage +{ + StreamDevHeader hdr; + StreamMsgData msg; +}; + +int SpiceStream::read_command() +{ + StreamDevHeader hdr; + uint8_t msg[64]; + int n; + + std::lock_guard<std::mutex> stream_guard(stream_mtx); + n = read(streamfd, &hdr, sizeof(hdr)); + if (n != sizeof(hdr)) { + syslog(LOG_WARNING, + "read command from device FAILED -- read %d expected %lu\n", + n, sizeof(hdr)); + return -1; + } + if (hdr.protocol_version != STREAM_DEVICE_PROTOCOL) { + syslog(LOG_WARNING, "BAD VERSION %d (expected is %d)\n", hdr.protocol_version, + STREAM_DEVICE_PROTOCOL); + return 0; // return -1; -- fail over this ? + } + if (hdr.type != STREAM_TYPE_START_STOP) { + syslog(LOG_WARNING, "UNKNOWN msg of type %d\n", hdr.type); + return 0; // return -1; + } + if (hdr.size >= sizeof(msg)) { + syslog(LOG_WARNING, + "msg size (%d) is too long (longer than %lu)\n", + hdr.size, sizeof(msg)); + return 0; // return -1; + } + n = read(streamfd, &msg, hdr.size); + if (n != hdr.size) { + syslog(LOG_WARNING, + "read command from device FAILED -- read %d expected %d\n", + n, hdr.size); + return -1; + } + streaming_requested = msg[0]; /* num_codecs */ + syslog(LOG_INFO, "GOT START_STOP message -- request to %s streaming\n", + streaming_requested ? "START" : "STOP"); + return 1; +} + +int SpiceStream::send_format(unsigned w, unsigned h, unsigned c) +{ + + SpiceStreamFormatMessage msg; + const size_t msgsize = sizeof(msg); + const size_t hdrsize = sizeof(msg.hdr); + memset(&msg, 0, msgsize); + msg.hdr.protocol_version = STREAM_DEVICE_PROTOCOL; + msg.hdr.type = STREAM_TYPE_FORMAT; + msg.hdr.size = msgsize - hdrsize; /* includes only the body? */ + msg.msg.width = w; + msg.msg.height = h; + msg.msg.codec = c; + syslog(LOG_DEBUG, "writing format\n"); + std::lock_guard<std::mutex> stream_guard(stream_mtx); + if (write_all(&msg, msgsize) != msgsize) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +int SpiceStream::send_frame(const void *buf, const unsigned size) +{ + SpiceStreamDataMessage msg; + const size_t msgsize = sizeof(msg); + ssize_t n; + + memset(&msg, 0, msgsize); + msg.hdr.protocol_version = STREAM_DEVICE_PROTOCOL; + msg.hdr.type = STREAM_TYPE_DATA; + msg.hdr.size = size; /* includes only the body? */ + std::lock_guard<std::mutex> stream_guard(stream_mtx); + n = write_all(&msg, msgsize); + syslog(LOG_DEBUG, + "wrote %ld bytes of header of data msg with frame of size %u bytes\n", + n, msg.hdr.size); + if (n != msgsize) { + syslog(LOG_WARNING, "write_all header: wrote %ld expected %lu\n", + n, msgsize); + return EXIT_FAILURE; + } + n = write_all(buf, size); + syslog(LOG_DEBUG, "wrote data msg body of size %ld\n", n); + if (n != size) { + syslog(LOG_WARNING, "write_all header: wrote %ld expected %u\n", + n, size); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +void SpiceStream::send_cursor(unsigned width, unsigned height, int hotspot_x, int hotspot_y, + std::function<void(uint32_t *)> fill_cursor) +{ + if (width >= STREAM_MSG_CURSOR_SET_MAX_WIDTH || + height >= STREAM_MSG_CURSOR_SET_MAX_HEIGHT) + return; + + size_t cursor_size = + sizeof(StreamDevHeader) + sizeof(StreamMsgCursorSet) + + width * height * sizeof(uint32_t); + std::unique_ptr<uint8_t[]> msg(new uint8_t[cursor_size]); + + StreamDevHeader &dev_hdr(*reinterpret_cast<StreamDevHeader*>(msg.get())); + memset(&dev_hdr, 0, sizeof(dev_hdr)); + dev_hdr.protocol_version = STREAM_DEVICE_PROTOCOL; + dev_hdr.type = STREAM_TYPE_CURSOR_SET; + dev_hdr.size = cursor_size - sizeof(StreamDevHeader); + + StreamMsgCursorSet &cursor_msg(*reinterpret_cast<StreamMsgCursorSet *>(msg.get() + sizeof(StreamDevHeader))); + memset(&cursor_msg, 0, sizeof(cursor_msg)); + + cursor_msg.type = SPICE_CURSOR_TYPE_ALPHA; + cursor_msg.width = width; + cursor_msg.height = height; + cursor_msg.hot_spot_x = hotspot_x; + cursor_msg.hot_spot_y = hotspot_y; + + uint32_t *pixels = reinterpret_cast<uint32_t *>(cursor_msg.data); + fill_cursor(pixels); + + std::lock_guard<std::mutex> stream_guard(stream_mtx); + write_all(msg.get(), cursor_size); +} + |