CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
18 RemoteIO::RemoteIO() {
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());
29 _inputBuffer.allocateBuffers();
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
52 RemoteIO::~RemoteIO() {
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
181 void RemoteIO::process_request_packet() {
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._monoBuffers[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