1 // device.c
2 //
3 /****************************************************************************
4    liblscp - LinuxSampler Control Protocol API
5    Copyright (C) 2004-2021, 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 General Public License along
18    with this program; if not, write to the Free Software Foundation, Inc.,
19    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21 *****************************************************************************/
22 
23 #include "common.h"
24 
25 
26 // Local prototypes.
27 
28 static lscp_driver_info_t *_lscp_driver_info_query (lscp_client_t *pClient, lscp_driver_info_t *pDriverInfo, char *pszQuery);
29 static lscp_device_info_t *_lscp_device_info_query (lscp_client_t *pClient, lscp_device_info_t *pDeviceInfo, char *pszQuery);
30 static lscp_param_info_t  *_lscp_param_info_query  (lscp_client_t *pClient, lscp_param_info_t *pParamInfo, char *pszQuery, int cchMaxQuery, lscp_param_t *pDepList);
31 
32 static lscp_device_port_info_t *_lscp_device_port_info_query (lscp_client_t *pClient, lscp_device_port_info_t *pDevicePortInfo, char *pszQuery);
33 
34 
35 //-------------------------------------------------------------------------
36 // Local funtions.
37 
38 // Common driver type query command.
_lscp_driver_info_query(lscp_client_t * pClient,lscp_driver_info_t * pDriverInfo,char * pszQuery)39 static lscp_driver_info_t *_lscp_driver_info_query ( lscp_client_t *pClient, lscp_driver_info_t *pDriverInfo, char *pszQuery )
40 {
41 	const char *pszResult;
42 	const char *pszSeps = ":";
43 	const char *pszCrlf = "\r\n";
44 	char *pszToken;
45 	char *pch;
46 
47 	// Lock this section up.
48 	lscp_mutex_lock(pClient->mutex);
49 
50 	lscp_driver_info_reset(pDriverInfo);
51 	if (lscp_client_call(pClient, pszQuery, 1) == LSCP_OK) {
52 		pszResult = lscp_client_get_result(pClient);
53 		pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
54 		while (pszToken) {
55 			if (strcasecmp(pszToken, "DESCRIPTION") == 0) {
56 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
57 				if (pszToken)
58 					lscp_unquote_dup(&(pDriverInfo->description), &pszToken);
59 			}
60 			else if (strcasecmp(pszToken, "VERSION") == 0) {
61 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
62 				if (pszToken)
63 					lscp_unquote_dup(&(pDriverInfo->version), &pszToken);
64 			}
65 			else if (strcasecmp(pszToken, "PARAMETERS") == 0) {
66 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
67 				if (pszToken) {
68 					if (pDriverInfo->parameters)
69 						lscp_szsplit_destroy(pDriverInfo->parameters);
70 					pDriverInfo->parameters = lscp_szsplit_create(pszToken, ",");
71 				}
72 			}
73 			pszToken = lscp_strtok(NULL, pszSeps, &(pch));
74 		}
75 	}
76 	else pDriverInfo = NULL;
77 
78 	// Unlock this section down.
79 	lscp_mutex_unlock(pClient->mutex);
80 
81 	return pDriverInfo;
82 }
83 
84 
85 // Common device info query command.
_lscp_device_info_query(lscp_client_t * pClient,lscp_device_info_t * pDeviceInfo,char * pszQuery)86 static lscp_device_info_t *_lscp_device_info_query ( lscp_client_t *pClient, lscp_device_info_t *pDeviceInfo, char *pszQuery )
87 {
88 	const char *pszResult;
89 	const char *pszSeps = ":";
90 	const char *pszCrlf = "\r\n";
91 	char *pszToken;
92 	char *pch;
93 	char *pszKey;
94 
95 	// Lock this section up.
96 	lscp_mutex_lock(pClient->mutex);
97 
98 	lscp_device_info_reset(pDeviceInfo);
99 	if (lscp_client_call(pClient, pszQuery, 1) == LSCP_OK) {
100 		pszResult = lscp_client_get_result(pClient);
101 		pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
102 		while (pszToken) {
103 			if (strcasecmp(pszToken, "DRIVER") == 0) {
104 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
105 				if (pszToken)
106 					lscp_unquote_dup(&(pDeviceInfo->driver), &pszToken);
107 			}
108 			else {
109 				pszKey = pszToken;
110 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
111 				if (pszToken)
112 					lscp_plist_append(&(pDeviceInfo->params), pszKey, lscp_unquote(&pszToken, 0));
113 			}
114 			pszToken = lscp_strtok(NULL, pszSeps, &(pch));
115 		}
116 	}
117 	else pDeviceInfo = NULL;
118 
119 	// Unlock this section down.
120 	lscp_mutex_unlock(pClient->mutex);
121 
122 	return pDeviceInfo;
123 }
124 
125 
126 // Common device channel/port info query command.
_lscp_device_port_info_query(lscp_client_t * pClient,lscp_device_port_info_t * pDevicePortInfo,char * pszQuery)127 static lscp_device_port_info_t *_lscp_device_port_info_query ( lscp_client_t *pClient, lscp_device_port_info_t *pDevicePortInfo, char *pszQuery )
128 {
129 	const char *pszResult;
130 	const char *pszSeps = ":";
131 	const char *pszCrlf = "\r\n";
132 	char *pszToken;
133 	char *pch;
134 	char *pszKey;
135 	char *pszVal;
136 
137 	// Lock this section up.
138 	lscp_mutex_lock(pClient->mutex);
139 
140 	lscp_device_port_info_reset(pDevicePortInfo);
141 	if (lscp_client_call(pClient, pszQuery, 1) == LSCP_OK) {
142 		pszResult = lscp_client_get_result(pClient);
143 		pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
144 		while (pszToken) {
145 			pszKey = pszToken;
146 			pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
147 			if (pszKey && pszToken) {
148 				pszVal = lscp_unquote(&pszToken, 0);
149 				lscp_plist_append(&(pDevicePortInfo->params), pszKey, pszVal);
150 				if (strcasecmp(pszKey, "NAME") == 0) {
151 					// Free desteny string, if already there.
152 					if (pDevicePortInfo->name)
153 						free(pDevicePortInfo->name);
154 					pDevicePortInfo->name = NULL;
155 					if (pszVal)
156 						pDevicePortInfo->name = strdup(pszVal);
157 				}
158 			}
159 			pszToken = lscp_strtok(NULL, pszSeps, &(pch));
160 		}
161 	}
162 	else pDevicePortInfo = NULL;
163 
164 	// Unlock this section down.
165 	lscp_mutex_unlock(pClient->mutex);
166 
167 	return pDevicePortInfo;
168 }
169 
170 
171 // Common parameter info query command.
_lscp_param_info_query(lscp_client_t * pClient,lscp_param_info_t * pParamInfo,char * pszQuery,int cchMaxQuery,lscp_param_t * pDepList)172 static lscp_param_info_t *_lscp_param_info_query ( lscp_client_t *pClient, lscp_param_info_t *pParamInfo, char *pszQuery, int cchMaxQuery, lscp_param_t *pDepList )
173 {
174 	const char *pszResult;
175 	const char *pszSeps = ":";
176 	const char *pszCrlf = "\r\n";
177 	char *pszToken;
178 	char *pch;
179 
180 	// Lock this section up.
181 	lscp_mutex_lock(pClient->mutex);
182 
183 	lscp_param_info_reset(pParamInfo);
184 	lscp_param_concat(pszQuery, cchMaxQuery, pDepList);
185 	if (lscp_client_call(pClient, pszQuery, 1) == LSCP_OK) {
186 		pszResult = lscp_client_get_result(pClient);
187 		pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch));
188 		while (pszToken) {
189 			if (strcasecmp(pszToken, "TYPE") == 0) {
190 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
191 				if (pszToken) {
192 					pszToken = lscp_unquote(&pszToken, 0);
193 					if (strcasecmp(pszToken, "BOOL") == 0)
194 						pParamInfo->type = LSCP_TYPE_BOOL;
195 					else if (strcasecmp(pszToken, "INT") == 0)
196 						pParamInfo->type = LSCP_TYPE_INT;
197 					else if (strcasecmp(pszToken, "FLOAT") == 0)
198 						pParamInfo->type = LSCP_TYPE_FLOAT;
199 					else if (strcasecmp(pszToken, "STRING") == 0)
200 						pParamInfo->type = LSCP_TYPE_STRING;
201 				}
202 			}
203 			else if (strcasecmp(pszToken, "DESCRIPTION") == 0) {
204 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
205 				if (pszToken)
206 					lscp_unquote_dup(&(pParamInfo->description), &pszToken);
207 			}
208 			else if (strcasecmp(pszToken, "MANDATORY") == 0) {
209 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
210 				if (pszToken)
211 					pParamInfo->mandatory = (strcasecmp(lscp_unquote(&pszToken, 0), "TRUE") == 0);
212 			}
213 			else if (strcasecmp(pszToken, "FIX") == 0) {
214 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
215 				if (pszToken)
216 					pParamInfo->fix = (strcasecmp(lscp_unquote(&pszToken, 0), "TRUE") == 0);
217 			}
218 			else if (strcasecmp(pszToken, "MULTIPLICITY") == 0) {
219 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
220 				if (pszToken)
221 					pParamInfo->multiplicity = (strcasecmp(lscp_unquote(&pszToken, 0), "TRUE") == 0);
222 			}
223 			else if (strcasecmp(pszToken, "DEPENDS") == 0) {
224 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
225 				if (pszToken) {
226 					if (pParamInfo->depends)
227 						lscp_szsplit_destroy(pParamInfo->depends);
228 					pParamInfo->depends = lscp_szsplit_create(pszToken, ",");
229 				}
230 			}
231 			else if (strcasecmp(pszToken, "DEFAULT") == 0) {
232 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
233 				if (pszToken)
234 					lscp_unquote_dup(&(pParamInfo->defaultv), &pszToken);
235 			}
236 			else if (strcasecmp(pszToken, "RANGE_MIN") == 0) {
237 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
238 				if (pszToken)
239 					lscp_unquote_dup(&(pParamInfo->range_min), &pszToken);
240 			}
241 			else if (strcasecmp(pszToken, "RANGE_MAX") == 0) {
242 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
243 				if (pszToken)
244 					lscp_unquote_dup(&(pParamInfo->range_max), &pszToken);
245 			}
246 			else if (strcasecmp(pszToken, "POSSIBILITIES") == 0) {
247 				pszToken = lscp_strtok(NULL, pszCrlf, &(pch));
248 				if (pszToken) {
249 					if (pParamInfo->possibilities)
250 						lscp_szsplit_destroy(pParamInfo->possibilities);
251 					pParamInfo->possibilities = lscp_szsplit_create(pszToken, ",");
252 				}
253 			}
254 			pszToken = lscp_strtok(NULL, pszSeps, &(pch));
255 		}
256 	}
257 	else pParamInfo = NULL;
258 
259 	// Unlock this section down.
260 	lscp_mutex_unlock(pClient->mutex);
261 
262 	return pParamInfo;
263 }
264 
265 
266 //-------------------------------------------------------------------------
267 // Audio driver control functions.
268 
269 /**
270  *  Getting all available audio output driver count.
271  *  GET AVAILABLE_AUDIO_OUTPUT_DRIVERS
272  *
273  *  @param pClient  Pointer to client instance structure.
274  *
275  *  @returns The current total number of audio output drivers on success,
276  *  -1 otherwise.
277  */
lscp_get_available_audio_drivers(lscp_client_t * pClient)278 int lscp_get_available_audio_drivers ( lscp_client_t *pClient )
279 {
280 	int iAudioDrivers = -1;
281 
282 	if (pClient == NULL)
283 		return -1;
284 
285 	// Lock this section up.
286 	lscp_mutex_lock(pClient->mutex);
287 
288 	if (lscp_client_call(pClient, "GET AVAILABLE_AUDIO_OUTPUT_DRIVERS\r\n", 0) == LSCP_OK)
289 		iAudioDrivers = atoi(lscp_client_get_result(pClient));
290 
291 	// Unlock this section down.
292 	lscp_mutex_unlock(pClient->mutex);
293 
294 	return iAudioDrivers;
295 }
296 
297 
298 /**
299  *  Getting all available audio output drivers.
300  *  LIST AVAILABLE_AUDIO_OUTPUT_DRIVERS
301  *
302  *  @param pClient  Pointer to client instance structure.
303  *
304  *  @returns A NULL terminated array of audio output driver type
305  *  name strings, or NULL in case of failure.
306  */
lscp_list_available_audio_drivers(lscp_client_t * pClient)307 const char ** lscp_list_available_audio_drivers ( lscp_client_t *pClient )
308 {
309 	const char *pszSeps = ",";
310 
311 	if (pClient == NULL)
312 		return NULL;
313 
314 	// Lock this section up.
315 	lscp_mutex_lock(pClient->mutex);
316 
317 	if (pClient->audio_drivers) {
318 		lscp_szsplit_destroy(pClient->audio_drivers);
319 		pClient->audio_drivers = NULL;
320 	}
321 
322 	if (lscp_client_call(pClient, "LIST AVAILABLE_AUDIO_OUTPUT_DRIVERS\r\n", 0) == LSCP_OK)
323 		pClient->audio_drivers = lscp_szsplit_create(lscp_client_get_result(pClient), pszSeps);
324 
325 	// Unlock this section down.
326 	lscp_mutex_unlock(pClient->mutex);
327 
328 	return (const char **) pClient->audio_drivers;
329 }
330 
331 
332 /**
333  *  Getting informations about a specific audio output driver.
334  *  GET AUDIO_OUTPUT_DRIVER INFO <audio-output-type>
335  *
336  *  @param pClient          Pointer to client instance structure.
337  *  @param pszAudioDriver   Audio driver type string (e.g. "ALSA").
338  *
339  *  @returns A pointer to a @ref lscp_driver_info_t structure, with
340  *  the given audio driver information, or NULL in case of failure.
341  */
lscp_get_audio_driver_info(lscp_client_t * pClient,const char * pszAudioDriver)342 lscp_driver_info_t* lscp_get_audio_driver_info ( lscp_client_t *pClient, const char *pszAudioDriver )
343 {
344 	char szQuery[LSCP_BUFSIZ];
345 
346 	if (pszAudioDriver == NULL)
347 		return NULL;
348 
349 	sprintf(szQuery, "GET AUDIO_OUTPUT_DRIVER INFO %s\r\n", pszAudioDriver);
350 	return _lscp_driver_info_query(pClient, &(pClient->audio_driver_info), szQuery);
351 }
352 
353 
354 /**
355  *  Getting informations about specific audio output driver parameter.
356  *  GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO <audio-output-driver> <param> [<dep-list>]
357  *
358  *  @param pClient          Pointer to client instance structure.
359  *  @param pszAudioDriver   Audio driver type string (e.g. "ALSA").
360  *  @param pszParam         Audio driver parameter name.
361  *  @param pDepList         Pointer to specific dependencies parameter list.
362  *
363  *  @returns A pointer to a @ref lscp_param_info_t structure, with
364  *  the given audio driver parameter information, or NULL in case of failure.
365  */
lscp_get_audio_driver_param_info(lscp_client_t * pClient,const char * pszAudioDriver,const char * pszParam,lscp_param_t * pDepList)366 lscp_param_info_t *lscp_get_audio_driver_param_info ( lscp_client_t *pClient, const char *pszAudioDriver, const char *pszParam, lscp_param_t *pDepList )
367 {
368 	char szQuery[LSCP_BUFSIZ];
369 
370 	if (pClient == NULL)
371 		return NULL;
372 	if (pszAudioDriver == NULL)
373 		return NULL;
374 	if (pszParam == NULL)
375 		return NULL;
376 
377 	sprintf(szQuery, "GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO %s %s", pszAudioDriver, pszParam);
378 	return _lscp_param_info_query(pClient, &(pClient->audio_param_info), szQuery, sizeof(szQuery), pDepList);
379 }
380 
381 
382 //-------------------------------------------------------------------------
383 // Audio device control functions.
384 
385 /**
386  *  Creating an audio output device.
387  *  CREATE AUDIO_OUTPUT_DEVICE <audio-output-driver> [<params>]
388  *
389  *  @param pClient          Pointer to client instance structure.
390  *  @param pszAudioDriver   Audio driver type string (e.g. "ALSA").
391  *  @param pParams          Pointer to specific parameter list.
392  *
393  *  @returns The new audio device number identifier on success,
394  *  or -1 in case of failure.
395  */
lscp_create_audio_device(lscp_client_t * pClient,const char * pszAudioDriver,lscp_param_t * pParams)396 int lscp_create_audio_device ( lscp_client_t *pClient, const char *pszAudioDriver, lscp_param_t *pParams )
397 {
398 	char szQuery[LSCP_BUFSIZ];
399 	int iAudioDevice = -1;
400 
401 	if (pClient == NULL)
402 		return -1;
403 	if (pszAudioDriver == NULL)
404 		return -1;
405 
406 	// Lock this section up.
407 	lscp_mutex_lock(pClient->mutex);
408 
409 	sprintf(szQuery, "CREATE AUDIO_OUTPUT_DEVICE %s", pszAudioDriver);
410 	lscp_param_concat(szQuery, sizeof(szQuery), pParams);
411 	if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK)
412 		iAudioDevice = atoi(lscp_client_get_result(pClient));
413 
414 	// Unlock this section down.
415 	lscp_mutex_unlock(pClient->mutex);
416 
417 	return iAudioDevice;
418 }
419 
420 
421 /**
422  *  Destroying an audio output device.
423  *  DESTROY AUDIO_OUTPUT_DEVICE <audio-device-id>
424  *
425  *  @param pClient      Pointer to client instance structure.
426  *  @param iAudioDevice Audio device number identifier.
427  *
428  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
429  */
lscp_destroy_audio_device(lscp_client_t * pClient,int iAudioDevice)430 lscp_status_t lscp_destroy_audio_device ( lscp_client_t *pClient, int iAudioDevice )
431 {
432 	lscp_status_t ret = LSCP_FAILED;
433 	char szQuery[LSCP_BUFSIZ];
434 
435 	if (pClient == NULL)
436 		return ret;
437 	if (iAudioDevice < 0)
438 		return ret;
439 
440 	sprintf(szQuery, "DESTROY AUDIO_OUTPUT_DEVICE %d\r\n", iAudioDevice);
441 	return lscp_client_query(pClient, szQuery);
442 }
443 
444 
445 /**
446  *  Getting all created audio output device count.
447  *  GET AUDIO_OUTPUT_DEVICES
448  *
449  *  @param pClient  Pointer to client instance structure.
450  *
451  *  @returns The current total number of audio devices on success,
452  *  -1 otherwise.
453  */
lscp_get_audio_devices(lscp_client_t * pClient)454 int lscp_get_audio_devices ( lscp_client_t *pClient )
455 {
456 	int iAudioDevices = -1;
457 
458 	if (pClient == NULL)
459 		return -1;
460 
461 	// Lock this section up.
462 	lscp_mutex_lock(pClient->mutex);
463 
464 	if (lscp_client_call(pClient, "GET AUDIO_OUTPUT_DEVICES\r\n", 0) == LSCP_OK)
465 		iAudioDevices = atoi(lscp_client_get_result(pClient));
466 
467 	// Unlock this section down.
468 	lscp_mutex_unlock(pClient->mutex);
469 
470 	return iAudioDevices;
471 }
472 
473 
474 /**
475  *  Getting all created audio output device list.
476  *  LIST AUDIO_OUTPUT_DEVICES
477  *
478  *  @param pClient  Pointer to client instance structure.
479  *
480  *  @returns An array of audio device number identifiers,
481  *  terminated with -1 on success, or NULL in case of failure.
482  */
lscp_list_audio_devices(lscp_client_t * pClient)483 int *lscp_list_audio_devices ( lscp_client_t *pClient )
484 {
485 	const char *pszSeps = ",";
486 
487 	if (pClient == NULL)
488 		return NULL;
489 
490 	// Lock this section up.
491 	lscp_mutex_lock(pClient->mutex);
492 
493 	if (pClient->audio_devices) {
494 		lscp_isplit_destroy(pClient->audio_devices);
495 		pClient->audio_devices = NULL;
496 	}
497 
498 	if (lscp_client_call(pClient, "LIST AUDIO_OUTPUT_DEVICES\r\n", 0) == LSCP_OK)
499 		pClient->audio_devices = lscp_isplit_create(lscp_client_get_result(pClient), pszSeps);
500 
501 	// Unlock this section down.
502 	lscp_mutex_unlock(pClient->mutex);
503 
504 	return pClient->audio_devices;
505 }
506 
507 
508 /**
509  *  Getting current settings of an audio output device.
510  *  GET AUDIO_OUTPUT_DEVICE INFO <audio-device-id>
511  *
512  *  @param pClient      Pointer to client instance structure.
513  *  @param iAudioDevice Audio device number identifier.
514  *
515  *  @returns A pointer to a @ref lscp_device_info_t structure, with
516  *  the given audio device information, or NULL in case of failure.
517  */
lscp_get_audio_device_info(lscp_client_t * pClient,int iAudioDevice)518 lscp_device_info_t *lscp_get_audio_device_info ( lscp_client_t *pClient, int iAudioDevice )
519 {
520 	char szQuery[LSCP_BUFSIZ];
521 
522 	if (pClient == NULL)
523 		return NULL;
524 	if (iAudioDevice < 0)
525 		return NULL;
526 
527 	sprintf(szQuery, "GET AUDIO_OUTPUT_DEVICE INFO %d\r\n", iAudioDevice);
528 	return _lscp_device_info_query(pClient, &(pClient->audio_device_info), szQuery);
529 }
530 
531 
532 /**
533  *  Changing settings of audio output devices.
534  *  SET AUDIO_OUTPUT_DEVICE_PARAMETER <audio-device-id> <param>=<value>
535  *
536  *  @param pClient      Pointer to client instance structure.
537  *  @param iAudioDevice Audio device number identifier.
538  *  @param pParam       Pointer to a key-valued audio device parameter.
539  *
540  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
541  */
lscp_set_audio_device_param(lscp_client_t * pClient,int iAudioDevice,lscp_param_t * pParam)542 lscp_status_t lscp_set_audio_device_param ( lscp_client_t *pClient, int iAudioDevice, lscp_param_t *pParam )
543 {
544 	char szQuery[LSCP_BUFSIZ];
545 
546 	if (pClient == NULL)
547 		return LSCP_FAILED;
548 	if (iAudioDevice < 0)
549 		return LSCP_FAILED;
550 	if (pParam == NULL)
551 		return LSCP_FAILED;
552 
553 	sprintf(szQuery, "SET AUDIO_OUTPUT_DEVICE_PARAMETER %d %s='%s'\r\n", iAudioDevice, pParam->key, pParam->value);
554 	return lscp_client_query(pClient, szQuery);
555 }
556 
557 
558 /**
559  *  Getting informations about an audio channel.
560  *  GET AUDIO_OUTPUT_CHANNEL INFO <audio-device-id> <audio-channel>
561  *
562  *  @param pClient          Pointer to client instance structure.
563  *  @param iAudioDevice     Audio device number identifier.
564  *  @param iAudioChannel    Audio channel number.
565  *
566  *  @returns A pointer to a @ref lscp_device_port_info_t structure,
567  *  with the given audio channel information, or NULL in case of failure.
568  */
lscp_get_audio_channel_info(lscp_client_t * pClient,int iAudioDevice,int iAudioChannel)569 lscp_device_port_info_t* lscp_get_audio_channel_info ( lscp_client_t *pClient, int iAudioDevice, int iAudioChannel )
570 {
571 	char szQuery[LSCP_BUFSIZ];
572 
573 	if (pClient == NULL)
574 		return NULL;
575 	if (iAudioDevice < 0)
576 		return NULL;
577 	if (iAudioChannel < 0)
578 		return NULL;
579 
580 	sprintf(szQuery, "GET AUDIO_OUTPUT_CHANNEL INFO %d %d\r\n", iAudioDevice, iAudioChannel);
581 	return _lscp_device_port_info_query(pClient, &(pClient->audio_channel_info), szQuery);
582 }
583 
584 
585 /**
586  *  Getting informations about specific audio channel parameter.
587  *  GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO <audio-device-id> <audio-channel> <param>
588  *
589  *  @param pClient          Pointer to client instance structure.
590  *  @param iAudioDevice     Audio device number identifier.
591  *  @param iAudioChannel    Audio channel number.
592  *  @param pszParam         Audio channel parameter name.
593  *
594  *  @returns A pointer to a @ref lscp_param_info_t structure, with
595  *  the given audio channel parameter information, or NULL in case of failure.
596  */
lscp_get_audio_channel_param_info(lscp_client_t * pClient,int iAudioDevice,int iAudioChannel,const char * pszParam)597 lscp_param_info_t* lscp_get_audio_channel_param_info ( lscp_client_t *pClient, int iAudioDevice, int iAudioChannel, const char *pszParam )
598 {
599 	char szQuery[LSCP_BUFSIZ];
600 
601 	if (pClient == NULL)
602 		return NULL;
603 	if (iAudioDevice < 0)
604 		return NULL;
605 	if (iAudioChannel < 0)
606 		return NULL;
607 	if (pszParam == NULL)
608 		return NULL;
609 
610 	sprintf(szQuery, "GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO %d %d %s", iAudioDevice, iAudioChannel, pszParam);
611 	return _lscp_param_info_query(pClient, &(pClient->audio_channel_param_info), szQuery, sizeof(szQuery), NULL);
612 }
613 
614 
615 /**
616  *  Changing settings of audio output channels.
617  *  SET AUDIO_OUTPUT_CHANNEL_PARAMETER <audio-device-id> <audio-channel> <param> <value>
618  *
619  *  @param pClient          Pointer to client instance structure.
620  *  @param iAudioDevice     Audio device number identifier.
621  *  @param iAudioChannel    Audio channel number.
622  *  @param pParam           Pointer to a key-valued audio channel parameter.
623  *
624  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
625  */
lscp_set_audio_channel_param(lscp_client_t * pClient,int iAudioDevice,int iAudioChannel,lscp_param_t * pParam)626 lscp_status_t lscp_set_audio_channel_param ( lscp_client_t *pClient, int iAudioDevice, int iAudioChannel, lscp_param_t *pParam )
627 {
628 	char szQuery[LSCP_BUFSIZ];
629 
630 	if (pClient == NULL)
631 		return LSCP_FAILED;
632 	if (iAudioDevice < 0)
633 		return LSCP_FAILED;
634 	if (iAudioChannel < 0)
635 		return LSCP_FAILED;
636 	if (pParam == NULL)
637 		return LSCP_FAILED;
638 
639 	sprintf(szQuery, "SET AUDIO_OUTPUT_CHANNEL_PARAMETER %d %d %s='%s'\r\n", iAudioDevice, iAudioChannel, pParam->key, pParam->value);
640 	return lscp_client_query(pClient, szQuery);
641 }
642 
643 
644 //-------------------------------------------------------------------------
645 // MIDI driver control functions.
646 
647 /**
648  *  Getting all available MIDI input driver count.
649  *  GET AVAILABLE_MIDI_INPUT_DRIVERS
650  *
651  *  @param pClient  Pointer to client instance structure.
652  *
653  *  @returns The current total number of MIDI input drivers on success,
654  *  -1 otherwise.
655  */
lscp_get_available_midi_drivers(lscp_client_t * pClient)656 int lscp_get_available_midi_drivers ( lscp_client_t *pClient )
657 {
658 	int iMidiDrivers = -1;
659 
660 	if (pClient == NULL)
661 		return -1;
662 
663 	// Lock this section up.
664 	lscp_mutex_lock(pClient->mutex);
665 
666 	if (lscp_client_call(pClient, "GET AVAILABLE_MIDI_INPUT_DRIVERS\r\n", 0) == LSCP_OK)
667 		iMidiDrivers = atoi(lscp_client_get_result(pClient));
668 
669 	// Unlock this section up.
670 	lscp_mutex_unlock(pClient->mutex);
671 
672 	return iMidiDrivers;
673 }
674 
675 
676 /**
677  *  Getting all available MIDI input drivers.
678  *  LIST AVAILABLE_MIDI_INPUT_DRIVERS
679  *
680  *  @param pClient  Pointer to client instance structure.
681  *
682  *  @returns A NULL terminated array of MIDI input driver type
683  *  name strings, or NULL in case of failure.
684  */
lscp_list_available_midi_drivers(lscp_client_t * pClient)685 const char** lscp_list_available_midi_drivers ( lscp_client_t *pClient )
686 {
687 	const char *pszSeps = ",";
688 
689 	if (pClient == NULL)
690 		return NULL;
691 
692 	// Lock this section up.
693 	lscp_mutex_lock(pClient->mutex);
694 
695 	if (pClient->midi_drivers) {
696 		lscp_szsplit_destroy(pClient->midi_drivers);
697 		pClient->midi_drivers = NULL;
698 	}
699 
700 	if (lscp_client_call(pClient, "LIST AVAILABLE_MIDI_INPUT_DRIVERS\r\n", 0) == LSCP_OK)
701 		pClient->midi_drivers = lscp_szsplit_create(lscp_client_get_result(pClient), pszSeps);
702 
703 	// Unlock this section up.
704 	lscp_mutex_unlock(pClient->mutex);
705 
706 	return (const char **) pClient->midi_drivers;
707 }
708 
709 
710 /**
711  *  Getting informations about a specific MIDI input driver.
712  *  GET MIDI_INPUT_DRIVER INFO <midi-input-type>
713  *
714  *  @param pClient          Pointer to client instance structure.
715  *  @param pszMidiDriver    MIDI driver type string (e.g. "ALSA").
716  *
717  *  @returns A pointer to a @ref lscp_driver_info_t structure, with
718  *  the given MIDI driver information, or NULL in case of failure.
719  */
lscp_get_midi_driver_info(lscp_client_t * pClient,const char * pszMidiDriver)720 lscp_driver_info_t* lscp_get_midi_driver_info ( lscp_client_t *pClient, const char *pszMidiDriver )
721 {
722 	char szQuery[LSCP_BUFSIZ];
723 
724 	if (pszMidiDriver == NULL)
725 		return NULL;
726 
727 	sprintf(szQuery, "GET MIDI_INPUT_DRIVER INFO %s\r\n", pszMidiDriver);
728 	return _lscp_driver_info_query(pClient, &(pClient->midi_driver_info), szQuery);
729 }
730 
731 
732 /**
733  *  Getting informations about specific MIDI input driver parameter.
734  *  GET MIDI_INPUT_DRIVER_PARAMETER INFO <midi-input-driver> <param> [<dep-list>]
735  *
736  *  @param pClient          Pointer to client instance structure.
737  *  @param pszMidiDriver    MIDI driver type string (e.g. "ALSA").
738  *  @param pszParam         MIDI driver parameter name.
739  *  @param pDepList         Pointer to specific dependencies parameter list.
740  *
741  *  @returns A pointer to a @ref lscp_param_info_t structure, with
742  *  the given MIDI driver parameter information, or NULL in case of failure.
743  *
744  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
745  */
lscp_get_midi_driver_param_info(lscp_client_t * pClient,const char * pszMidiDriver,const char * pszParam,lscp_param_t * pDepList)746 lscp_param_info_t *lscp_get_midi_driver_param_info ( lscp_client_t *pClient, const char *pszMidiDriver, const char *pszParam, lscp_param_t *pDepList )
747 {
748 	char szQuery[LSCP_BUFSIZ];
749 
750 	if (pClient == NULL)
751 		return NULL;
752 	if (pszMidiDriver == NULL)
753 		return NULL;
754 	if (pszParam == NULL)
755 		return NULL;
756 
757 	sprintf(szQuery, "GET MIDI_INPUT_DRIVER_PARAMETER INFO %s %s", pszMidiDriver, pszParam);
758 	return _lscp_param_info_query(pClient, &(pClient->midi_param_info), szQuery, sizeof(szQuery), pDepList);
759 }
760 
761 
762 //-------------------------------------------------------------------------
763 // MIDI device control functions.
764 
765 /**
766  *  Creating a MIDI input device.
767  *  CREATE MIDI_INPUT_DEVICE <midi-input-driver> [<params>]
768  *
769  *  @param pClient          Pointer to client instance structure.
770  *  @param pszMidiDriver    MIDI driver type string (e.g. "ALSA").
771  *  @param pParams          Pointer to specific parameter list.
772  *
773  *  @returns The new audio device number identifier on success,
774  *  or -1 in case of failure.
775  */
lscp_create_midi_device(lscp_client_t * pClient,const char * pszMidiDriver,lscp_param_t * pParams)776 int lscp_create_midi_device ( lscp_client_t *pClient, const char *pszMidiDriver, lscp_param_t *pParams )
777 {
778 	char szQuery[LSCP_BUFSIZ];
779 	int iMidiDevice = -1;
780 
781 	if (pClient == NULL)
782 		return -1;
783 	if (pszMidiDriver == NULL)
784 		return -1;
785 
786 	// Lock this section up.
787 	lscp_mutex_lock(pClient->mutex);
788 
789 	sprintf(szQuery, "CREATE MIDI_INPUT_DEVICE %s", pszMidiDriver);
790 	lscp_param_concat(szQuery, sizeof(szQuery), pParams);
791 	if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK)
792 		iMidiDevice = atoi(lscp_client_get_result(pClient));
793 
794 	// Unlock this section down.
795 	lscp_mutex_unlock(pClient->mutex);
796 
797 	return iMidiDevice;
798 }
799 
800 
801 /**
802  *  Destroying a MIDI input device.
803  *  DESTROY MIDI_INPUT_DEVICE <midi-device-id>
804  *
805  *  @param pClient      Pointer to client instance structure.
806  *  @param iMidiDevice  MIDI device number identifier.
807  *
808  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
809  */
lscp_destroy_midi_device(lscp_client_t * pClient,int iMidiDevice)810 lscp_status_t lscp_destroy_midi_device ( lscp_client_t *pClient, int iMidiDevice )
811 {
812 	lscp_status_t ret = LSCP_FAILED;
813 	char szQuery[LSCP_BUFSIZ];
814 
815 	if (pClient == NULL)
816 		return ret;
817 	if (iMidiDevice < 0)
818 		return ret;
819 
820 	sprintf(szQuery, "DESTROY MIDI_INPUT_DEVICE %d\r\n", iMidiDevice);
821 	return lscp_client_query(pClient, szQuery);
822 }
823 
824 
825 /**
826  *  Getting all created MIDI intput device count.
827  *  GET MIDI_INPUT_DEVICES
828  *
829  *  @param pClient  Pointer to client instance structure.
830  *
831  *  @returns The current total number of MIDI devices on success,
832  *  -1 otherwise.
833  */
lscp_get_midi_devices(lscp_client_t * pClient)834 int lscp_get_midi_devices ( lscp_client_t *pClient )
835 {
836 	int iMidiDevices = -1;
837 
838 	if (pClient == NULL)
839 		return -1;
840 
841 	// Lock this section up.
842 	lscp_mutex_lock(pClient->mutex);
843 
844 	if (lscp_client_call(pClient, "GET MIDI_INPUT_DEVICES\r\n", 0) == LSCP_OK)
845 		iMidiDevices = atoi(lscp_client_get_result(pClient));
846 
847 	// Unlock this section down.
848 	lscp_mutex_unlock(pClient->mutex);
849 
850 	return iMidiDevices;
851 }
852 
853 
854 /**
855  *  Getting all created MIDI intput device list.
856  *  LIST MIDI_INPUT_DEVICES
857  *
858  *  @param pClient  Pointer to client instance structure.
859  *
860  *  @returns An array of MIDI device number identifiers,
861  *  terminated with -1 on success, or NULL in case of failure.
862  */
lscp_list_midi_devices(lscp_client_t * pClient)863 int *lscp_list_midi_devices ( lscp_client_t *pClient )
864 {
865 	const char *pszSeps = ",";
866 
867 	if (pClient == NULL)
868 		return NULL;
869 
870 	// Lock this section up.
871 	lscp_mutex_lock(pClient->mutex);
872 
873 	if (pClient->midi_devices) {
874 		lscp_isplit_destroy(pClient->midi_devices);
875 		pClient->midi_devices = NULL;
876 	}
877 
878 	if (lscp_client_call(pClient, "LIST MIDI_INPUT_DEVICES\r\n", 0) == LSCP_OK)
879 		pClient->midi_devices = lscp_isplit_create(lscp_client_get_result(pClient), pszSeps);
880 
881 	// Unlock this section down.
882 	lscp_mutex_unlock(pClient->mutex);
883 
884 	return pClient->midi_devices;
885 }
886 
887 
888 /**
889  *  Getting current settings of a MIDI input device.
890  *  GET MIDI_INPUT_DEVICE INFO <midi-device-id>
891  *
892  *  @param pClient      Pointer to client instance structure.
893  *  @param iMidiDevice  MIDI device number identifier.
894  *
895  *  @returns A pointer to a @ref lscp_device_info_t structure, with
896  *  the given MIDI device information, or NULL in case of failure.
897  */
lscp_get_midi_device_info(lscp_client_t * pClient,int iMidiDevice)898 lscp_device_info_t* lscp_get_midi_device_info ( lscp_client_t *pClient, int iMidiDevice )
899 {
900 	char szQuery[LSCP_BUFSIZ];
901 
902 	if (pClient == NULL)
903 		return NULL;
904 	if (iMidiDevice < 0)
905 		return NULL;
906 
907 	sprintf(szQuery, "GET MIDI_INPUT_DEVICE INFO %d\r\n", iMidiDevice);
908 	return _lscp_device_info_query(pClient, &(pClient->midi_device_info), szQuery);
909 }
910 
911 
912 /**
913  *  Changing settings of MIDI input devices.
914  *  SET MIDI_INPUT_DEVICE_PARAMETER <midi-device-id> <param>=<value>
915  *
916  *  @param pClient      Pointer to client instance structure.
917  *  @param iMidiDevice  MIDI device number identifier.
918  *  @param pParam       Pointer to a key-valued MIDI device parameter.
919  *
920  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
921  */
lscp_set_midi_device_param(lscp_client_t * pClient,int iMidiDevice,lscp_param_t * pParam)922 lscp_status_t lscp_set_midi_device_param ( lscp_client_t *pClient, int iMidiDevice, lscp_param_t *pParam )
923 {
924 	char szQuery[LSCP_BUFSIZ];
925 
926 	if (pClient == NULL)
927 		return LSCP_FAILED;
928 	if (iMidiDevice < 0)
929 		return LSCP_FAILED;
930 	if (pParam == NULL)
931 		return LSCP_FAILED;
932 
933 	sprintf(szQuery, "SET MIDI_INPUT_DEVICE_PARAMETER %d %s='%s'\r\n", iMidiDevice, pParam->key, pParam->value);
934 	return lscp_client_query(pClient, szQuery);
935 }
936 
937 
938 /**
939  *  Getting informations about a MIDI port.
940  *  GET MIDI_INPUT_PORT INFO <midi-device-id> <midi-port>
941  *
942  *  @param pClient      Pointer to client instance structure.
943  *  @param iMidiDevice  MIDI device number identifier.
944  *  @param iMidiPort    MIDI port number.
945  *
946  *  @returns A pointer to a @ref lscp_device_port_info_t structure,
947  *  with the given MIDI port information, or NULL in case of failure.
948  */
lscp_get_midi_port_info(lscp_client_t * pClient,int iMidiDevice,int iMidiPort)949 lscp_device_port_info_t* lscp_get_midi_port_info ( lscp_client_t *pClient, int iMidiDevice, int iMidiPort )
950 {
951 	char szQuery[LSCP_BUFSIZ];
952 
953 	if (pClient == NULL)
954 		return NULL;
955 	if (iMidiDevice < 0)
956 		return NULL;
957 	if (iMidiPort < 0)
958 		return NULL;
959 
960 	sprintf(szQuery, "GET MIDI_INPUT_PORT INFO %d %d\r\n", iMidiDevice, iMidiPort);
961 	return _lscp_device_port_info_query(pClient, &(pClient->midi_port_info), szQuery);
962 }
963 
964 
965 /**
966  *  Getting informations about specific MIDI port parameter.
967  *  GET MIDI_INPUT_PORT_PARAMETER INFO <midi-device-id> <midi-port> <param>
968  *
969  *  @param pClient      Pointer to client instance structure.
970  *  @param iMidiDevice  MIDI device number identifier.
971  *  @param iMidiPort    MIDI port number.
972  *  @param pszParam     MIDI port parameter name.
973  *
974  *  @returns A pointer to a @ref lscp_param_info_t structure, with
975  *  the given MIDI port parameter information, or NULL in case of failure.
976  */
lscp_get_midi_port_param_info(lscp_client_t * pClient,int iMidiDevice,int iMidiPort,const char * pszParam)977 lscp_param_info_t* lscp_get_midi_port_param_info ( lscp_client_t *pClient, int iMidiDevice, int iMidiPort, const char *pszParam )
978 {
979 	char szQuery[LSCP_BUFSIZ];
980 
981 	if (pClient == NULL)
982 		return NULL;
983 	if (iMidiDevice < 0)
984 		return NULL;
985 	if (iMidiPort < 0)
986 		return NULL;
987 	if (pszParam == NULL)
988 		return NULL;
989 
990 	sprintf(szQuery, "GET MIDI_INPUT_PORT_PARAMETER INFO %d %d %s", iMidiDevice, iMidiPort, pszParam);
991 	return _lscp_param_info_query(pClient, &(pClient->midi_port_param_info), szQuery, sizeof(szQuery), NULL);
992 }
993 
994 
995 /**
996  *  Changing settings of MIDI input ports.
997  *  SET MIDI_INPUT_PORT_PARAMETER <midi-device-id> <midi-port> <param> <value>
998  *
999  *  @param pClient      Pointer to client instance structure.
1000  *  @param iMidiDevice  MIDI device number identifier.
1001  *  @param iMidiPort    MIDI port number.
1002  *  @param pParam       Pointer to a key-valued MIDI port parameter.
1003  *
1004  *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
1005  */
lscp_set_midi_port_param(lscp_client_t * pClient,int iMidiDevice,int iMidiPort,lscp_param_t * pParam)1006 lscp_status_t lscp_set_midi_port_param ( lscp_client_t *pClient, int iMidiDevice, int iMidiPort, lscp_param_t *pParam )
1007 {
1008 	char szQuery[LSCP_BUFSIZ];
1009 
1010 	if (pClient == NULL)
1011 		return LSCP_FAILED;
1012 	if (iMidiDevice < 0)
1013 		return LSCP_FAILED;
1014 	if (iMidiPort < 0)
1015 		return LSCP_FAILED;
1016 	if (pParam == NULL)
1017 		return LSCP_FAILED;
1018 
1019 	sprintf(szQuery, "SET MIDI_INPUT_PORT_PARAMETER %d %d %s='%s'\r\n", iMidiDevice, iMidiPort, pParam->key, pParam->value);
1020 	return lscp_client_query(pClient, szQuery);
1021 }
1022 
1023 
1024 //-------------------------------------------------------------------------
1025 // Generic parameter list functions.
1026 
lscp_get_param_value(lscp_param_t * pParams,const char * pszParam)1027 const char *lscp_get_param_value ( lscp_param_t *pParams, const char *pszParam )
1028 {
1029 	int i;
1030 
1031 	for (i = 0; pParams && pParams[i].key; i++) {
1032 		if (strcasecmp(pParams[i].key, pszParam) == 0)
1033 			return (const char *) pParams[i].value;
1034 	}
1035 	return NULL;
1036 }
1037 
1038 
1039 // end of device.c
1040 
1041