Skip to content

Commit

Permalink
channels: make it possible to connect/disconnect channels at any time
Browse files Browse the repository at this point in the history
As we plan to use the display feed as a fallback mechansim in Looking
Glass we need to be able to connect it only when we need it otherwise we
will be wasing CPU time processing updates when it's not in use.
  • Loading branch information
gnif committed May 22, 2022
1 parent 4cd5254 commit 7021559
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 25 deletions.
36 changes: 36 additions & 0 deletions include/purespice.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ typedef struct PSServerInfo
}
PSServerInfo;

typedef enum PSChannelType
{
PS_CHANNEL_MAIN,
PS_CHANNEL_INPUTS,
PS_CHANNEL_PLAYBACK,
PS_CHANNEL_RECORD,
PS_CHANNEL_DISPLAY,

PS_CHANNEL_MAX
}
PSChannelType;

typedef enum PSSurfaceFormat
{
PS_SURFACE_FMT_1_A,
Expand Down Expand Up @@ -127,6 +139,16 @@ typedef struct PSConfig
/* [optional] called once the connection is ready (all channels connected) */
void (*ready)(void);

struct
{
/* enable input support if available */
bool enable;

/* automatically connect to the channel as soon as it's available */
bool autoConnect;
}
inputs;

struct
{
/* enable clipboard support if available */
Expand All @@ -151,6 +173,9 @@ typedef struct PSConfig
/* enable the playback channel if available */
bool enable;

/* automatically connect to the channel as soon as it's available */
bool autoConnect;

/* called with the details of the stream to open */
void (*start)(int channels, int sampleRate, PSAudioFormat format,
uint32_t time);
Expand All @@ -174,6 +199,9 @@ typedef struct PSConfig
/* enable the playback channel if available */
bool enable;

/* automatically connect to the channel as soon as it's available */
bool autoConnect;

/* called with the details of the stream to open */
void (*start)(int channels, int sampleRate, PSAudioFormat format);

Expand All @@ -193,6 +221,9 @@ typedef struct PSConfig
/* enable the display channel if available */
bool enable;

/* automatically connect to the channel as soon as it's available */
bool autoConnect;

/* called to create a new surface */
void (*surfaceCreate)(unsigned int surfaceId, PSSurfaceFormat format,
unsigned int width, unsigned int height);
Expand Down Expand Up @@ -239,6 +270,11 @@ PSStatus purespice_process(int timeout);
bool purespice_getServerInfo(PSServerInfo * info);
void purespice_freeServerInfo(PSServerInfo * info);

bool purespice_hasChannel (PSChannelType channel);
bool purespice_channelConnected (PSChannelType channel);
bool purespice_connectChannel (PSChannelType channel);
bool purespice_disconnectChannel(PSChannelType channel);

bool purespice_keyDown (uint32_t code);
bool purespice_keyUp (uint32_t code);
bool purespice_keyModifiers (uint32_t modifiers);
Expand Down
1 change: 1 addition & 0 deletions src/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ void channel_disconnect(PSChannel * channel)
channel->bufferSize = 0;
free(channel->buffer);
channel->buffer = NULL;
channel->connected = false;
}

static PS_STATUS onMessage_setAck(PSChannel * channel)
Expand Down
24 changes: 12 additions & 12 deletions src/channel_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,21 @@ static PS_STATUS onMessage_mainChannelsList(struct PSChannel * channel)
{
SpiceMainChannelsList * msg = (SpiceMainChannelsList *)channel->buffer;

for(int n = 0; n < PS_CHANNEL_MAX; ++n)
{
struct PSChannel * ch = &g_ps.channels[n];
ch->available = false;
}

for(size_t i = 0; i < msg->num_of_channels; ++i)
for(int n = 0; n < PS_CHANNEL_MAX; ++n)
{
struct PSChannel * ch = &g_ps.channels[n];
if (ch->spiceType != msg->channels[i].type ||
(ch->enable && !*ch->enable))
if (ch->spiceType != msg->channels[i].type)
continue;

ch->available = true;
if ((ch->enable && !*ch->enable) || (ch->autoConnect && !*ch->autoConnect))
continue;

if (ch->connected)
Expand All @@ -210,16 +219,7 @@ static PS_STATUS onMessage_mainChannelsList(struct PSChannel * channel)
return PS_STATUS_ERROR;
}

PS_STATUS status;
if ((status = channel_connect(ch)) != PS_STATUS_OK)
{
purespice_disconnect();
PS_LOG_ERROR("Failed to connect to the %s channel", ch->name);
return PS_STATUS_ERROR;
}

PS_LOG_INFO("%s channel connected", ch->name);
if (ch->onConnect && (status = ch->onConnect(ch)) != PS_STATUS_OK)
if (!ps_connectChannel(ch))
{
purespice_disconnect();
PS_LOG_ERROR("Failed to connect to the %s channel", ch->name);
Expand Down
149 changes: 148 additions & 1 deletion src/ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ PS g_ps =
{
.spiceType = SPICE_CHANNEL_INPUTS,
.name = "INPUTS",
.enable = &g_ps.config.inputs.enable,
.autoConnect = &g_ps.config.inputs.autoConnect,
.getConnectPacket = channelInputs_getConnectPacket,
.onMessage = channelInputs_onMessage
},
Expand All @@ -69,6 +71,7 @@ PS g_ps =
.spiceType = SPICE_CHANNEL_PLAYBACK,
.name = "PLAYBACK",
.enable = &g_ps.config.playback.enable,
.autoConnect = &g_ps.config.playback.autoConnect,
.getConnectPacket = channelPlayback_getConnectPacket,
.onMessage = channelPlayback_onMessage
},
Expand All @@ -77,13 +80,15 @@ PS g_ps =
.spiceType = SPICE_CHANNEL_RECORD,
.name = "RECORD",
.enable = &g_ps.config.record.enable,
.autoConnect = &g_ps.config.record.autoConnect,
.getConnectPacket = channelRecord_getConnectPacket,
.onMessage = channelRecord_onMessage,
},
{
.spiceType = SPICE_CHANNEL_DISPLAY,
.name = "DISPLAY",
.enable = &g_ps.config.display.enable,
.autoConnect = &g_ps.config.display.autoConnect,
.getConnectPacket = channelDisplay_getConnectPacket,
.onConnect = channelDisplay_onConnect,
.onMessage = channelDisplay_onMessage
Expand Down Expand Up @@ -186,6 +191,33 @@ bool purespice_connect(const PSConfig * config)
}
}

