CSL  6.0
RemoteIO.cpp
Go to the documentation of this file.
1 //
2 // RemoteIO.cpp -- CSL I/O Port for sending sample buffers out over sockets
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5 
6 #include "RemoteIO.h"
7 
8 using namespace csl;
9 
10 // Constructor
11 
12 RemoteIO::RemoteIO(unsigned chans) {
13  init_io(0, chans);
14 }
15 
16 // Default is stereo
17 
19  init_io(0, 2);
20 }
21 
22 // Initialization function
23 
24 void RemoteIO::init_io(unsigned in, unsigned out) {
25  _inputs = in;
26  _outputs = out;
27  _outputBuffer.set_size(_outputs, CGestalt::max_buffer_frames()); // dummy buffer
28  _inputBuffer.set_size(_outputs, CGestalt::max_buffer_frames());
30  _inputBuffer.zero_buffers();
31  _inSock = 0;
32  _outSock = 0;
33  unsigned _bufferSize = CGestalt::max_buffer_frames();
34  unsigned _numChannels = _outputs; // needed by RFS macro below
35 
36  // Allocate my local sample buffer
37  _buffer = (sample *) malloc(RFS_RESPONSE_PACKET_SIZE);
38  if (_buffer <= 0)
39  logMsg(kLogError, "Cannot allocate RFS output buffers.");
40 #ifdef CSL_WINDOWS
41  WSADATA localWSA;
42  if (WSAStartup(MAKEWORD(1,1),&localWSA)!= 0)
43  perror("Couldn't do WSAStartup");
44 #endif
45 #ifdef DO_TIMING
46  thisSec = timeVals = timeSum = 0;
47 #endif
48 }
49 
50 // Destructor
51 
53  if (_buffer != 0)
54  free(_buffer);
55 }
56 
57 // Open up the port
58 
59 status RemoteIO::open() {
60  return(this->open(CSL_DEFAULT_REQUEST_PORT));
61 }
62 
63 // Really open and create the server read (input) socket
64 
65 status RemoteIO::open(unsigned port) {
66  struct sockaddr_in serv_addr;
67  // Create TCP-IP socket
68  if((_inSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
69  perror("RemoteIO open_client: bad _inSock");
70  return cslErr;
71  }
72  logMsg("Open RemoteIO server read socket on port %d = %d", port, _inSock);
73  memset((char *)&serv_addr, 0, sizeof(serv_addr));
74  serv_addr.sin_family = AF_INET;
75  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
76  serv_addr.sin_port = htons(port);
77  // Bind the socket to my address
78  if(bind(_inSock, (struct sockaddr *) &serv_addr, sizeof(struct sockaddr)) < 0) {
79  perror("RemoteIO open_client: unable to bind");
80  return cslErr;
81  }
82  return cslOk;
83 }
84 
85 // Close the port (doesn't work because I can't call the stdlib close...)
86 
87 status RemoteIO::close() {
88  if (_inSock)
89  if (closesocket(_inSock) < 0)
90  perror("Close _inSock");
91  if (_outSock)
92  if (closesocket(_outSock) < 0)
93  perror("Close _outSock");
94  return cslOk;
95 }
96 
97 // Start playing -- this is the main loop and forks the reader thread
98 
99 status RemoteIO::start() {
100  socklen_t addrLen = sizeof(struct sockaddr_in);
101 
102 // logMsg("RemoteIO server listening to socket");
103  if (listen(_inSock, 2) < 0) {
104  perror("\tTCP_RemoteIO listen");
105  return cslErr;
106  }
107 // logMsg("RemoteIO server accepting socket connection");
108  if ((_outSock = accept(_inSock, (struct sockaddr *) & _clientAddr, & addrLen)) < 0) {
109  perror("\tTCP_RemoteIO accept");
110  return cslErr;
111  }
112  logMsg("RemoteIO server accepted client socket connection");
113  // now fork the IO thread
114  CSL_CreateThread(RemoteIO_read_loop, (void *) this);
115  return cslOk;
116 };
117 
118 // This is the macro to cast the pointer to a RemoteIO instance reference.
119 
120 #define THE_IO ((RemoteIO *) my_inst)
121 
122 // This is the forked thread for the RemoteIO read loop.
123 // Note that this is "extern" because I fork it off as a separate thread; thus, it has to refer to
124 // the RemoteIO instance via the void * pointer passed in the thread creation call.
125 
126 extern "C" void * RemoteIO_read_loop(void * my_inst) {
127  ssize_t xfer_len;
128  unsigned command, magic = RFS_PACKET_MAGIC;
129  int sock = THE_IO->get_out_sock();
130  sample * _buffer = THE_IO->get_buffer();
131  unsigned char * b_str = (unsigned char *) _buffer;
132  CSL_RFS_MSG * pkt_header = (CSL_RFS_MSG *) b_str;
133 
134  logMsg("Starting RemoteIO socket read loop (%d)", sock);
135  while(TRUE) { // Endless loop
136  // printf("\tRemoteIO reading from %d\n", _inSock);
137  xfer_len = read(sock, (char *) _buffer, RFS_PACKET_SIZE);
138  if (xfer_len < 0) {
139  perror("RemoteIO loop read");
140  goto next_loop;
141  }
142  // logMsg("\tgot %d bytes = %x (%d) %d %d", xfer_len, pkt_header->magic,
143  // (pkt_header->magic & 0x00ff), pkt_header->frames, pkt_header->channels);
144  command = pkt_header->magic;
145  if ((command & 0xffffff00) != magic) { // Check header fields, ignore packet on any error
146  logMsg(kLogError, "RemoteIO: bad request magic number: %x", command);
147  goto next_loop;
148  }
149  command = command & 0x000000ff; // Get the low-order byte (the actual command)
150  switch (command) { // Command packet processing switch
151  case CSL_CMD_SET_CLIENT: // Read the operands of the set client command
152  if (xfer_len != RFS_PACKET_SIZE) {
153  logMsg(kLogError, "RemoteIO: wrong size in client ID packet\n");
154  break;
155  }
156  logMsg("RemoteIO set_client");
157  // Echo the request packet back to the client
158  xfer_len = write(sock, (char *) _buffer, RFS_PACKET_SIZE);
159  if (xfer_len < 0)
160  perror("RemoteIO set_client write");
161  break;
162  case CSL_CMD_NEXT_BUFFER: // Process a buffer request packet
163  THE_IO->process_request_packet();
164  break;
165  case CSL_CMD_STOP: // Stop the server
166  THE_IO->stop();
167  THE_IO->close();
168  exit(1);
169  default: // Default = ??
170  logMsg(kLogError, "RemoteIO: Illegal command: %d", command);
171  break;
172  }
173 next_loop:
174  continue;
175  }
176  return NULL; // Never reached
177 }
178 
179 // This is the method to generate a sample buffer and send it back to the client
180 
182  unsigned packet_size = 0;
183  unsigned magic = RFS_PACKET_MAGIC;
184  unsigned char * sbuf = (unsigned char *) _buffer;
185  CSL_RFS_MSG * pkt_header = (CSL_RFS_MSG *) sbuf;
186  unsigned frames = pkt_header->frames;
187  ssize_t bytes_wrote;
188 
189  if ((frames < 32) || (frames > CGestalt::max_buffer_frames())) {
190  logMsg(kLogError, "\tRemoteIO bad request frame count: %d", frames);
191  return;
192  }
193  if (pkt_header->channels != _outputs) {
194  logMsg(kLogError, "\tRemoteIO: bad request channel count: %d (%d)",
195  pkt_header->channels, _outputs);
196  return;
197  } // Set up pointer for response samples
198  // Send result buffer back to Remote client
199  packet_size = RFS_PACKET_SIZE + (frames * _outputs * sizeof(sample));
200  memcpy(&sbuf[packet_size], &magic, 4);
201  packet_size += 4;
202 // printf("RemoteIO sending client %d sample bytes\n\t", packet_size);
203  // write away!
204  bytes_wrote = write(_outSock, (char *) sbuf, packet_size);
205  if (bytes_wrote < 0)
206  perror("sendto");
207  // now execute the graph for the next buffer
208  if (_graph != 0) {
209  memset(((void *) & sbuf[RFS_PACKET_SIZE]), 0, (frames * _outputs * sizeof(sample)));
210  _outputBuffer._numFrames = frames;
211  _inputBuffer._numFrames = frames; // this is empty for now
212  for (unsigned i = 0; i < _outputs; i++) // set output buffer sample pointers
213  _outputBuffer._buffers[i] = (sample *) & sbuf[RFS_PACKET_SIZE
214  + (i * frames * sizeof(sample))];
215 #ifdef DO_TIMING
216  GET_TIME(&then);
217 #endif
218  // Call the client's next_buffer function to do the work!
219  _graph->next_buffer(_inputBuffer, _outputBuffer);
220 
221 #ifdef DO_TIMING
222  GET_TIME(&now);
223  this->print_time_statistics(&now, &then, &thisSec, &timeSum, &timeVals);
224 #endif
225  }
226 }
227 
228 // Stop playing
229 
230 status RemoteIO::stop() {
231  _outSock = 0;
232  return cslOk;
233 }
234 
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
#define CSL_DEFAULT_REQUEST_PORT
Definition: RemoteStream.h:74
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
status stop()
Definition: RemoteIO.cpp:230
#define THE_IO
Definition: RemoteIO.cpp:120
void process_request_packet()
Definition: RemoteIO.cpp:181
unsigned _outputs
Definition: RemoteIO.h:31
void * RemoteIO_read_loop(void *inst)
Definition: RemoteIO.cpp:126
#define GET_TIME(val)
Definition: CSL_Core.h:700
status open()
Definition: RemoteIO.cpp:59
Buffer _outputBuffer
Definition: RemoteIO.h:32
sample * _buffer
Definition: RemoteIO.h:39
#define CSL_CMD_STOP
Definition: RemoteStream.h:85
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
#define closesocket(x)
Definition: RemoteStream.h:51
#define TRUE
Definition: CSL_Types.h:328
int _outSock
Definition: RemoteIO.h:37
Buffer _inputBuffer
Definition: RemoteIO.h:33
int CSL_CreateThread(THREAD_START_ROUTINE pfnThreadProc, void *pvParam)
void init_io(unsigned in, unsigned out)
Definition: RemoteIO.cpp:24
virtual status start()
Definition: RemoteIO.cpp:99
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
#define CSL_CMD_NEXT_BUFFER
Definition: RemoteStream.h:81
#define CSL_CMD_SET_CLIENT
Definition: RemoteStream.h:80
unsigned _inputs
Definition: RemoteIO.h:31
status close()
open/close start/stop methods
Definition: RemoteIO.cpp:87