/[svn]/liblscp/trunk/src/client.c
ViewVC logotype

Contents of /liblscp/trunk/src/client.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 125 - (show annotations) (download)
Mon Jun 14 21:04:04 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 40589 byte(s)
* Added support for the new LIST commands (draft v.08).

1 // client.c
2 //
3 /****************************************************************************
4 liblscp - LinuxSampler Control Protocol API
5 Copyright (C) 2004, rncbc aka Rui Nuno Capela. All rights reserved.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21 *****************************************************************************/
22
23 #include "common.h"
24
25 // Default timeout value (in milliseconds).
26 #define LSCP_TIMEOUT_MSECS 500
27
28
29 // Local prototypes.
30
31 static void _lscp_client_set_result (lscp_client_t *pClient, char *pszResult, int iErrno);
32 static void _lscp_client_udp_proc (void *pvClient);
33
34
35 //-------------------------------------------------------------------------
36 // Helper functions.
37
38 // Result buffer internal settler.
39 static void _lscp_client_set_result ( lscp_client_t *pClient, char *pszResult, int iErrno )
40 {
41 if (pClient->pszResult)
42 free(pClient->pszResult);
43 pClient->pszResult = NULL;
44
45 pClient->iErrno = iErrno;
46
47 if (pszResult)
48 pClient->pszResult = strdup(lscp_ltrim(pszResult));
49 }
50
51
52 //-------------------------------------------------------------------------
53 // UDP service (datagram oriented).
54
55 static void _lscp_client_udp_proc ( void *pvClient )
56 {
57 lscp_client_t *pClient = (lscp_client_t *) pvClient;
58 struct sockaddr_in addr;
59 int cAddr;
60 char achBuffer[LSCP_BUFSIZ];
61 int cchBuffer;
62 const char *pszSeps = " \r\n";
63 char *pszToken;
64 char *pch;
65
66 #ifdef DEBUG
67 fprintf(stderr, "_lscp_client_udp_proc: Client waiting for events.\n");
68 #endif
69
70 while (pClient->udp.iState) {
71 cAddr = sizeof(struct sockaddr_in);
72 cchBuffer = recvfrom(pClient->udp.sock, achBuffer, sizeof(achBuffer), 0, (struct sockaddr *) &addr, &cAddr);
73 if (cchBuffer > 0) {
74 #ifdef DEBUG
75 lscp_socket_trace("_lscp_client_udp_proc: recvfrom", &addr, achBuffer, cchBuffer);
76 #endif
77 if (strncasecmp(achBuffer, "PING ", 5) == 0) {
78 // Make sure received buffer it's null terminated.
79 achBuffer[cchBuffer] = (char) 0;
80 lscp_strtok(achBuffer, pszSeps, &(pch)); // Skip "PING"
81 lscp_strtok(NULL, pszSeps, &(pch)); // Skip port (must be the same as in addr)
82 pszToken = lscp_strtok(NULL, pszSeps, &(pch)); // Have session-id.
83 if (pszToken) {
84 // Set now client's session-id, if not already
85 if (pClient->sessid == NULL)
86 pClient->sessid = strdup(pszToken);
87 if (pClient->sessid && strcmp(pszToken, pClient->sessid) == 0) {
88 sprintf(achBuffer, "PONG %s\r\n", pClient->sessid);
89 cchBuffer = strlen(achBuffer);
90 if (sendto(pClient->udp.sock, achBuffer, cchBuffer, 0, (struct sockaddr *) &addr, cAddr) < cchBuffer)
91 lscp_socket_perror("_lscp_client_udp_proc: sendto");
92 #ifdef DEBUG
93 fprintf(stderr, "> %s", achBuffer);
94 #endif
95 }
96 }
97 // Done with life proof.
98 } else {
99 //
100 if ((*pClient->pfnCallback)(
101 pClient,
102 achBuffer,
103 cchBuffer,
104 pClient->pvData) != LSCP_OK) {
105 pClient->udp.iState = 0;
106 }
107 }
108 } else {
109 lscp_socket_perror("_lscp_client_udp_proc: recvfrom");
110 pClient->udp.iState = 0;
111 }
112 }
113
114 #ifdef DEBUG
115 fprintf(stderr, "_lscp_client_udp_proc: Client closing.\n");
116 #endif
117 }
118
119
120 //-------------------------------------------------------------------------
121 // Client versioning teller fuunction.
122
123
124 /** Retrieve the current client library version string. */
125 const char* lscp_client_package (void) { return LSCP_PACKAGE; }
126
127 /** Retrieve the current client library version string. */
128 const char* lscp_client_version (void) { return LSCP_VERSION; }
129
130 /** Retrieve the current client library build timestamp string. */
131 const char* lscp_client_build (void) { return __DATE__ " " __TIME__; }
132
133
134 //-------------------------------------------------------------------------
135 // Client socket functions.
136
137 /**
138 * Create a client instance, estabilishing a connection to a server hostname,
139 * which must be listening on the given port. A client callback function is
140 * also supplied for server notification event handling.
141 *
142 * @param pszHost Hostname of the linuxsampler listening server.
143 * @param iPort Port number of the linuxsampler listening server.
144 * @param pfnCallback Callback function to receive event notifications.
145 * @param pvData User context opaque data, that will be passed
146 * to the callback function.
147 *
148 * @returns The new client instance pointer if successfull, which shall be
149 * used on all subsequent client calls, NULL otherwise.
150 */
151 lscp_client_t* lscp_client_create ( const char *pszHost, int iPort, lscp_client_proc_t pfnCallback, void *pvData )
152 {
153 lscp_client_t *pClient;
154 struct hostent *pHost;
155 lscp_socket_t sock;
156 struct sockaddr_in addr;
157 int cAddr;
158 int iSockOpt = (-1);
159
160 if (pfnCallback == NULL) {
161 fprintf(stderr, "lscp_client_create: Invalid client callback function.\n");
162 return NULL;
163 }
164
165 pHost = gethostbyname(pszHost);
166 if (pHost == NULL) {
167 lscp_socket_herror("lscp_client_create: gethostbyname");
168 return NULL;
169 }
170
171 // Allocate client descriptor...
172
173 pClient = (lscp_client_t *) malloc(sizeof(lscp_client_t));
174 if (pClient == NULL) {
175 fprintf(stderr, "lscp_client_create: Out of memory.\n");
176 return NULL;
177 }
178 memset(pClient, 0, sizeof(lscp_client_t));
179
180 pClient->pfnCallback = pfnCallback;
181 pClient->pvData = pvData;
182
183 #ifdef DEBUG
184 fprintf(stderr, "lscp_client_create: pClient=%p: pszHost=%s iPort=%d.\n", pClient, pszHost, iPort);
185 #endif
186
187 // Prepare the TCP connection socket...
188
189 sock = socket(AF_INET, SOCK_STREAM, 0);
190 if (sock == INVALID_SOCKET) {
191 lscp_socket_perror("lscp_client_create: tcp: socket");
192 free(pClient);
193 return NULL;
194 }
195
196 #if defined(WIN32)
197 if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
198 lscp_socket_perror("lscp_client_create: tcp: setsockopt(SO_DONTLINGER)");
199 #endif
200
201 #ifdef DEBUG
202 lscp_socket_getopts("lscp_client_create: tcp", sock);
203 #endif
204
205 cAddr = sizeof(struct sockaddr_in);
206 memset((char *) &addr, 0, cAddr);
207 addr.sin_family = pHost->h_addrtype;
208 memmove((char *) &(addr.sin_addr), pHost->h_addr, pHost->h_length);
209 addr.sin_port = htons((short) iPort);
210
211 if (connect(sock, (struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
212 lscp_socket_perror("lscp_client_create: tcp: connect");
213 closesocket(sock);
214 free(pClient);
215 return NULL;
216 }
217
218 lscp_socket_agent_init(&(pClient->tcp), sock, &addr, cAddr);
219
220 #ifdef DEBUG
221 fprintf(stderr, "lscp_client_create: tcp: pClient=%p: sock=%d addr=%s port=%d.\n", pClient, pClient->tcp.sock, inet_ntoa(pClient->tcp.addr.sin_addr), ntohs(pClient->tcp.addr.sin_port));
222 #endif
223
224 // Prepare the UDP datagram service socket...
225
226 sock = socket(AF_INET, SOCK_DGRAM, 0);
227 if (sock == INVALID_SOCKET) {
228 lscp_socket_perror("lscp_client_create: udp: socket");
229 lscp_socket_agent_free(&(pClient->tcp));
230 free(pClient);
231 return NULL;
232 }
233
234 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
235 lscp_socket_perror("lscp_client_create: udp: setsockopt(SO_REUSEADDR)");
236
237 #ifdef DEBUG
238 lscp_socket_getopts("lscp_client_create: udp", sock);
239 #endif
240
241 cAddr = sizeof(struct sockaddr_in);
242 memset((char *) &addr, 0, cAddr);
243 addr.sin_family = AF_INET;
244 addr.sin_addr.s_addr = htonl(INADDR_ANY);
245 addr.sin_port = htons(0);
246
247 if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
248 lscp_socket_perror("lscp_client_create: udp: bind");
249 lscp_socket_agent_free(&(pClient->tcp));
250 closesocket(sock);
251 free(pClient);
252 return NULL;
253 }
254
255 if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
256 lscp_socket_perror("lscp_client_create: udp: getsockname");
257 lscp_socket_agent_free(&(pClient->tcp));
258 closesocket(sock);
259 free(pClient);
260 return NULL;
261 }
262
263 lscp_socket_agent_init(&(pClient->udp), sock, &addr, cAddr);
264
265 #ifdef DEBUG
266 fprintf(stderr, "lscp_client_create: udp: pClient=%p: sock=%d addr=%s port=%d.\n", pClient, pClient->udp.sock, inet_ntoa(pClient->udp.addr.sin_addr), ntohs(pClient->udp.addr.sin_port));
267 #endif
268
269 // No session id, yet.
270 pClient->sessid = NULL;
271 // Initialize cached members.
272 pClient->audio_drivers = NULL;
273 pClient->midi_drivers = NULL;
274 pClient->audio_devices = NULL;
275 pClient->midi_devices = NULL;
276 pClient->engines = NULL;
277 pClient->channels = NULL;
278 lscp_driver_info_init(&(pClient->audio_info));
279 lscp_driver_info_init(&(pClient->midi_info));
280 lscp_engine_info_init(&(pClient->engine_info));
281 lscp_channel_info_init(&(pClient->channel_info));
282 // Initialize error stuff.
283 pClient->pszResult = NULL;
284 pClient->iErrno = -1;
285 // Stream usage stuff.
286 pClient->buffer_fill = NULL;
287 pClient->iStreamCount = 0;
288 // Default timeout value.
289 pClient->iTimeout = LSCP_TIMEOUT_MSECS;
290
291 // Initialize the transaction mutex.
292 lscp_mutex_init(pClient->mutex);
293
294 // Now's finally time to startup threads...
295 // UDP service thread...
296 if (lscp_socket_agent_start(&(pClient->udp), _lscp_client_udp_proc, pClient, 0) != LSCP_OK) {
297 lscp_socket_agent_free(&(pClient->tcp));
298 lscp_socket_agent_free(&(pClient->udp));
299 lscp_mutex_destroy(pClient->mutex);
300 free(pClient);
301 return NULL;
302 }
303
304 // Finally we've some success...
305 return pClient;
306 }
307
308
309 /**
310 * Wait for a client instance to terminate graciously.
311 *
312 * @param pClient Pointer to client instance structure.
313 */
314 lscp_status_t lscp_client_join ( lscp_client_t *pClient )
315 {
316 if (pClient == NULL)
317 return LSCP_FAILED;
318
319 #ifdef DEBUG
320 fprintf(stderr, "lscp_client_join: pClient=%p.\n", pClient);
321 #endif
322
323 // lscp_socket_agent_join(&(pClient->udp));
324 lscp_socket_agent_join(&(pClient->tcp));
325
326 return LSCP_OK;
327 }
328
329
330 /**
331 * Terminate and destroy a client instance.
332 *
333 * @param pClient Pointer to client instance structure.
334 *
335 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
336 */
337 lscp_status_t lscp_client_destroy ( lscp_client_t *pClient )
338 {
339 if (pClient == NULL)
340 return LSCP_FAILED;
341
342 #ifdef DEBUG
343 fprintf(stderr, "lscp_client_destroy: pClient=%p.\n", pClient);
344 #endif
345
346 // Free session-id, if any.
347 if (pClient->sessid)
348 free(pClient->sessid);
349 pClient->sessid = NULL;
350 // Free up all cached members.
351 lscp_channel_info_reset(&(pClient->channel_info));
352 lscp_engine_info_reset(&(pClient->engine_info));
353 lscp_driver_info_reset(&(pClient->midi_info));
354 lscp_driver_info_reset(&(pClient->audio_info));
355 // Free available engine table.
356 lscp_szsplit_destroy(pClient->audio_drivers);
357 lscp_szsplit_destroy(pClient->midi_drivers);
358 lscp_isplit_destroy(pClient->audio_devices);
359 lscp_isplit_destroy(pClient->midi_devices);
360 lscp_szsplit_destroy(pClient->engines);
361 lscp_isplit_destroy(pClient->channels);
362 // Make them null.
363 pClient->audio_drivers = NULL;
364 pClient->midi_drivers = NULL;
365 pClient->engines = NULL;
366 // Free result error stuff.
367 _lscp_client_set_result(pClient, NULL, 0);
368 // Frre stream usage stuff.
369 if (pClient->buffer_fill)
370 free(pClient->buffer_fill);
371 pClient->buffer_fill = NULL;
372 pClient->iStreamCount = 0;
373 pClient->iTimeout = 0;
374
375 // Free socket agents.
376 lscp_socket_agent_free(&(pClient->udp));
377 lscp_socket_agent_free(&(pClient->tcp));
378
379 // Last but not least, free good ol'transaction mutex.
380 lscp_mutex_destroy(pClient->mutex);
381
382 free(pClient);
383
384 return LSCP_OK;
385 }
386
387
388 /**
389 * Set the client transaction timeout interval.
390 *
391 * @param pClient Pointer to client instance structure.
392 * @param iTimeout Transaction timeout in milliseconds.
393 *
394 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
395 */
396 lscp_status_t lscp_client_set_timeout ( lscp_client_t *pClient, int iTimeout )
397 {
398 if (pClient == NULL)
399 return LSCP_FAILED;
400 if (iTimeout < 0)
401 return LSCP_FAILED;
402
403 pClient->iTimeout = iTimeout;
404 return LSCP_OK;
405 }
406
407
408 /**
409 * Get the client transaction timeout interval.
410 *
411 * @param pClient Pointer to client instance structure.
412 *
413 * @returns The current timeout value milliseconds, -1 in case of failure.
414 */
415 int lscp_client_get_timeout ( lscp_client_t *pClient )
416 {
417 if (pClient == NULL)
418 return -1;
419
420 return pClient->iTimeout;
421 }
422
423
424 //-------------------------------------------------------------------------
425 // Client common protocol functions.
426
427
428 /**
429 * Submit a command query line string to the server. The query string
430 * must be cr/lf and null terminated. Besides the return code, the
431 * specific server response to the command request is made available
432 * by the @ref lscp_client_get_result and @ref lscp_client_get_errno
433 * function calls.
434 *
435 * @param pClient Pointer to client instance structure.
436 * @param pszQuery Command request line to be sent to server,
437 * must be cr/lf and null terminated.
438 *
439 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
440 */
441 lscp_status_t lscp_client_query ( lscp_client_t *pClient, const char *pszQuery )
442 {
443 fd_set fds; // File descriptor list for select().
444 int fd, fdmax; // Maximum file descriptor number.
445 struct timeval tv; // For specifying a timeout value.
446 int iSelect; // Holds select return status.
447 int iTimeout;
448 int cchQuery;
449 char achResult[LSCP_BUFSIZ];
450 int cchResult;
451 const char *pszSeps = ":[]";
452 char *pszResult;
453 char *pszToken;
454 char *pch;
455 int iErrno;
456
457 lscp_status_t ret = LSCP_FAILED;
458
459 if (pClient == NULL)
460 return ret;
461
462 // Lock this section up.
463 lscp_mutex_lock(pClient->mutex);
464
465 pszResult = NULL;
466 iErrno = -1;
467
468 // Send data, and then, wait for the result...
469 cchQuery = strlen(pszQuery);
470 if (send(pClient->tcp.sock, pszQuery, cchQuery, 0) < cchQuery) {
471 lscp_socket_perror("lscp_client_query: send");
472 pszResult = "Failure during send operation";
473 _lscp_client_set_result(pClient, pszResult, iErrno);
474 lscp_mutex_unlock(pClient->mutex);
475 return ret;
476 }
477
478 // Prepare for waiting on select...
479 fd = (int) pClient->tcp.sock;
480 FD_ZERO(&fds);
481 FD_SET((unsigned int) fd, &fds);
482 fdmax = fd;
483
484 // Use the timeout select feature...
485 iTimeout = pClient->iTimeout;
486 if (iTimeout > 1000) {
487 tv.tv_sec = iTimeout / 1000;
488 iTimeout -= tv.tv_sec * 1000;
489 }
490 else tv.tv_sec = 0;
491 tv.tv_usec = iTimeout * 1000;
492
493 // Wait for event...
494 iSelect = select(fdmax + 1, &fds, NULL, NULL, &tv);
495 if (iSelect > 0 && FD_ISSET(fd, &fds)) {
496 // May recv now...
497 cchResult = recv(pClient->tcp.sock, achResult, sizeof(achResult), 0);
498 if (cchResult > 0) {
499 // Assume early success.
500 ret = LSCP_OK;
501 // Always force the result to be null terminated (and trim trailing CRLFs)!
502 while (cchResult > 0 && (achResult[cchResult - 1] == '\n' || achResult[cchResult- 1] == '\r'))
503 cchResult--;
504 achResult[cchResult] = (char) 0;
505 // Check if the response it's an error or warning message.
506 if (strncasecmp(achResult, "WRN:", 4) == 0)
507 ret = LSCP_WARNING;
508 else if (strncasecmp(achResult, "ERR:", 4) == 0)
509 ret = LSCP_ERROR;
510 // So we got a result...
511 if (ret == LSCP_OK) {
512 // Reset errno in case of success.
513 iErrno = 0;
514 // Is it a special successful response?
515 if (strncasecmp(achResult, "OK[", 3) == 0) {
516 // Parse the OK message, get the return string under brackets...
517 pszToken = lscp_strtok(achResult, pszSeps, &(pch));
518 if (pszToken)
519 pszResult = lscp_strtok(NULL, pszSeps, &(pch));
520 }
521 else pszResult = achResult;
522 // The result string is now set to the command response, if any.
523 } else {
524 // Parse the error/warning message, skip first colon...
525 pszToken = lscp_strtok(achResult, pszSeps, &(pch));
526 if (pszToken) {
527 // Get the error number...
528 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
529 if (pszToken) {
530 iErrno = atoi(pszToken);
531 // And make the message text our final result.
532 pszResult = lscp_strtok(NULL, pszSeps, &(pch));
533 }
534 }
535 // The result string is set to the error/warning message text.
536 }
537 }
538 else if (cchResult == 0) {
539 // Fake a result message.
540 ret = LSCP_QUIT;
541 pszResult = "Server terminated the connection";
542 iErrno = (int) ret;
543 } else {
544 // What's down?
545 lscp_socket_perror("lscp_client_query: recv");
546 pszResult = "Failure during receive operation";
547 }
548 } // Check if select has timed out.
549 else if (iSelect == 0) {
550 // Fake a result message.
551 ret = LSCP_TIMEOUT;
552 pszResult = "Timeout during receive operation";
553 iErrno = (int) ret;
554 }
555 else lscp_socket_perror("lscp_client_query: select");
556
557 // Make the result official...
558 _lscp_client_set_result(pClient, pszResult, iErrno);
559
560 // Can go on with it...
561 lscp_mutex_unlock(pClient->mutex);
562
563 return ret;
564 }
565
566
567 /**
568 * Get the last received result string. In case of error or warning,
569 * this is the text of the error or warning message issued.
570 *
571 * @param pClient Pointer to client instance structure.
572 *
573 * @returns A pointer to the literal null-terminated result string as
574 * of the last command request.
575 */
576 const char *lscp_client_get_result ( lscp_client_t *pClient )
577 {
578 if (pClient == NULL)
579 return NULL;
580
581 return pClient->pszResult;
582 }
583
584
585 /**
586 * Get the last error/warning number received.
587 *
588 * @param pClient Pointer to client instance structure.
589 *
590 * @returns The numerical value of the last error or warning
591 * response code received.
592 */
593 int lscp_client_get_errno ( lscp_client_t *pClient )
594 {
595 if (pClient == NULL)
596 return -1;
597
598 return pClient->iErrno;
599 }
600
601
602 //-------------------------------------------------------------------------
603 // Client registration protocol functions.
604
605 /**
606 * Register frontend for receiving UDP event messages:
607 * SUBSCRIBE NOTIFICATION <udp-port>
608 *
609 * @param pClient Pointer to client instance structure.
610 *
611 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
612 */
613 lscp_status_t lscp_client_subscribe ( lscp_client_t *pClient )
614 {
615 lscp_status_t ret;
616 char szQuery[LSCP_BUFSIZ];
617 const char *pszResult;
618 const char *pszSeps = "[]";
619 char *pszToken;
620 char *pch;
621
622 if (pClient == NULL || pClient->sessid)
623 return LSCP_FAILED;
624
625 sprintf(szQuery, "SUBSCRIBE NOTIFICATION %d\r\n", ntohs(pClient->udp.addr.sin_port));
626 ret = lscp_client_query(pClient, szQuery);
627 if (ret == LSCP_OK) {
628 pszResult = lscp_client_get_result(pClient);
629 #ifdef DEBUG
630 fprintf(stderr, "lscp_client_subscribe: %s\n", pszResult);
631 #endif
632 // Check for the session-id on "OK[sessid]" response.
633 pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
634 if (pszToken && strcasecmp(pszToken, "OK") == 0) {
635 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
636 if (pszToken)
637 pClient->sessid = strdup(pszToken);
638 }
639 }
640
641 return ret;
642 }
643
644
645 /**
646 * Deregister frontend for not receiving UDP event messages anymore:
647 * UNSUBSCRIBE NOTIFICATION <session-id>
648 *
649 * @param pClient Pointer to client instance structure.
650 *
651 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
652 */
653 lscp_status_t lscp_client_unsubscribe ( lscp_client_t *pClient )
654 {
655 lscp_status_t ret;
656 char szQuery[LSCP_BUFSIZ];
657
658 if (pClient == NULL)
659 return LSCP_FAILED;
660 if (pClient->sessid == NULL)
661 return LSCP_FAILED;
662
663 sprintf(szQuery, "UNSUBSCRIBE NOTIFICATION %s\n\n", pClient->sessid);
664 ret = lscp_client_query(pClient, szQuery);
665 if (ret == LSCP_OK) {
666 #ifdef DEBUG
667 fprintf(stderr, "lscp_client_unsubscribe: %s\n", lscp_client_get_result(pClient));
668 #endif
669 // Bail out session-id string.
670 free(pClient->sessid);
671 pClient->sessid = NULL;
672 }
673
674 return ret;
675 }
676
677
678 //-------------------------------------------------------------------------
679 // Client command protocol functions.
680
681 /**
682 * Loading an instrument:
683 * LOAD INSTRUMENT <filename> <instr-index> <sampler-channel>
684 *
685 * @param pClient Pointer to client instance structure.
686 * @param pszFileName Instrument file name.
687 * @param iInstrIndex Instrument index number.
688 * @param iSamplerChannel Sampler Channel.
689 *
690 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
691 */
692 lscp_status_t lscp_load_instrument ( lscp_client_t *pClient, const char *pszFileName, int iInstrIndex, int iSamplerChannel )
693 {
694 char szQuery[LSCP_BUFSIZ];
695
696 if (pszFileName == NULL || iSamplerChannel < 0)
697 return LSCP_FAILED;
698
699 sprintf(szQuery, "LOAD INSTRUMENT %s %d %d\r\n", pszFileName, iInstrIndex, iSamplerChannel);
700 return lscp_client_query(pClient, szQuery);
701 }
702
703
704 /**
705 * Loading a sampler engine:
706 * LOAD ENGINE <engine-name> <sampler-channel>
707 *
708 * @param pClient Pointer to client instance structure.
709 * @param pszEngineName Engine name.
710 * @param iSamplerChannel Sampler channel number.
711 *
712 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
713 */
714 lscp_status_t lscp_load_engine ( lscp_client_t *pClient, const char *pszEngineName, int iSamplerChannel )
715 {
716 char szQuery[LSCP_BUFSIZ];
717
718 if (pszEngineName == NULL || iSamplerChannel < 0)
719 return LSCP_FAILED;
720
721 sprintf(szQuery, "LOAD ENGINE %s %d\r\n", pszEngineName, iSamplerChannel);
722 return lscp_client_query(pClient, szQuery);
723 }
724
725
726 /**
727 * Current number of sampler channels:
728 * GET CHANNELS
729 *
730 * @param pClient Pointer to client instance structure.
731 *
732 * @returns The current total number of sampler channels on success,
733 * -1 otherwise.
734 */
735 int lscp_get_channels ( lscp_client_t *pClient )
736 {
737 int iChannels = -1;
738 if (lscp_client_query(pClient, "GET CHANNELS\r\n") == LSCP_OK)
739 iChannels = atoi(lscp_client_get_result(pClient));
740 return iChannels;
741 }
742
743
744 /**
745 * List current sampler channels number identifiers:
746 * LIST CHANNELS
747 *
748 * @param pClient Pointer to client instance structure.
749 *
750 * @returns An array of the sampler channels identifiers as positive integers,
751 * terminated with -1 on success, NULL otherwise.
752 */
753 int *lscp_list_channels ( lscp_client_t *pClient )
754 {
755 const char *pszSeps = ",";
756
757 if (pClient == NULL)
758 return NULL;
759
760 if (pClient->channels) {
761 lscp_isplit_destroy(pClient->channels);
762 pClient->channels = NULL;
763 }
764
765 if (lscp_client_query(pClient, "LIST CHANNELS\r\n") == LSCP_OK)
766 pClient->channels = lscp_isplit_create(lscp_client_get_result(pClient), pszSeps);
767
768 return pClient->channels;
769 }
770
771
772 /**
773 * Adding a new sampler channel:
774 * ADD CHANNEL
775 *
776 * @param pClient Pointer to client instance structure.
777 *
778 * @returns The new sampler channel number identifier,
779 * or -1 in case of failure.
780 */
781 int lscp_add_channel ( lscp_client_t *pClient )
782 {
783 int iSamplerChannel = -1;
784 if (lscp_client_query(pClient, "ADD CHANNEL\r\n") == LSCP_OK)
785 iSamplerChannel = atoi(lscp_client_get_result(pClient));
786 return iSamplerChannel;
787 }
788
789
790 /**
791 * Removing a sampler channel:
792 * REMOVE CHANNEL <sampler-channel>
793 *
794 * @param pClient Pointer to client instance structure.
795 * @param iSamplerChannel Sampler channel number.
796 *
797 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
798 */
799 lscp_status_t lscp_remove_channel ( lscp_client_t *pClient, int iSamplerChannel )
800 {
801 char szQuery[LSCP_BUFSIZ];
802
803 if (iSamplerChannel < 0)
804 return LSCP_FAILED;
805
806 sprintf(szQuery, "REMOVE CHANNEL %d\r\n", iSamplerChannel);
807 return lscp_client_query(pClient, szQuery);
808 }
809
810
811 /**
812 * Getting all available engines:
813 * GET AVAILABLE_ENGINES
814 *
815 * @param pClient Pointer to client instance structure.
816 *
817 * @returns A NULL terminated array of engine name strings,
818 * or NULL in case of failure.
819 */
820 const char **lscp_get_available_engines ( lscp_client_t *pClient )
821 {
822 const char *pszSeps = ",";
823
824 if (pClient->engines) {
825 lscp_szsplit_destroy(pClient->engines);
826 pClient->engines = NULL;
827 }
828
829 if (lscp_client_query(pClient, "GET AVAILABLE_ENGINES\r\n") == LSCP_OK)
830 pClient->engines = lscp_szsplit_create(lscp_client_get_result(pClient), pszSeps);
831
832 return (const char **) pClient->engines;
833 }
834
835
836 /**
837 * Getting information about an engine.
838 * GET ENGINE INFO <engine-name>
839 *
840 * @param pClient Pointer to client instance structure.
841 * @param pszEngineName Engine name.
842 *
843 * @returns A pointer to a @ref lscp_engine_info_t structure, with all the
844 * information of the given sampler engine, or NULL in case of failure.
845 */
846 lscp_engine_info_t *lscp_get_engine_info ( lscp_client_t *pClient, const char *pszEngineName )
847 {
848 lscp_engine_info_t *pEngineInfo;
849 char szQuery[LSCP_BUFSIZ];
850 const char *pszResult;
851 const char *pszSeps = ":";
852 const char *pszCrlf = "\r\n";
853 char *pszToken;
854 char *pch;
855
856 if (pszEngineName == NULL)
857 return NULL;
858
859 pEngineInfo = &(pClient->engine_info);
860 lscp_engine_info_reset(pEngineInfo);
861
862 sprintf(szQuery, "GET ENGINE INFO %s\r\n", pszEngineName);
863 if (lscp_client_query(pClient, szQuery) != LSCP_OK)
864 return NULL;
865
866 pszResult = lscp_client_get_result(pClient);
867 pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
868 while (pszToken) {
869 if (strcasecmp(pszToken, "DESCRIPTION") == 0) {
870 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
871 if (pszToken)
872 pEngineInfo->description = lscp_unquote(&pszToken, 1);
873 }
874 else if (strcasecmp(pszToken, "VERSION") == 0) {
875 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
876 if (pszToken)
877 pEngineInfo->version = lscp_unquote(&pszToken, 1);
878 }
879 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
880 }
881
882 return pEngineInfo;
883 }
884
885
886 /**
887 * Getting sampler channel informations:
888 * GET CHANNEL INFO <sampler-channel>
889 *
890 * @param pClient Pointer to client instance structure.
891 * @param iSamplerChannel Sampler channel number.
892 *
893 * @returns A pointer to a @ref lscp_channel_info_t structure, with all the
894 * information of the given sampler channel, or NULL in case of failure.
895 */
896 lscp_channel_info_t *lscp_get_channel_info ( lscp_client_t *pClient, int iSamplerChannel )
897 {
898 lscp_channel_info_t *pChannelInfo;
899 char szQuery[LSCP_BUFSIZ];
900 const char *pszResult;
901 const char *pszSeps = ":";
902 const char *pszCrlf = "\r\n";
903 char *pszToken;
904 char *pch;
905
906 if (iSamplerChannel < 0)
907 return NULL;
908
909 pChannelInfo = &(pClient->channel_info);
910 lscp_channel_info_reset(pChannelInfo);
911
912 sprintf(szQuery, "GET CHANNEL INFO %d\r\n", iSamplerChannel);
913 if (lscp_client_query(pClient, szQuery) != LSCP_OK)
914 return NULL;
915
916 pszResult = lscp_client_get_result(pClient);
917 pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
918 while (pszToken) {
919 if (strcasecmp(pszToken, "ENGINE_NAME") == 0) {
920 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
921 if (pszToken)
922 pChannelInfo->engine_name = lscp_unquote(&pszToken, 1);
923 }
924 else if (strcasecmp(pszToken, "AUDIO_OUTPUT_DEVICE") == 0) {
925 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
926 if (pszToken)
927 pChannelInfo->audio_device = atoi(lscp_ltrim(pszToken));
928 }
929 else if (strcasecmp(pszToken, "AUDIO_OUTPUT_CHANNELS") == 0) {
930 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
931 if (pszToken)
932 pChannelInfo->audio_channels = atoi(lscp_ltrim(pszToken));
933 }
934 else if (strcasecmp(pszToken, "AUDIO_OUTPUT_ROUTING") == 0) {
935 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
936 if (pszToken)
937 pChannelInfo->audio_routing = lscp_szsplit_create(pszToken, ",");
938 }
939 else if (strcasecmp(pszToken, "INSTRUMENT_FILE") == 0) {
940 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
941 if (pszToken)
942 pChannelInfo->instrument_file = lscp_unquote(&pszToken, 1);
943 }
944 else if (strcasecmp(pszToken, "INSTRUMENT_NR") == 0) {
945 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
946 if (pszToken)
947 pChannelInfo->instrument_nr = atoi(lscp_ltrim(pszToken));
948 }
949 else if (strcasecmp(pszToken, "MIDI_INPUT_DEVICE") == 0) {
950 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
951 if (pszToken)
952 pChannelInfo->midi_device = atoi(lscp_ltrim(pszToken));
953 }
954 else if (strcasecmp(pszToken, "MIDI_INPUT_PORT") == 0) {
955 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
956 if (pszToken)
957 pChannelInfo->midi_port = atoi(lscp_ltrim(pszToken));
958 }
959 else if (strcasecmp(pszToken, "MIDI_INPUT_CHANNEL") == 0) {
960 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
961 if (pszToken)
962 pChannelInfo->midi_channel = atoi(lscp_ltrim(pszToken));
963 }
964 else if (strcasecmp(pszToken, "VOLUME") == 0) {
965 pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
966 if (pszToken)
967 pChannelInfo->volume = (float) atof(lscp_ltrim(pszToken));
968 }
969 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
970 }
971
972 return pChannelInfo;
973 }
974
975
976 /**
977 * Current number of active voices:
978 * GET CHANNEL VOICE_COUNT <sampler-channel>
979 *
980 * @param pClient Pointer to client instance structure.
981 * @param iSamplerChannel Sampler channel number.
982 *
983 * @returns The number of voices currently active, -1 in case of failure.
984 */
985 int lscp_get_channel_voice_count ( lscp_client_t *pClient, int iSamplerChannel )
986 {
987 char szQuery[LSCP_BUFSIZ];
988 int iVoiceCount = -1;
989
990 if (iSamplerChannel < 0)
991 return iVoiceCount;
992
993 sprintf(szQuery, "GET CHANNEL VOICE_COUNT %d\r\n", iSamplerChannel);
994 if (lscp_client_query(pClient, szQuery) == LSCP_OK)
995 iVoiceCount = atoi(lscp_client_get_result(pClient));
996
997 return iVoiceCount;
998 }
999
1000
1001 /**
1002 * Current number of active disk streams:
1003 * GET CHANNEL STREAM_COUNT <sampler-channel>
1004 *
1005 * @returns The number of active disk streams on success, -1 otherwise.
1006 */
1007 int lscp_get_channel_stream_count ( lscp_client_t *pClient, int iSamplerChannel )
1008 {
1009 char szQuery[LSCP_BUFSIZ];
1010 int iStreamCount = -1;
1011
1012 if (iSamplerChannel < 0)
1013 return iStreamCount;
1014
1015 sprintf(szQuery, "GET CHANNEL STREAM_COUNT %d\r\n", iSamplerChannel);
1016 if (lscp_client_query(pClient, szQuery) == LSCP_OK)
1017 iStreamCount = atoi(lscp_client_get_result(pClient));
1018
1019 return iStreamCount;
1020 }
1021
1022
1023 /**
1024 * Current fill state of disk stream buffers:
1025 * GET CHANNEL BUFFER_FILL {BYTES|PERCENTAGE} <sampler-channel>
1026 *
1027 * @param pClient Pointer to client instance structure.
1028 * @param usage_type Usage type to be returned, either
1029 * @ref LSCP_USAGE_BYTES, or
1030 * @ref LSCP_USAGE_PERCENTAGE.
1031 * @param iSamplerChannel Sampler channel number.
1032 *
1033 * @returns A pointer to a @ref lscp_buffer_fill_t structure, with the
1034 * information of the current disk stream buffer fill usage, for the given
1035 * sampler channel, or NULL in case of failure.
1036 */
1037 lscp_buffer_fill_t *lscp_get_channel_buffer_fill ( lscp_client_t *pClient, lscp_usage_t usage_type, int iSamplerChannel )
1038 {
1039 lscp_buffer_fill_t *pBufferFill;
1040 char szQuery[LSCP_BUFSIZ];
1041 int iStreamCount;
1042 const char *pszUsageType = (usage_type == LSCP_USAGE_BYTES ? "BYTES" : "PERCENTAGE");
1043 const char *pszResult;
1044 const char *pszSeps = "[]%,";
1045 char *pszToken;
1046 char *pch;
1047 int iStream;
1048
1049 iStreamCount = lscp_get_channel_stream_count(pClient, iSamplerChannel);
1050 if (pClient->iStreamCount != iStreamCount) {
1051 if (pClient->buffer_fill)
1052 free(pClient->buffer_fill);
1053 if (iStreamCount > 0)
1054 pClient->buffer_fill = (lscp_buffer_fill_t *) malloc(iStreamCount * sizeof(lscp_buffer_fill_t));
1055 else
1056 pClient->buffer_fill = NULL;
1057 pClient->iStreamCount = iStreamCount;
1058 }
1059
1060 if (pClient->iStreamCount < 1)
1061 return NULL;
1062
1063 iStream = 0;
1064 pBufferFill = pClient->buffer_fill;
1065
1066 // Get buffer fill usage...
1067 sprintf(szQuery, "GET CHANNEL BUFFER_FILL %s %d\r\n", pszUsageType, iSamplerChannel);
1068 if (lscp_client_query(pClient, szQuery) == LSCP_OK) {
1069 pszResult = lscp_client_get_result(pClient);
1070 pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
1071 while (pszToken && iStream < pClient->iStreamCount) {
1072 if (*pszToken) {
1073 pBufferFill[iStream].stream_id = atol(pszToken);
1074 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
1075 if (pszToken == NULL)
1076 break;
1077 pBufferFill[iStream].stream_usage = atol(pszToken);
1078 iStream++;
1079 }
1080 pszToken = lscp_strtok(NULL, pszSeps, &(pch));
1081 }
1082 } // Reset the usage, whatever it was before.
1083 else while (iStream < pClient->iStreamCount)
1084 pBufferFill[iStream++].stream_usage = 0;
1085
1086 return pBufferFill;
1087 }
1088
1089
1090 /**
1091 * Setting audio output type:
1092 * SET CHANNEL AUDIO_OUTPUT_TYPE <sampler-channel> <audio-output-type>
1093 *
1094 * @param pClient Pointer to client instance structure.
1095 * @param iSamplerChannel Sampler channel number.
1096 * @param pszAudioDriver Audio output driver type (e.g. "ALSA" or "JACK").
1097 */
1098 lscp_status_t lscp_set_channel_audio_type ( lscp_client_t *pClient, int iSamplerChannel, const char *pszAudioDriver )
1099 {
1100 char szQuery[LSCP_BUFSIZ];
1101
1102 if (iSamplerChannel < 0 || pszAudioDriver == NULL)
1103 return LSCP_FAILED;
1104
1105 sprintf(szQuery, "SET CHANNEL AUDIO_OUTPUT_TYPE %d %s\r\n", iSamplerChannel, pszAudioDriver);
1106 return lscp_client_query(pClient, szQuery);
1107 }
1108
1109
1110 /**
1111 * Setting audio output channel:
1112 * SET CHANNEL AUDIO_OUTPUT_CHANNEL <sampler-channel> <audio-output-chan> <audio-input-chan>
1113 *
1114 * @param pClient Pointer to client instance structure.
1115 * @param iSamplerChannel Sampler channel number.
1116 * @param iAudioOut Audio output device channel to be routed from.
1117 * @param iAudioIn Audio output device channel to be routed into.
1118 *
1119 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1120 */
1121 lscp_status_t lscp_set_channel_audio_channel ( lscp_client_t *pClient, int iSamplerChannel, int iAudioOut, int iAudioIn )
1122 {
1123 char szQuery[LSCP_BUFSIZ];
1124
1125 if (iSamplerChannel < 0 || iAudioOut < 0 || iAudioIn < 0)
1126 return LSCP_FAILED;
1127
1128 sprintf(szQuery, "SET CHANNEL AUDIO_OUTPUT_CHANNELS %d %d %d\r\n", iSamplerChannel, iAudioOut, iAudioIn);
1129 return lscp_client_query(pClient, szQuery);
1130 }
1131
1132
1133 /**
1134 * Setting MIDI input type:
1135 * SET CHANNEL MIDI_INPUT_TYPE <sampler-channel> <midi-input-type>
1136 *
1137 * @param pClient Pointer to client instance structure.
1138 * @param iSamplerChannel Sampler channel number.
1139 * @param pszMidiDriver MIDI input driver type (e.g. "ALSA").
1140 *
1141 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1142 */
1143 lscp_status_t lscp_set_channel_midi_type ( lscp_client_t *pClient, int iSamplerChannel, const char *pszMidiDriver )
1144 {
1145 char szQuery[LSCP_BUFSIZ];
1146
1147 if (iSamplerChannel < 0 || pszMidiDriver == NULL)
1148 return LSCP_FAILED;
1149
1150 sprintf(szQuery, "SET CHANNEL MIDI_INPUT_TYPE %d %s\r\n", iSamplerChannel, pszMidiDriver);
1151 return lscp_client_query(pClient, szQuery);
1152 }
1153
1154
1155 /**
1156 * Setting MIDI input port:
1157 * SET CHANNEL MIDI_INPUT_PORT <sampler-channel> <midi-input-port>
1158 *
1159 * @param pClient Pointer to client instance structure.
1160 * @param iSamplerChannel Sampler channel number.
1161 * @param iMidiPort MIDI input driver virtual port number.
1162 *
1163 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1164 */
1165 lscp_status_t lscp_set_channel_midi_port ( lscp_client_t *pClient, int iSamplerChannel, int iMidiPort )
1166 {
1167 char szQuery[LSCP_BUFSIZ];
1168
1169 if (iSamplerChannel < 0 || iMidiPort < 0)
1170 return LSCP_FAILED;
1171
1172 sprintf(szQuery, "SET CHANNEL MIDI_INPUT_PORT %d %d\r\n", iSamplerChannel, iMidiPort);
1173 return lscp_client_query(pClient, szQuery);
1174 }
1175
1176
1177 /**
1178 * Setting MIDI input channel:
1179 * SET CHANNEL MIDI_INPUT_CHANNEL <sampler-channel> <midi-input-chan>
1180 *
1181 * @param pClient Pointer to client instance structure.
1182 * @param iSamplerChannel Sampler channel number.
1183 * @param iMidiChannel MIDI channel number to listen (1-16) or
1184 * zero (0) to listen on all channels.
1185 *
1186 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1187 */
1188 lscp_status_t lscp_set_channel_midi_channel ( lscp_client_t *pClient, int iSamplerChannel, int iMidiChannel )
1189 {
1190 char szQuery[LSCP_BUFSIZ];
1191
1192 if (iSamplerChannel < 0 || iMidiChannel < 0 || iMidiChannel > 16)
1193 return LSCP_FAILED;
1194
1195 if (iMidiChannel > 0)
1196 sprintf(szQuery, "SET CHANNEL MIDI_INPUT_CHANNEL %d %d\r\n", iSamplerChannel, iMidiChannel);
1197 else
1198 sprintf(szQuery, "SET CHANNEL MIDI_INPUT_CHANNEL %d ALL\r\n", iSamplerChannel);
1199 return lscp_client_query(pClient, szQuery);
1200 }
1201
1202
1203 /**
1204 * Setting channel volume:
1205 * SET CHANNEL VOLUME <sampler-channel> <volume>
1206 *
1207 * @param pClient Pointer to client instance structure.
1208 * @param iSamplerChannel Sampler channel number.
1209 * @param fVolume Sampler channel volume as a positive floating point
1210 * number, where a value less than 1.0 for attenuation,
1211 * and greater than 1.0 for amplification.
1212 *
1213 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1214 */
1215 lscp_status_t lscp_set_channel_volume ( lscp_client_t *pClient, int iSamplerChannel, float fVolume )
1216 {
1217 char szQuery[LSCP_BUFSIZ];
1218
1219 if (iSamplerChannel < 0 || fVolume < 0.0)
1220 return LSCP_FAILED;
1221
1222 sprintf(szQuery, "SET CHANNEL VOLUME %d %g\r\n", iSamplerChannel, fVolume);
1223 return lscp_client_query(pClient, szQuery);
1224 }
1225
1226
1227 /**
1228 * Resetting a sampler channel:
1229 * RESET CHANNEL <sampler-channel>
1230 *
1231 * @param pClient Pointer to client instance structure.
1232 * @param iSamplerChannel Sampler channel number.
1233 *
1234 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1235 */
1236 lscp_status_t lscp_reset_channel ( lscp_client_t *pClient, int iSamplerChannel )
1237 {
1238 char szQuery[LSCP_BUFSIZ];
1239
1240 if (iSamplerChannel < 0)
1241 return LSCP_FAILED;
1242
1243 sprintf(szQuery, "RESET CHANNEL %d\r\n", iSamplerChannel);
1244 return lscp_client_query(pClient, szQuery);
1245 }
1246
1247
1248 // end of client.c

  ViewVC Help
Powered by ViewVC