if (g_ps.config.display.enable)
{
if (!g_ps.config.display.surfaceCreate)
{
PS_LOG_ERROR("display->surfaceCreate is mandatory");
goto err_config;
}

if (!g_ps.config.display.surfaceDestroy)
{
PS_LOG_ERROR("display->surfaceDestroy is mandatory");
goto err_config;
}

if (!g_ps.config.display.drawBitmap)
{
PS_LOG_ERROR("display->drawBitmap is mandatory");
goto err_config;
}

if (!g_ps.config.display.drawFill)
{
PS_LOG_ERROR("display->drawFill is mandatory");
goto err_config;
}
}

memset(&g_ps.addr, 0, sizeof(g_ps.addr));

if (g_ps.config.port == 0)
Expand Down Expand Up @@ -485,8 +517,8 @@ PSStatus purespice_process(int timeout)

done_disconnect:
++done;
channel->connected = false;
events[i].data.ptr = NULL;
channel_disconnect(channel);
}
}

Expand Down Expand Up @@ -522,3 +554,118 @@ void purespice_freeServerInfo(PSServerInfo * info)
if (info->name)
free(info->name);
}

static uint8_t channelTypeToSpiceType(PSChannelType channel)
{
switch(channel)
{
case PS_CHANNEL_MAIN:
return SPICE_CHANNEL_MAIN;

case PS_CHANNEL_INPUTS:
return SPICE_CHANNEL_INPUTS;

case PS_CHANNEL_PLAYBACK:
return SPICE_CHANNEL_PLAYBACK;

case PS_CHANNEL_RECORD:
return SPICE_CHANNEL_RECORD;

case PS_CHANNEL_DISPLAY:
return SPICE_CHANNEL_DISPLAY;

default:
PS_LOG_ERROR("Invalid channel");
return 255;
};

__builtin_unreachable();
}

