ref: 73ef8a7e9d895b7d5aba295d8242e93824bc5fb2
parent: 4328e3dc108fd1e6ab4d1d08dcca9004ad09d344
author: Alex Mayfield <[email protected]>
date: Sat Feb 18 13:59:25 EST 2017
First working prototype Since I had communication working, I then completely reworked the original interface to cater to Chocolate Doom. A couple of hours later, I finally have a working prototype - launching Chocolate Doom will play music, and you can control the music volume independently of the sound effects.
--- a/midiproc/main.c
+++ b/midiproc/main.c
@@ -43,93 +43,48 @@
// Currently playing music track
static Mix_Music *music = NULL;
-static char *filename = NULL;
-static void UnregisterSong();
-
//=============================================================================
//
// SDL_mixer Interface
//
-//
-// RegisterSong
-//
-static void RegisterSong(char* filename)
+static boolean RegisterSong(const char *filename)
{
- if (music)
- {
- UnregisterSong();
- }
+ fprintf(stderr, "%s %s\n", __FUNCTION__, filename);
music = Mix_LoadMUS(filename);
-}
+ fprintf(stderr, "<-- %p\n", music);
-//
-// StartSong
-//
-static void StartSong(boolean loop)
-{
- if (music)
+ if (music == NULL)
{
- Mix_PlayMusic(music, loop ? -1 : 0);
+ fprintf(stderr, "Error loading midi: %s\n", Mix_GetError());
+
+ return false;
}
-}
-//
-// SetVolume
-//
-static void SetVolume(int volume)
-{
- Mix_VolumeMusic((volume * 128) / 15);
+ return true;
}
-static int paused_midi_volume;
-
-//
-// PauseSong
-//
-static void PauseSong()
+static void SetVolume(int vol)
{
- paused_midi_volume = Mix_VolumeMusic(-1);
- Mix_VolumeMusic(0);
+ fprintf(stderr, "%s %d\n", __FUNCTION__, vol);
+
+ Mix_VolumeMusic(vol);
}
-//
-// ResumeSong
-//
-static void ResumeSong()
+static void PlaySong(int loops)
{
- Mix_VolumeMusic(paused_midi_volume);
+ fprintf(stderr, "%s %d\n", __FUNCTION__, loops);
+
+ Mix_PlayMusic(music, loops);
}
-//
-// StopSong
-//
static void StopSong()
{
- if (music)
- {
- Mix_HaltMusic();
- }
-}
+ fprintf(stderr, "%s\n", __FUNCTION__);
-//
-// UnregisterSong
-//
-static void UnregisterSong()
-{
- if (!music)
- {
- return;
- }
-
- StopSong();
- Mix_FreeMusic(music);
- free(filename);
-
- filename = NULL;
- music = NULL;
+ Mix_HaltMusic();
}
//
@@ -144,178 +99,85 @@
//=============================================================================
//
-// RPC Server Interface
+// Pipe Server Interface
//
-//
-// MidiPipe_PrepareNewSong
-//
-// Prepare the engine to receive new song data from the RPC client.
-//
-boolean MidiPipe_PrepareNewSong()
+static boolean MidiPipe_RegisterSong(buffer_reader_t *reader)
{
- // Stop anything currently playing and free it.
- UnregisterSong();
-
- fprintf(stderr, "%s\n", __FUNCTION__);
- return true;
-}
-
-//
-// MidiPipe_AddChunk
-//
-// Set the filename of the song.
-//
-boolean MidiPipe_SetFilename(buffer_reader_t *reader)
-{
- free(filename);
- filename = NULL;
-
- char* file = Reader_ReadString(reader);
- if (file == NULL)
+ char *filename = Reader_ReadString(reader);
+ if (filename == NULL)
{
return false;
}
- int size = Reader_BytesRead(reader) - 2;
- if (size <= 0)
- {
- return false;
- }
+ RegisterSong(filename);
- filename = malloc(size);
- if (filename == NULL)
- {
- return false;
- }
+ unsigned int i = NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG_ACK;
+ CHAR buffer[2];
+ buffer[0] = (i >> 8) & 0xff;
+ buffer[1] = i & 0xff;
- memcpy(filename, file, size);
+ BOOL ok = WriteFile(midi_process_out, buffer, sizeof(buffer),
+ NULL, NULL);
- fprintf(stderr, "%s\n", __FUNCTION__);
return true;
}
-//
-// MidiPipe_PlaySong
-//
-// Start playing the song.
-//
-boolean MidiPipe_PlaySong(buffer_reader_t *reader)
+boolean MidiPipe_SetVolume(buffer_reader_t *reader)
{
- uint8_t looping;
-
- if (!Reader_ReadInt8(reader, &looping))
+ int vol;
+ boolean ok = Reader_ReadInt32(reader, &vol);
+ if (!ok)
{
return false;
}
- RegisterSong(filename);
- StartSong((boolean)looping);
+ SetVolume(vol);
- fprintf(stderr, "%s\n", __FUNCTION__);
return true;
}
-//
-// MidiPipe_StopSong
-//
-// Stop the song.
-//
-boolean MidiPipe_StopSong()
+boolean MidiPipe_PlaySong(buffer_reader_t *reader)
{
- StopSong();
-
- fprintf(stderr, "%s\n", __FUNCTION__);
- return true;
-}
-
-//
-// MidiPipe_ChangeVolume
-//
-// Set playback volume level.
-//
-boolean MidiPipe_ChangeVolume(buffer_reader_t *reader)
-{
- int volume;
-
- if (!Reader_ReadInt32(reader, &volume))
+ int loops;
+ boolean ok = Reader_ReadInt32(reader, &loops);
+ if (!ok)
{
return false;
}
- SetVolume(volume);
+ PlaySong(loops);
- fprintf(stderr, "%s\n", __FUNCTION__);
return true;
}
-//
-// MidiPipe_PauseSong
-//
-// Pause the song.
-//
-boolean MidiPipe_PauseSong()
+boolean MidiPipe_StopSong(buffer_reader_t *reader)
{
- PauseSong();
+ StopSong();
- fprintf(stderr, "%s\n", __FUNCTION__);
return true;
}
-//
-// MidiPipe_ResumeSong
-//
-// Resume after pausing.
-//
-boolean MidiPipe_ResumeSong()
-{
- ResumeSong();
-
- fprintf(stderr, "%s\n", __FUNCTION__);
- return true;
-}
-
-//
-// MidiPipe_StopServer
-//
-// Stops the RPC server so the program can shutdown.
-//
-boolean MidiPipe_StopServer()
-{
- // Local shutdown tasks
- ShutdownSDL();
- free(filename);
- filename = NULL;
-
- fprintf(stderr, "%s\n", __FUNCTION__);
- return true;
-}
-
//=============================================================================
//
// Server Implementation
//
+//
+// Parses a command and directs to the proper read function.
+//
boolean ParseCommand(buffer_reader_t *reader, uint16_t command)
{
switch (command)
{
- case NET_MIDIPIPE_PACKET_TYPE_PREPARE_NEW_SONG:
- return MidiPipe_PrepareNewSong();
- case NET_MIDIPIPE_PACKET_TYPE_SET_FILENAME:
- return MidiPipe_SetFilename(reader);
+ case NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG:
+ return MidiPipe_RegisterSong(reader);
+ case NET_MIDIPIPE_PACKET_TYPE_SET_VOLUME:
+ return MidiPipe_SetVolume(reader);
case NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG:
return MidiPipe_PlaySong(reader);
case NET_MIDIPIPE_PACKET_TYPE_STOP_SONG:
- return MidiPipe_StopSong();
- case NET_MIDIPIPE_PACKET_TYPE_CHANGE_VOLUME:
- return MidiPipe_ChangeVolume(reader);
- case NET_MIDIPIPE_PACKET_TYPE_PAUSE_SONG:
- return MidiPipe_PauseSong();
- case NET_MIDIPIPE_PACKET_TYPE_RESUME_SONG:
- return MidiPipe_ResumeSong();
- case NET_MIDIPIPE_PACKET_TYPE_STOP_SERVER:
- return MidiPipe_StopServer();
+ return MidiPipe_StopSong(reader);
default:
return false;
}
@@ -365,7 +227,6 @@
boolean ok = false;
buffer_t *buffer = NewBuffer();
- fprintf(stderr, "%s\n", "In theory we should be reading...");
for (;;)
{
// Wait until we see some data on the pipe.
@@ -382,7 +243,6 @@
}
// Read data off the pipe and add it to the buffer.
- fprintf(stderr, "%s\n", "ReadFile");
wok = ReadFile(midi_process_in, pipe_buffer, sizeof(pipe_buffer),
&pipe_buffer_read, NULL);
if (!wok)
@@ -390,7 +250,6 @@
return false;
}
- fprintf(stderr, "%s\n", "Buffer_Push");
ok = Buffer_Push(buffer, pipe_buffer, pipe_buffer_read);
if (!ok)
{
@@ -397,7 +256,6 @@
return false;
}
- fprintf(stderr, "%s\n", "ParseMessage");
do
{
// Read messages off the buffer until we can't anymore.
--- a/src/i_midipipe.c
+++ b/src/i_midipipe.c
@@ -20,11 +20,11 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-#include <SDL_net.h>
#include "i_midipipe.h"
#include "config.h"
+#include "i_timer.h"
#include "m_misc.h"
#include "net_packet.h"
@@ -39,6 +39,8 @@
// Data
//
+#define MIDIPIPE_MAX_WAIT 500 // Max amount of ms to wait for expected data.
+
static HANDLE midi_process_in_reader; // Input stream for midi process.
static HANDLE midi_process_in_writer;
static HANDLE midi_process_out_reader; // Output stream for midi process.
@@ -49,220 +51,203 @@
//=============================================================================
//
-// RPC Wrappers
+// Private functions
//
//
-// CHECK_RPC_STATUS
+// WritePipe
//
-// If either server or client initialization failed, we don't try to make any
-// RPC calls.
+// Writes packet data to the subprocess' standard in.
//
-#define CHECK_RPC_STATUS() \
- if(!server_init) \
- return false
-
-#define MIDIRPC_MAXTRIES 50 // This number * 10 is the amount of time you can try to wait for.
-
-static boolean I_MidiPipeWrite(void *data, int len)
+static boolean WritePipe(net_packet_t *packet)
{
- DWORD written;
- if (WriteFile(midi_process_in_writer, data, len, &written, NULL))
+ BOOL ok = WriteFile(midi_process_in_writer, packet->data, packet->len,
+ NULL, NULL);
+
+ if (!ok)
{
- return true;
- }
- else
- {
return false;
}
-}
-static boolean I_MidiPipeWaitForServer()
-{
- int tries = 0;
- while(false) // TODO: Is there some way to tell if the server is listening?
- {
- I_Sleep(10);
- if (++tries >= MIDIRPC_MAXTRIES)
- {
- return false;
- }
- }
return true;
}
//
-// I_MidiPipeRegisterSong
+// ExpectPipe
//
-// Prepare the RPC MIDI engine to receive new song data, and transmit the song
-// filename to the server process.
+// Expect the contents of a packet off of the subprocess' stdout. If the
+// response is unexpected, or doesn't arrive within a specific amuont of time,
+// assume the subprocess is in an unknown state.
//
-boolean I_MidiPipeRegisterSong(const char *filename)
+static boolean ExpectPipe(net_packet_t *packet)
{
- BOOL wok;
- net_packet_t *packet;
+ BOOL ok;
+ CHAR pipe_buffer[8192];
+ DWORD pipe_buffer_read = 0;
- CHECK_RPC_STATUS();
-
- packet = NET_NewPacket(64);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_PREPARE_NEW_SONG);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_SET_FILENAME);
- NET_WriteString(packet, filename);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
- NET_FreePacket(packet);
-
- if (!wok)
+ if (packet->len > sizeof(pipe_buffer))
{
- DEBUGOUT("I_MidiPipeRegisterSong failed");
+ // The size of the packet we're expecting is larger than our buffer
+ // size, so bail out now.
return false;
}
- DEBUGOUT("I_MidiPipeRegisterSong succeeded");
- return true;
+ int start = I_GetTimeMS();
+
+ do
+ {
+ // Wait until we see exactly the amount of data we expect on the pipe.
+ ok = PeekNamedPipe(midi_process_out_reader, NULL, 0, NULL,
+ &pipe_buffer_read, NULL);
+ if (!ok)
+ {
+ goto fail;
+ }
+ else if (pipe_buffer_read < packet->len)
+ {
+ I_Sleep(1);
+ continue;
+ }
+
+ // Read precisely the number of bytes we're expecting, and no more.
+ ok = ReadFile(midi_process_out_reader, pipe_buffer, packet->len,
+ &pipe_buffer_read, NULL);
+ if (!ok || pipe_buffer_read != packet->len)
+ {
+ goto fail;
+ }
+
+ // Compare our data buffer to the packet.
+ if (memcmp(packet->data, pipe_buffer, packet->len) != 0)
+ {
+ goto fail;
+ }
+
+ return true;
+
+ // Continue looping as long as we don't exceed our maximum wait time.
+ } while (start + MIDIPIPE_MAX_WAIT > I_GetTimeMS());
+fail:
+
+ // TODO: Deal with the wedged process.
+ return false;
}
+//=============================================================================
//
-// I_MidiPipePlaySong
+// Protocol Commands
//
-// Tell the RPC server to start playing a song.
+
//
-boolean I_MidiPipePlaySong(boolean looping)
+// I_MidiPipe_RegisterSong
+//
+// Tells the MIDI subprocess to load a specific filename for playing. This
+// function blocks until there is an acknowledgement from the server.
+//
+Mix_Music *I_MidiPipe_RegisterSong(const char *filename)
{
- BOOL wok;
+ boolean ok;
net_packet_t *packet;
- CHECK_RPC_STATUS();
-
- packet = NET_NewPacket(3);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG);
- NET_WriteInt8(packet, looping);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
+ packet = NET_NewPacket(64);
+ NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG);
+ NET_WriteString(packet, filename);
+ ok = WritePipe(packet);
NET_FreePacket(packet);
- if (!wok)
+ if (!ok)
{
- DEBUGOUT("I_MidiPipePlaySong failed");
+ DEBUGOUT("I_MidiPipe_RegisterSong failed");
return false;
}
- DEBUGOUT("I_MidiPipePlaySong succeeded");
- return true;
-}
-
-//
-// I_MidiPipeStopSong
-//
-// Tell the RPC server to stop any currently playing song.
-//
-boolean I_MidiPipeStopSong()
-{
- BOOL wok;
- net_packet_t *packet;
-
- CHECK_RPC_STATUS();
-
packet = NET_NewPacket(2);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_STOP_SONG);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
+ NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG_ACK);
+ ok = ExpectPipe(packet);
NET_FreePacket(packet);
- if (!wok)
+ if (!ok)
{
- DEBUGOUT("I_MidiPipeStopSong failed");
+ DEBUGOUT("I_MidiPipe_RegisterSong ack failed");
return false;
}
- DEBUGOUT("I_MidiPipeStopSong succeeded");
+ DEBUGOUT("I_MidiPipe_RegisterSong succeeded");
return true;
}
//
-// I_MidiPipeSetVolume
+// I_MidiPipe_SetVolume
//
-// Change the volume level of music played by the RPC midi server.
+// Tells the MIDI subprocess to set a specific volume for the song.
//
-boolean I_MidiPipeSetVolume(int volume)
+void I_MidiPipe_SetVolume(int vol)
{
- BOOL wok;
+ boolean ok;
net_packet_t *packet;
- CHECK_RPC_STATUS();
-
packet = NET_NewPacket(6);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_CHANGE_VOLUME);
- NET_WriteInt32(packet, volume);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
+ NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_SET_VOLUME);
+ NET_WriteInt32(packet, vol);
+ ok = WritePipe(packet);
NET_FreePacket(packet);
- if (!wok)
+ if (!ok)
{
- DEBUGOUT("I_MidiPipeSetVolume failed");
- return false;
+ DEBUGOUT("I_MidiPipe_SetVolume failed");
+ return;
}
- DEBUGOUT("I_MidiPipeSetVolume succeeded");
- return true;
+ DEBUGOUT("I_MidiPipe_SetVolume succeeded");
}
//
-// I_MidiPipePauseSong
+// I_MidiPipe_PlaySong
//
-// Pause the music being played by the server. In actuality, due to SDL_mixer
-// limitations, this just temporarily sets the volume to zero.
+// Tells the MIDI subprocess to play the currently loaded song.
//
-boolean I_MidiPipePauseSong()
+void I_MidiPipe_PlaySong(int loops)
{
- BOOL wok;
+ boolean ok;
net_packet_t *packet;
- CHECK_RPC_STATUS();
-
- packet = NET_NewPacket(2);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_PAUSE_SONG);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
+ packet = NET_NewPacket(6);
+ NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG);
+ NET_WriteInt32(packet, loops);
+ ok = WritePipe(packet);
NET_FreePacket(packet);
- if (!wok)
+ if (!ok)
{
- DEBUGOUT("I_MidiPipePauseSong failed");
- return false;
+ DEBUGOUT("I_MidiPipe_PlaySong failed");
+ return;
}
- DEBUGOUT("I_MidiPipePauseSong succeeded");
- return true;
+ DEBUGOUT("I_MidiPipe_PlaySong succeeded");
}
//
-// I_MidiPipeResumeSong
+// I_MidiPipe_StopSong
//
-// Resume a song after having paused it.
+// Tells the MIDI subprocess to stop playing the currently loaded song.
//
-boolean I_MidiPipeResumeSong()
+void I_MidiPipe_StopSong()
{
- BOOL wok;
+ boolean ok;
net_packet_t *packet;
- CHECK_RPC_STATUS();
-
packet = NET_NewPacket(2);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_RESUME_SONG);
- wok = WriteFile(midi_process_in_writer, packet->data, packet->len,
- NULL, NULL);
+ NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_STOP_SONG);
+ ok = WritePipe(packet);
NET_FreePacket(packet);
- if (!wok)
+ if (!ok)
{
- DEBUGOUT("I_MidiPipeResumeSong failed");
- return false;
+ DEBUGOUT("I_MidiPipe_StopSong failed");
+ return;
}
- DEBUGOUT("I_MidiPipeResumeSong succeeded");
- return true;
+ DEBUGOUT("I_MidiPipe_StopSong succeeded");
}
//=============================================================================
@@ -275,7 +260,7 @@
//
// Start up the MIDI server.
//
-boolean I_MidiPipeInitServer()
+boolean I_MidiPipe_InitServer()
{
struct stat sbuf;
char filename[MAX_PATH+1];
@@ -359,61 +344,6 @@
}
return ok;
-}
-
-//
-// I_MidiPipeInitClient
-//
-// Ensure that we can actually communicate with the subprocess.
-//
-boolean I_MidiPipeInitClient()
-{
- client_init = true;
- return true;
-}
-
-//
-// I_MidiPipeClientShutDown
-//
-// Shutdown the RPC Client
-//
-/* void I_MidiPipeClientShutDown()
-{
- // stop the server
- if(server_init)
- {
- net_packet_t *packet;
- packet = NET_NewPacket(2);
- NET_WriteInt16(packet, NET_MIDIPIPE_PACKET_TYPE_STOP_SERVER);
- int len = SDLNet_TCP_Send(midi_socket, packet->data, packet->len);
- NET_FreePacket(packet);
- if (len < packet->len)
- {
- DEBUGOUT("Problem encountered when stopping RPC server");
- }
-
- server_init = false;
- }
-
- if (midi_socket)
- {
- SDLNet_TCP_Close(midi_socket);
- midi_socket = NULL;
- }
-
- client_init = false;
-} */
-
-//
-// I_MidiPipeReady
-//
-// Returns true if both server and client initialized successfully.
-//
-boolean I_MidiPipeReady()
-{
- CHECK_RPC_STATUS();
-
- return true;
}
#endif
--- a/src/i_midipipe.h
+++ b/src/i_midipipe.h
@@ -21,19 +21,16 @@
#if _WIN32
+#include "SDL_mixer.h"
+
#include "doomtype.h"
-boolean I_MidiPipeInitServer();
-boolean I_MidiPipeInitClient();
-void I_MidiPipeClientShutDown();
-boolean I_MidiPipeReady();
+Mix_Music *I_MidiPipe_RegisterSong(const char *filename);
+void I_MidiPipe_SetVolume(int vol);
+void I_MidiPipe_PlaySong(int loops);
+void I_MidiPipe_StopSong();
-boolean I_MidiPipeRegisterSong(const char *filename);
-boolean I_MidiPipePlaySong(boolean looping);
-boolean I_MidiPipeStopSong();
-boolean I_MidiPipeSetVolume(int volume);
-boolean I_MidiPipePauseSong();
-boolean I_MidiPipeResumeSong();
+boolean I_MidiPipe_InitServer();
#endif
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -975,7 +975,7 @@
}
#if WIN32
- I_MidiPipeInitServer();
+ I_MidiPipe_InitServer();
#endif
return music_initialized;
@@ -1000,7 +1000,7 @@
}
#if WIN32
- I_MidiPipeSetVolume(vol);
+ I_MidiPipe_SetVolume(vol);
#else
Mix_VolumeMusic(vol);
#endif
@@ -1055,7 +1055,7 @@
}
#if _WIN32
- I_MidiPipePlaySong(loops);
+ I_MidiPipe_PlaySong(loops);
#else
Mix_PlayMusic(current_track_music, loops);
#endif
@@ -1093,7 +1093,7 @@
}
#if _WIN32
- I_MidiPipeStopSong();
+ I_MidiPipe_StopSong();
#else
Mix_HaltMusic();
#endif
@@ -1116,7 +1116,9 @@
return;
}
+#ifndef _WIN32
Mix_FreeMusic(music);
+#endif
}
// Determine whether memory block is a .mid file
@@ -1209,7 +1211,7 @@
// we have to generate a temporary file.
#ifdef _WIN32
- music = (Mix_Music*)I_MidiPipeRegisterSong(filename);
+ music = I_MidiPipe_RegisterSong(filename);
#else
music = Mix_LoadMUS(filename);
#endif
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -143,14 +143,11 @@
} net_master_packet_type_t;
typedef enum {
- NET_MIDIPIPE_PACKET_TYPE_PREPARE_NEW_SONG,
- NET_MIDIPIPE_PACKET_TYPE_SET_FILENAME,
+ NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG,
+ NET_MIDIPIPE_PACKET_TYPE_REGISTER_SONG_ACK,
+ NET_MIDIPIPE_PACKET_TYPE_SET_VOLUME,
NET_MIDIPIPE_PACKET_TYPE_PLAY_SONG,
NET_MIDIPIPE_PACKET_TYPE_STOP_SONG,
- NET_MIDIPIPE_PACKET_TYPE_CHANGE_VOLUME,
- NET_MIDIPIPE_PACKET_TYPE_PAUSE_SONG,
- NET_MIDIPIPE_PACKET_TYPE_RESUME_SONG,
- NET_MIDIPIPE_PACKET_TYPE_STOP_SERVER
} net_midipipe_packet_type_t;
// Settings specified when the client connects to the server.