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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 107 - (hide annotations) (download)
Fri Jun 4 21:06:59 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 39310 byte(s)
Initial alpha release.

1 capela 107 // 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_perror("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->engines = NULL;
275     lscp_driver_info_init(&(pClient->audio_info));
276     lscp_driver_info_init(&(pClient->midi_info));
277     lscp_engine_info_init(&(pClient->engine_info));
278     lscp_channel_info_init(&(pClient->channel_info));
279     // Initialize error stuff.
280     pClient->pszResult = NULL;
281     pClient->iErrno = -1;
282     // Stream usage stuff.
283     pClient->buffer_fill = NULL;
284     pClient->iStreamCount = 0;
285     // Default timeout value.
286     pClient->iTimeout = LSCP_TIMEOUT_MSECS;
287    
288     // Initialize the transaction mutex.
289     lscp_mutex_init(pClient->mutex);
290    
291     // Now's finally time to startup threads...
292     // UDP service thread...
293     if (lscp_socket_agent_start(&(pClient->udp), _lscp_client_udp_proc, pClient, 0) != LSCP_OK) {
294     lscp_socket_agent_free(&(pClient->tcp));
295     lscp_socket_agent_free(&(pClient->udp));
296     lscp_mutex_destroy(pClient->mutex);
297     free(pClient);
298     return NULL;
299     }
300    
301     // Finally we've some success...
302     return pClient;
303     }
304    
305    
306     /**
307     * Wait for a client instance to terminate graciously.
308     *
309     * @param pClient Pointer to client instance structure.
310     */
311     lscp_status_t lscp_client_join ( lscp_client_t *pClient )
312     {
313     if (pClient == NULL)
314     return LSCP_FAILED;
315    
316     #ifdef DEBUG
317     fprintf(stderr, "lscp_client_join: pClient=%p.\n", pClient);
318     #endif
319    
320     // lscp_socket_agent_join(&(pClient->udp));
321     lscp_socket_agent_join(&(pClient->tcp));
322    
323     return LSCP_OK;
324     }
325    
326    
327     /**
328     * Terminate and destroy a client instance.
329     *
330     * @param pClient Pointer to client instance structure.
331     *
332     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
333     */
334     lscp_status_t lscp_client_destroy ( lscp_client_t *pClient )
335     {
336     if (pClient == NULL)
337     return LSCP_FAILED;
338    
339     #ifdef DEBUG
340     fprintf(stderr, "lscp_client_destroy: pClient=%p.\n", pClient);
341     #endif
342    
343     // Free session-id, if any.
344     if (pClient->sessid)
345     free(pClient->sessid);
346     pClient->sessid = NULL;
347     // Free up all cached members.
348     lscp_channel_info_reset(&(pClient->channel_info));
349     lscp_engine_info_reset(&(pClient->engine_info));
350     lscp_driver_info_reset(&(pClient->midi_info));
351     lscp_driver_info_reset(&(pClient->audio_info));
352     // Free available engine table.
353     lscp_szsplit_destroy(pClient->audio_drivers);
354     lscp_szsplit_destroy(pClient->midi_drivers);
355     lscp_szsplit_destroy(pClient->engines);
356     // Make them null.
357     pClient->audio_drivers = NULL;
358     pClient->midi_drivers = NULL;
359     pClient->engines = NULL;
360     // Free result error stuff.
361     _lscp_client_set_result(pClient, NULL, 0);
362     // Frre stream usage stuff.
363     if (pClient->buffer_fill)
364     free(pClient->buffer_fill);
365     pClient->buffer_fill = NULL;
366     pClient->iStreamCount = 0;
367     pClient->iTimeout = 0;
368    
369     // Free socket agents.
370     lscp_socket_agent_free(&(pClient->udp));
371     lscp_socket_agent_free(&(pClient->tcp));
372    
373     // Last but not least, free good ol'transaction mutex.
374     lscp_mutex_destroy(pClient->mutex);
375    
376     free(pClient);
377    
378     return LSCP_OK;
379     }
380    
381    
382     /**
383     * Set the client transaction timeout interval.
384     *
385     * @param pClient Pointer to client instance structure.
386     * @param iTimeout Transaction timeout in milliseconds.
387     *
388     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
389     */
390     lscp_status_t lscp_client_set_timeout ( lscp_client_t *pClient, int iTimeout )
391     {
392     if (pClient == NULL)
393     return LSCP_FAILED;
394     if (iTimeout < 0)
395     return LSCP_FAILED;
396    
397     pClient->iTimeout = iTimeout;
398     return LSCP_OK;
399     }
400    
401    
402     /**
403     * Get the client transaction timeout interval.
404     *
405     * @param pClient Pointer to client instance structure.
406     *
407     * @returns The current timeout value milliseconds, -1 in case of failure.
408     */
409     int lscp_client_get_timeout ( lscp_client_t *pClient )
410     {
411     if (pClient == NULL)
412     return -1;
413    
414     return pClient->iTimeout;
415     }
416    
417    
418     //-------------------------------------------------------------------------
419     // Client common protocol functions.
420    
421    
422     /**
423     * Submit a command query line string to the server. The query string
424     * must be cr/lf and null terminated. Besides the return code, the
425     * specific server response to the command request is made available
426     * by the @ref lscp_client_get_result and @ref lscp_client_get_errno
427     * function calls.
428     *
429     * @param pClient Pointer to client instance structure.
430     * @param pszQuery Command request line to be sent to server,
431     * must be cr/lf and null terminated.
432     *
433     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
434     */
435     lscp_status_t lscp_client_query ( lscp_client_t *pClient, const char *pszQuery )
436     {
437     fd_set fds; // File descriptor list for select().
438     int fd, fdmax; // Maximum file descriptor number.
439     struct timeval tv; // For specifying a timeout value.
440     int iSelect; // Holds select return status.
441     int iTimeout;
442     int cchQuery;
443     char achResult[LSCP_BUFSIZ];
444     int cchResult;
445     const char *pszSeps = ":[]";
446     char *pszResult;
447     char *pszToken;
448     char *pch;
449     int iErrno;
450    
451     lscp_status_t ret = LSCP_FAILED;
452    
453     if (pClient == NULL)
454     return ret;
455    
456     // Lock this section up.
457     lscp_mutex_lock(pClient->mutex);
458    
459     pszResult = NULL;
460     iErrno = -1;
461    
462     // Send data, and then, wait for the result...
463     cchQuery = strlen(pszQuery);
464     if (send(pClient->tcp.sock, pszQuery, cchQuery, 0) < cchQuery) {
465     lscp_socket_perror("lscp_client_query: send");
466     lscp_mutex_unlock(pClient->mutex);
467     return ret;
468     }
469    
470     // Prepare for waiting on select...
471     fd = (int) pClient->tcp.sock;
472     FD_ZERO(&fds);
473     FD_SET((unsigned int) fd, &fds);
474     fdmax = fd;
475    
476     // Use the timeout select feature...
477     iTimeout = pClient->iTimeout;
478     if (iTimeout > 1000) {
479     tv.tv_sec = iTimeout / 1000;
480     iTimeout -= tv.tv_sec * 1000;
481     }
482     else tv.tv_sec = 0;
483     tv.tv_usec = iTimeout * 1000;
484    
485     // Wait for event...
486     iSelect = select(fdmax + 1, &fds, NULL, NULL, &tv);
487     if (iSelect > 0 && FD_ISSET(fd, &fds)) {
488     // May recv now...
489     cchResult = recv(pClient->tcp.sock, achResult, sizeof(achResult), 0);
490     if (cchResult > 0) {
491     // Assume early success.
492     ret = LSCP_OK;
493     // Always force the result to be null terminated (and trim trailing CRLFs)!
494     while (cchResult > 0 && (achResult[cchResult - 1] == '\n' || achResult[cchResult- 1] == '\r'))
495     cchResult--;
496     achResult[cchResult] = (char) 0;
497     // Check if the response it's an error or warning message.
498     if (strncasecmp(achResult, "WRN:", 4) == 0)
499     ret = LSCP_WARNING;
500     else if (strncasecmp(achResult, "ERR:", 4) == 0)
501     ret = LSCP_ERROR;
502     // So we got a result...
503     if (ret == LSCP_OK) {
504     // Reset errno in case of success.
505     iErrno = 0;
506     // Is it a special successful response?
507     if (strncasecmp(achResult, "OK[", 3) == 0) {
508     // Parse the OK message, get the return string under brackets...
509     pszToken = lscp_strtok(achResult, pszSeps, &(pch));
510     if (pszToken)
511     pszResult = lscp_strtok(NULL, pszSeps, &(pch));
512     }
513     else pszResult = achResult;
514     // The result string is now set to the command response, if any.
515     } else {
516     // Parse the error/warning message, skip first colon...
517     pszToken = lscp_strtok(achResult, pszSeps, &(pch));
518     if (pszToken) {
519     // Get the error number...
520     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
521     if (pszToken) {
522     iErrno = atoi(pszToken);
523     // And make the message text our final result.
524     pszResult = lscp_strtok(NULL, pszSeps, &(pch));
525     }
526     }
527     // The result string is set to the error/warning message text.
528     }
529     }
530     else if (cchResult == 0) {
531     // Fake a result message.
532     pszResult = "Server terminated the connection";
533     ret = LSCP_QUIT;
534     }
535     else lscp_socket_perror("lscp_client_query: recv");
536     } // Check if select has timed out.
537     else if (iSelect == 0) {
538     // Fake a result message.
539     pszResult = "Timeout during receive operation";
540     ret = LSCP_TIMEOUT;
541     }
542     else lscp_socket_perror("lscp_client_query: select");
543    
544     // Make the result official...
545     _lscp_client_set_result(pClient, pszResult, iErrno);
546    
547     // Can go on with it...
548     lscp_mutex_unlock(pClient->mutex);
549    
550     return ret;
551     }
552    
553    
554     /**
555     * Get the last received result string. In case of error or warning,
556     * this is the text of the error or warning message issued.
557     *
558     * @param pClient Pointer to client instance structure.
559     *
560     * @returns A pointer to the literal null-terminated result string as
561     * of the last command request.
562     */
563     const char *lscp_client_get_result ( lscp_client_t *pClient )
564     {
565     if (pClient == NULL)
566     return NULL;
567    
568     return pClient->pszResult;
569     }
570    
571    
572     /**
573     * Get the last error/warning number received.
574     *
575     * @param pClient Pointer to client instance structure.
576     *
577     * @returns The numerical value of the last error or warning
578     * response code received.
579     */
580     int lscp_client_get_errno ( lscp_client_t *pClient )
581     {
582     if (pClient == NULL)
583     return -1;
584    
585     return pClient->iErrno;
586     }
587    
588    
589     //-------------------------------------------------------------------------
590     // Client registration protocol functions.
591    
592     /**
593     * Register frontend for receiving UDP event messages:
594     * SUBSCRIBE NOTIFICATION <udp-port>
595     *
596     * @param pClient Pointer to client instance structure.
597     *
598     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
599     */
600     lscp_status_t lscp_client_subscribe ( lscp_client_t *pClient )
601     {
602     lscp_status_t ret;
603     char szQuery[LSCP_BUFSIZ];
604     const char *pszResult;
605     const char *pszSeps = "[]";
606     char *pszToken;
607     char *pch;
608    
609     if (pClient == NULL || pClient->sessid)
610     return LSCP_FAILED;
611    
612     sprintf(szQuery, "SUBSCRIBE NOTIFICATION %d\r\n", ntohs(pClient->udp.addr.sin_port));
613     ret = lscp_client_query(pClient, szQuery);
614     if (ret == LSCP_OK) {
615     pszResult = lscp_client_get_result(pClient);
616     #ifdef DEBUG
617     fprintf(stderr, "lscp_client_subscribe: %s\n", pszResult);
618     #endif
619     // Check for the session-id on "OK[sessid]" response.
620     pszToken = lscp_strtok(pszResult, pszSeps, &(pch));
621     if (pszToken && strcasecmp(pszToken, "OK") == 0) {
622     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
623     if (pszToken)
624     pClient->sessid = strdup(pszToken);
625     }
626     }
627    
628     return ret;
629     }
630    
631    
632     /**
633     * Deregister frontend for not receiving UDP event messages anymore:
634     * UNSUBSCRIBE NOTIFICATION <session-id>
635     *
636     * @param pClient Pointer to client instance structure.
637     *
638     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
639     */
640     lscp_status_t lscp_client_unsubscribe ( lscp_client_t *pClient )
641     {
642     lscp_status_t ret;
643     char szQuery[LSCP_BUFSIZ];
644    
645     if (pClient == NULL)
646     return LSCP_FAILED;
647     if (pClient->sessid == NULL)
648     return LSCP_FAILED;
649    
650     sprintf(szQuery, "UNSUBSCRIBE NOTIFICATION %s\n\n", pClient->sessid);
651     ret = lscp_client_query(pClient, szQuery);
652     if (ret == LSCP_OK) {
653     #ifdef DEBUG
654     fprintf(stderr, "lscp_client_unsubscribe: %s\n", lscp_client_get_result(pClient));
655     #endif
656     // Bail out session-id string.
657     free(pClient->sessid);
658     pClient->sessid = NULL;
659     }
660    
661     return ret;
662     }
663    
664    
665     //-------------------------------------------------------------------------
666     // Client command protocol functions.
667    
668     /**
669     * Loading an instrument:
670     * LOAD INSTRUMENT <filename> <instr-index> <sampler-channel>
671     *
672     * @param pClient Pointer to client instance structure.
673     * @param pszFileName Instrument file name.
674     * @param iInstrIndex Instrument index number.
675     * @param iSamplerChannel Sampler Channel.
676     *
677     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
678     */
679     lscp_status_t lscp_load_instrument ( lscp_client_t *pClient, const char *pszFileName, int iInstrIndex, int iSamplerChannel )
680     {
681     char szQuery[LSCP_BUFSIZ];
682    
683     if (pszFileName == NULL || iSamplerChannel < 0)
684     return LSCP_FAILED;
685    
686     sprintf(szQuery, "LOAD INSTRUMENT %s %d %d\r\n", pszFileName, iInstrIndex, iSamplerChannel);
687     return lscp_client_query(pClient, szQuery);
688     }
689    
690    
691     /**
692     * Loading a sampler engine:
693     * LOAD ENGINE <engine-name> <sampler-channel>
694     *
695     * @param pClient Pointer to client instance structure.
696     * @param pszEngineName Engine name.
697     * @param iSamplerChannel Sampler channel number.
698     *
699     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
700     */
701     lscp_status_t lscp_load_engine ( lscp_client_t *pClient, const char *pszEngineName, int iSamplerChannel )
702     {
703     char szQuery[LSCP_BUFSIZ];
704    
705     if (pszEngineName == NULL || iSamplerChannel < 0)
706     return LSCP_FAILED;
707    
708     sprintf(szQuery, "LOAD ENGINE %s %d\r\n", pszEngineName, iSamplerChannel);
709     return lscp_client_query(pClient, szQuery);
710     }
711    
712    
713     /**
714     * Current number of sampler channels:
715     * GET CHANNELS
716     *
717     * @param pClient Pointer to client instance structure.
718     *
719     * @returns The current total number of sampler channels on success,
720     * -1 otherwise.
721     */
722     int lscp_get_channels ( lscp_client_t *pClient )
723     {
724     int iChannels = -1;
725     if (lscp_client_query(pClient, "GET CHANNELS\r\n") == LSCP_OK)
726     iChannels = atoi(lscp_client_get_result(pClient));
727     return iChannels;
728     }
729    
730    
731     /**
732     * Adding a new sampler channel:
733     * ADD CHANNEL
734     *
735     * @param pClient Pointer to client instance structure.
736     *
737     * @returns The new sampler channel number identifier,
738     * or -1 in case of failure.
739     */
740     int lscp_add_channel ( lscp_client_t *pClient )
741     {
742     int iSamplerChannel = -1;
743     if (lscp_client_query(pClient, "ADD CHANNEL\r\n") == LSCP_OK)
744     iSamplerChannel = atoi(lscp_client_get_result(pClient));
745     return iSamplerChannel;
746     }
747    
748    
749     /**
750     * Removing a sampler channel:
751     * REMOVE CHANNEL <sampler-channel>
752     *
753     * @param pClient Pointer to client instance structure.
754     * @param iSamplerChannel Sampler channel number.
755     *
756     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
757     */
758     lscp_status_t lscp_remove_channel ( lscp_client_t *pClient, int iSamplerChannel )
759     {
760     char szQuery[LSCP_BUFSIZ];
761    
762     if (iSamplerChannel < 0)
763     return LSCP_FAILED;
764    
765     sprintf(szQuery, "REMOVE CHANNEL %d\r\n", iSamplerChannel);
766     return lscp_client_query(pClient, szQuery);
767     }
768    
769    
770     /**
771     * Getting all available engines:
772     * GET AVAILABLE_ENGINES
773     *
774     * @param pClient Pointer to client instance structure.
775     *
776     * @returns A NULL terminated array of engine name strings,
777     * or NULL in case of failure.
778     */
779     const char **lscp_get_available_engines ( lscp_client_t *pClient )
780     {
781     const char *pszSeps = ",";
782    
783     if (pClient->engines) {
784     lscp_szsplit_destroy(pClient->engines);
785     pClient->engines = NULL;
786     }
787    
788     if (lscp_client_query(pClient, "GET AVAILABLE_ENGINES\r\n") == LSCP_OK)
789     pClient->engines = lscp_szsplit_create(lscp_client_get_result(pClient), pszSeps);
790    
791     return (const char **) pClient->engines;
792     }
793    
794    
795     /**
796     * Getting information about an engine.
797     * GET ENGINE INFO <engine-name>
798     *
799     * @param pClient Pointer to client instance structure.
800     * @param pszEngineName Engine name.
801     *
802     * @returns A pointer to a @ref lscp_engine_info_t structure, with all the
803     * information of the given sampler engine, or NULL in case of failure.
804     */
805     lscp_engine_info_t *lscp_get_engine_info ( lscp_client_t *pClient, const char *pszEngineName )
806     {
807     lscp_engine_info_t *pEngineInfo;
808     char szQuery[LSCP_BUFSIZ];
809     const char *pszResult;
810     const char *pszSeps = ":";
811     const char *pszCrlf = "\r\n";
812     char *pszToken;
813     char *pch;
814    
815     if (pszEngineName == NULL)
816     return NULL;
817    
818     pEngineInfo = &(pClient->engine_info);
819     lscp_engine_info_reset(pEngineInfo);
820    
821     sprintf(szQuery, "GET ENGINE INFO %s\r\n", pszEngineName);
822     if (lscp_client_query(pClient, szQuery) != LSCP_OK)
823     return NULL;
824    
825     pszResult = lscp_client_get_result(pClient);
826     pszToken = lscp_strtok(pszResult, pszSeps, &(pch));
827     while (pszToken) {
828     if (strcasecmp(pszToken, "DESCRIPTION") == 0) {
829     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
830     if (pszToken)
831     pEngineInfo->description = lscp_unquote(&pszToken, 1);
832     }
833     else if (strcasecmp(pszToken, "VERSION") == 0) {
834     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
835     if (pszToken)
836     pEngineInfo->version = lscp_unquote(&pszToken, 1);
837     }
838     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
839     }
840    
841     return pEngineInfo;
842     }
843    
844    
845     /**
846     * Getting sampler channel informations:
847     * GET CHANNEL INFO <sampler-channel>
848     *
849     * @param pClient Pointer to client instance structure.
850     * @param iSamplerChannel Sampler channel number.
851     *
852     * @returns A pointer to a @ref lscp_channel_info_t structure, with all the
853     * information of the given sampler channel, or NULL in case of failure.
854     */
855     lscp_channel_info_t *lscp_get_channel_info ( lscp_client_t *pClient, int iSamplerChannel )
856     {
857     lscp_channel_info_t *pChannelInfo;
858     char szQuery[LSCP_BUFSIZ];
859     const char *pszResult;
860     const char *pszSeps = ":";
861     const char *pszCrlf = "\r\n";
862     char *pszToken;
863     char *pch;
864    
865     if (iSamplerChannel < 0)
866     return NULL;
867    
868     pChannelInfo = &(pClient->channel_info);
869     lscp_channel_info_reset(pChannelInfo);
870    
871     sprintf(szQuery, "GET CHANNEL INFO %d\r\n", iSamplerChannel);
872     if (lscp_client_query(pClient, szQuery) != LSCP_OK)
873     return NULL;
874    
875     pszResult = lscp_client_get_result(pClient);
876     pszToken = lscp_strtok(pszResult, pszSeps, &(pch));
877     while (pszToken) {
878     if (strcasecmp(pszToken, "ENGINE_NAME") == 0) {
879     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
880     if (pszToken)
881     pChannelInfo->engine_name = lscp_unquote(&pszToken, 1);
882     }
883     else if (strcasecmp(pszToken, "AUDIO_OUTPUT_DEVICE") == 0) {
884     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
885     if (pszToken)
886     pChannelInfo->audio_device = atoi(lscp_ltrim(pszToken));
887     }
888     else if (strcasecmp(pszToken, "AUDIO_OUTPUT_CHANNELS") == 0) {
889     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
890     if (pszToken)
891     pChannelInfo->audio_channels = atoi(lscp_ltrim(pszToken));
892     }
893     else if (strcasecmp(pszToken, "AUDIO_OUTPUT_ROUTING") == 0) {
894     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
895     if (pszToken)
896     pChannelInfo->audio_routing = lscp_szsplit_create(pszToken, ",");
897     }
898     else if (strcasecmp(pszToken, "INSTRUMENT_FILE") == 0) {
899     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
900     if (pszToken)
901     pChannelInfo->instrument_file = lscp_unquote(&pszToken, 1);
902     }
903     else if (strcasecmp(pszToken, "INSTRUMENT_NR") == 0) {
904     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
905     if (pszToken)
906     pChannelInfo->instrument_nr = atoi(lscp_ltrim(pszToken));
907     }
908     else if (strcasecmp(pszToken, "MIDI_INPUT_DEVICE") == 0) {
909     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
910     if (pszToken)
911     pChannelInfo->midi_device = atoi(lscp_ltrim(pszToken));
912     }
913     else if (strcasecmp(pszToken, "MIDI_INPUT_PORT") == 0) {
914     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
915     if (pszToken)
916     pChannelInfo->midi_port = atoi(lscp_ltrim(pszToken));
917     }
918     else if (strcasecmp(pszToken, "MIDI_INPUT_CHANNEL") == 0) {
919     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
920     if (pszToken)
921     pChannelInfo->midi_channel = atoi(lscp_ltrim(pszToken));
922     }
923     else if (strcasecmp(pszToken, "VOLUME") == 0) {
924     pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
925     if (pszToken)
926     pChannelInfo->volume = (float) atof(lscp_ltrim(pszToken));
927     }
928     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
929     }
930    
931     return pChannelInfo;
932     }
933    
934    
935     /**
936     * Current number of active voices:
937     * GET CHANNEL VOICE_COUNT <sampler-channel>
938     *
939     * @param pClient Pointer to client instance structure.
940     * @param iSamplerChannel Sampler channel number.
941     *
942     * @returns The number of voices currently active, -1 in case of failure.
943     */
944     int lscp_get_channel_voice_count ( lscp_client_t *pClient, int iSamplerChannel )
945     {
946     char szQuery[LSCP_BUFSIZ];
947     int iVoiceCount = -1;
948    
949     if (iSamplerChannel < 0)
950     return iVoiceCount;
951    
952     sprintf(szQuery, "GET CHANNEL VOICE_COUNT %d\r\n", iSamplerChannel);
953     if (lscp_client_query(pClient, szQuery) == LSCP_OK)
954     iVoiceCount = atoi(lscp_client_get_result(pClient));
955    
956     return iVoiceCount;
957     }
958    
959    
960     /**
961     * Current number of active disk streams:
962     * GET CHANNEL STREAM_COUNT <sampler-channel>
963     *
964     * @returns The number of active disk streams on success, -1 otherwise.
965     */
966     int lscp_get_channel_stream_count ( lscp_client_t *pClient, int iSamplerChannel )
967     {
968     char szQuery[LSCP_BUFSIZ];
969     int iStreamCount = -1;
970    
971     if (iSamplerChannel < 0)
972     return iStreamCount;
973    
974     sprintf(szQuery, "GET CHANNEL STREAM_COUNT %d\r\n", iSamplerChannel);
975     if (lscp_client_query(pClient, szQuery) == LSCP_OK)
976     iStreamCount = atoi(lscp_client_get_result(pClient));
977    
978     return iStreamCount;
979     }
980    
981    
982     /**
983     * Current fill state of disk stream buffers:
984     * GET CHANNEL BUFFER_FILL {BYTES|PERCENTAGE} <sampler-channel>
985     *
986     * @param pClient Pointer to client instance structure.
987     * @param usage_type Usage type to be returned, either
988     * @ref LSCP_USAGE_BYTES, or
989     * @ref LSCP_USAGE_PERCENTAGE.
990     * @param iSamplerChannel Sampler channel number.
991     *
992     * @returns A pointer to a @ref lscp_buffer_fill_t structure, with the
993     * information of the current disk stream buffer fill usage, for the given
994     * sampler channel, or NULL in case of failure.
995     */
996     lscp_buffer_fill_t *lscp_get_channel_buffer_fill ( lscp_client_t *pClient, lscp_usage_t usage_type, int iSamplerChannel )
997     {
998     lscp_buffer_fill_t *pBufferFill;
999     char szQuery[LSCP_BUFSIZ];
1000     int iStreamCount;
1001     const char *pszUsageType = (usage_type == LSCP_USAGE_BYTES ? "BYTES" : "PERCENTAGE");
1002     const char *pszResult;
1003     const char *pszSeps = "[]%,";
1004     char *pszToken;
1005     char *pch;
1006     int iStream;
1007    
1008     iStreamCount = lscp_get_channel_stream_count(pClient, iSamplerChannel);
1009     if (pClient->iStreamCount != iStreamCount) {
1010     if (pClient->buffer_fill)
1011     free(pClient->buffer_fill);
1012     if (iStreamCount > 0)
1013     pClient->buffer_fill = (lscp_buffer_fill_t *) malloc(iStreamCount * sizeof(lscp_buffer_fill_t));
1014     else
1015     pClient->buffer_fill = NULL;
1016     pClient->iStreamCount = iStreamCount;
1017     }
1018    
1019     if (pClient->iStreamCount < 1)
1020     return NULL;
1021    
1022     iStream = 0;
1023     pBufferFill = pClient->buffer_fill;
1024    
1025     // Get buffer fill usage...
1026     sprintf(szQuery, "GET CHANNEL BUFFER_FILL %s %d\r\n", pszUsageType, iSamplerChannel);
1027     if (lscp_client_query(pClient, szQuery) == LSCP_OK) {
1028     pszResult = lscp_client_get_result(pClient);
1029     pszToken = lscp_strtok(pszResult, pszSeps, &(pch));
1030     while (pszToken && iStream < pClient->iStreamCount) {
1031     if (*pszToken) {
1032     pBufferFill[iStream].stream_id = atol(pszToken);
1033     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
1034     if (pszToken == NULL)
1035     break;
1036     pBufferFill[iStream].stream_usage = atol(pszToken);
1037     iStream++;
1038     }
1039     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
1040     }
1041     } // Reset the usage, whatever it was before.
1042     else while (iStream < pClient->iStreamCount)
1043     pBufferFill[iStream++].stream_usage = 0;
1044    
1045     return pBufferFill;
1046     }
1047    
1048    
1049     /**
1050     * Setting audio output type:
1051     * SET CHANNEL AUDIO_OUTPUT_TYPE <sampler-channel> <audio-output-type>
1052     *
1053     * @param pClient Pointer to client instance structure.
1054     * @param iSamplerChannel Sampler channel number.
1055     * @param pszAudioDriver Audio output driver type (e.g. "ALSA" or "JACK").
1056     */
1057     lscp_status_t lscp_set_channel_audio_type ( lscp_client_t *pClient, int iSamplerChannel, const char *pszAudioDriver )
1058     {
1059     char szQuery[LSCP_BUFSIZ];
1060    
1061     if (iSamplerChannel < 0 || pszAudioDriver == NULL)
1062     return LSCP_FAILED;
1063    
1064     sprintf(szQuery, "SET CHANNEL AUDIO_OUTPUT_TYPE %d %s\r\n", iSamplerChannel, pszAudioDriver);
1065     return lscp_client_query(pClient, szQuery);
1066     }
1067    
1068    
1069     /**
1070     * Setting audio output channel:
1071     * SET CHANNEL AUDIO_OUTPUT_CHANNEL <sampler-channel> <audio-output-chan> <audio-input-chan>
1072     *
1073     * @param pClient Pointer to client instance structure.
1074     * @param iSamplerChannel Sampler channel number.
1075     * @param iAudioOut Audio output device channel to be routed from.
1076     * @param iAudioIn Audio output device channel to be routed into.
1077     *
1078     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1079     */
1080     lscp_status_t lscp_set_channel_audio_channel ( lscp_client_t *pClient, int iSamplerChannel, int iAudioOut, int iAudioIn )
1081     {
1082     char szQuery[LSCP_BUFSIZ];
1083    
1084     if (iSamplerChannel < 0 || iAudioOut < 0 || iAudioIn < 0)
1085     return LSCP_FAILED;
1086    
1087     sprintf(szQuery, "SET CHANNEL AUDIO_OUTPUT_CHANNELS %d %d %d\r\n", iSamplerChannel, iAudioOut, iAudioIn);
1088     return lscp_client_query(pClient, szQuery);
1089     }
1090    
1091    
1092     /**
1093     * Setting MIDI input type:
1094     * SET CHANNEL MIDI_INPUT_TYPE <sampler-channel> <midi-input-type>
1095     *
1096     * @param pClient Pointer to client instance structure.
1097     * @param iSamplerChannel Sampler channel number.
1098     * @param pszMidiDriver MIDI input driver type (e.g. "ALSA").
1099     *
1100     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1101     */
1102     lscp_status_t lscp_set_channel_midi_type ( lscp_client_t *pClient, int iSamplerChannel, const char *pszMidiDriver )
1103     {
1104     char szQuery[LSCP_BUFSIZ];
1105    
1106     if (iSamplerChannel < 0 || pszMidiDriver == NULL)
1107     return LSCP_FAILED;
1108    
1109     sprintf(szQuery, "SET CHANNEL MIDI_INPUT_TYPE %d %s\r\n", iSamplerChannel, pszMidiDriver);
1110     return lscp_client_query(pClient, szQuery);
1111     }
1112    
1113    
1114     /**
1115     * Setting MIDI input port:
1116     * SET CHANNEL MIDI_INPUT_PORT <sampler-channel> <midi-input-port>
1117     *
1118     * @param pClient Pointer to client instance structure.
1119     * @param iSamplerChannel Sampler channel number.
1120     * @param iMidiPort MIDI input driver virtual port number.
1121     *
1122     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1123     */
1124     lscp_status_t lscp_set_channel_midi_port ( lscp_client_t *pClient, int iSamplerChannel, int iMidiPort )
1125     {
1126     char szQuery[LSCP_BUFSIZ];
1127    
1128     if (iSamplerChannel < 0 || iMidiPort < 0)
1129     return LSCP_FAILED;
1130    
1131     sprintf(szQuery, "SET CHANNEL MIDI_INPUT_PORT %d %d\r\n", iSamplerChannel, iMidiPort);
1132     return lscp_client_query(pClient, szQuery);
1133     }
1134    
1135    
1136     /**
1137     * Setting MIDI input channel:
1138     * SET CHANNEL MIDI_INPUT_CHANNEL <sampler-channel> <midi-input-chan>
1139     *
1140     * @param pClient Pointer to client instance structure.
1141     * @param iSamplerChannel Sampler channel number.
1142     * @param iMidiChannel MIDI channel number to listen (1-16) or
1143     * zero (0) to listen on all channels.
1144     *
1145     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1146     */
1147     lscp_status_t lscp_set_channel_midi_channel ( lscp_client_t *pClient, int iSamplerChannel, int iMidiChannel )
1148     {
1149     char szQuery[LSCP_BUFSIZ];
1150    
1151     if (iSamplerChannel < 0 || iMidiChannel < 0 || iMidiChannel > 16)
1152     return LSCP_FAILED;
1153    
1154     if (iMidiChannel > 0)
1155     sprintf(szQuery, "SET CHANNEL MIDI_INPUT_CHANNEL %d %d\r\n", iSamplerChannel, iMidiChannel);
1156     else
1157     sprintf(szQuery, "SET CHANNEL MIDI_INPUT_CHANNEL %d ALL\r\n", iSamplerChannel);
1158     return lscp_client_query(pClient, szQuery);
1159     }
1160    
1161    
1162     /**
1163     * Setting channel volume:
1164     * SET CHANNEL VOLUME <sampler-channel> <volume>
1165     *
1166     * @param pClient Pointer to client instance structure.
1167     * @param iSamplerChannel Sampler channel number.
1168     * @param fVolume Sampler channel volume as a positive floating point
1169     * number, where a value less than 1.0 for attenuation,
1170     * and greater than 1.0 for amplification.
1171     *
1172     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1173     */
1174     lscp_status_t lscp_set_channel_volume ( lscp_client_t *pClient, int iSamplerChannel, float fVolume )
1175     {
1176     char szQuery[LSCP_BUFSIZ];
1177    
1178     if (iSamplerChannel < 0 || fVolume < 0.0)
1179     return LSCP_FAILED;
1180    
1181     sprintf(szQuery, "SET CHANNEL VOLUME %d %g\r\n", iSamplerChannel, fVolume);
1182     return lscp_client_query(pClient, szQuery);
1183     }
1184    
1185    
1186     /**
1187     * Resetting a sampler channel:
1188     * RESET CHANNEL <sampler-channel>
1189     *
1190     * @param pClient Pointer to client instance structure.
1191     * @param iSamplerChannel Sampler channel number.
1192     *
1193     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
1194     */
1195     lscp_status_t lscp_reset_channel ( lscp_client_t *pClient, int iSamplerChannel )
1196     {
1197     char szQuery[LSCP_BUFSIZ];
1198    
1199     if (iSamplerChannel < 0)
1200     return LSCP_FAILED;
1201    
1202     sprintf(szQuery, "RESET CHANNEL %d\r\n", iSamplerChannel);
1203     return lscp_client_query(pClient, szQuery);
1204     }
1205    
1206    
1207     // end of client.c

  ViewVC Help
Powered by ViewVC