static PSChannel * getChannel(PSChannelType channel)
{
const uint8_t spiceType = channelTypeToSpiceType(channel);
if (spiceType == 255)
return NULL;

for(int i = 0; i < PS_CHANNEL_MAX; ++i)
if (g_ps.channels[i].spiceType == spiceType)
return &g_ps.channels[i];

__builtin_unreachable();
}

bool purespice_hasChannel(PSChannelType channel)
{
PSChannel * ch = getChannel(channel);
if (!ch)
return false;

return ch->available;
}

bool purespice_channelConnected(PSChannelType channel)
{
PSChannel * ch = getChannel(channel);
if (!ch)
return false;
return ch->connected;
}

PS_STATUS ps_connectChannel(PSChannel * ch)
{
PS_STATUS status;
if ((status = channel_connect(ch)) != PS_STATUS_OK)
{
purespice_disconnect();
PS_LOG_ERROR("Failed to connect to the %s channel", ch->name);
return status;
}

PS_LOG_INFO("%s channel connected", ch->name);
if (ch->onConnect && (status = ch->onConnect(ch)) != PS_STATUS_OK)
{
purespice_disconnect();
PS_LOG_ERROR("Failed to connect to the %s channel", ch->name);
return status;
}

return PS_STATUS_OK;
}

bool purespice_connectChannel(PSChannelType channel)
{
PSChannel * ch = getChannel(channel);
if (!ch)
return false;

if (!ch->available)
{
PS_LOG_ERROR("%s: Channel is not availble", ch->name);
return false;
}

if (ch->connected)
return true;

return ps_connectChannel(ch) == PS_STATUS_OK;
}

bool purespice_disconnectChannel(PSChannelType channel)
{
PSChannel * ch = getChannel(channel);
if (!ch)
return false;

if (!ch->available)
{
PS_LOG_ERROR("%s: Channel is not availble", ch->name);
return false;
}

if (!ch->connected)
return true;

channel_disconnect(ch);
return true;
}
16 changes: 4 additions & 12 deletions src/ps.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define _SPICE_MOUSE_BUTTON_MASK_SIDE (1 << 5)
#define _SPICE_MOUSE_BUTTON_MASK_EXTRA (1 << 6)

typedef enum
{
PS_CHANNEL_MAIN,
PS_CHANNEL_INPUTS,
PS_CHANNEL_PLAYBACK,
PS_CHANNEL_RECORD,
PS_CHANNEL_DISPLAY,

PS_CHANNEL_MAX
}
PSChannel;

typedef enum
{
PS_STATUS_OK,
Expand All @@ -136,7 +124,9 @@ struct PSChannel
{
uint8_t spiceType;
const char * name;
bool available;
bool * enable;
bool * autoConnect;

SpiceMiniDataHeader header;
unsigned int headerRead;
Expand Down Expand Up @@ -211,6 +201,8 @@ struct PS

extern PS g_ps;

PS_STATUS ps_connectChannel(PSChannel * ch);

PS_STATUS purespice_onCommonRead(PSChannel * channel,
SpiceMiniDataHeader * header, int * dataAvailable);

Expand Down
16 changes: 16 additions & 0 deletions test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ int main(int argc, char * argv[])
.port = port,
.password = "",
.ready = connection_ready,
.inputs =
{
.enable = true,
.autoConnect = false
},
.clipboard =
{
.enable = false,
Expand All @@ -337,6 +342,7 @@ int main(int argc, char * argv[])
},
.display = {
.enable = true,
.autoConnect = false,
.surfaceCreate = display_surfaceCreate,
.surfaceDestroy = display_surfaceDestroy,
.drawFill = display_drawFill,
Expand Down Expand Up @@ -401,6 +407,16 @@ int main(int argc, char * argv[])
goto exit;

case ADL_EVENT_KEY_DOWN:
if (purespice_channelConnected(PS_CHANNEL_DISPLAY))
{
printf("Disconnect display\n");
purespice_disconnectChannel(PS_CHANNEL_DISPLAY);
}
else
{
printf("Connect display\n");
purespice_connectChannel(PS_CHANNEL_DISPLAY);
}
break;

case ADL_EVENT_KEY_UP:
Expand Down

0 comments on commit 7021559

Please sign in to comment.