1 /*
2  * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #define USE_ERROR
27 //#define USE_TRACE
28 
29 #include "Ports.h"
30 #include "PLATFORM_API_SolarisOS_Utils.h"
31 
32 #if USE_PORTS == TRUE
33 
34 #define MONITOR_GAIN_STRING "Monitor Gain"
35 
36 #define ALL_TARGET_PORT_COUNT 6
37 
38 // define the following to not use audio_prinfo_t.mod_ports
39 #define SOLARIS7_COMPATIBLE
40 
41 // Solaris audio defines
42 static int targetPorts[ALL_TARGET_PORT_COUNT] = {
43     AUDIO_SPEAKER,
44     AUDIO_HEADPHONE,
45     AUDIO_LINE_OUT,
46     AUDIO_AUX1_OUT,
47     AUDIO_AUX2_OUT,
48     AUDIO_SPDIF_OUT
49 };
50 
51 static char* targetPortNames[ALL_TARGET_PORT_COUNT] = {
52     "Speaker",
53     "Headphone",
54     "Line Out",
55     "AUX1 Out",
56     "AUX2 Out",
57     "SPDIF Out"
58 };
59 
60 // defined in Ports.h
61 static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = {
62     PORT_DST_SPEAKER,
63     PORT_DST_HEADPHONE,
64     PORT_DST_LINE_OUT,
65     PORT_DST_UNKNOWN,
66     PORT_DST_UNKNOWN,
67     PORT_DST_UNKNOWN,
68 };
69 
70 #define ALL_SOURCE_PORT_COUNT 7
71 
72 // Solaris audio defines
73 static int sourcePorts[ALL_SOURCE_PORT_COUNT] = {
74     AUDIO_MICROPHONE,
75     AUDIO_LINE_IN,
76     AUDIO_CD,
77     AUDIO_AUX1_IN,
78     AUDIO_AUX2_IN,
79     AUDIO_SPDIF_IN,
80     AUDIO_CODEC_LOOPB_IN
81 };
82 
83 static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = {
84     "Microphone In",
85     "Line In",
86     "Compact Disc In",
87     "AUX1 In",
88     "AUX2 In",
89     "SPDIF In",
90     "Internal Loopback"
91 };
92 
93 // Ports.h defines
94 static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = {
95     PORT_SRC_MICROPHONE,
96     PORT_SRC_LINE_IN,
97     PORT_SRC_COMPACT_DISC,
98     PORT_SRC_UNKNOWN,
99     PORT_SRC_UNKNOWN,
100     PORT_SRC_UNKNOWN,
101     PORT_SRC_UNKNOWN
102 };
103 
104 struct tag_PortControlID;
105 
106 typedef struct tag_PortInfo {
107     int fd;                    // file descriptor of the pseudo device
108     audio_info_t audioInfo;
109     // ports
110     int targetPortCount;
111     int sourcePortCount;
112     // indexes to sourcePorts/targetPorts
113     // contains first target ports, then source ports
114     int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT];
115     // controls
116     int maxControlCount;       // upper bound of number of controls
117     int usedControlIDs;        // number of items already filled in controlIDs
118     struct tag_PortControlID* controlIDs; // the control IDs themselves
119 } PortInfo;
120 
121 #define PORT_CONTROL_TYPE_PLAY          0x4000000
122 #define PORT_CONTROL_TYPE_RECORD        0x8000000
123 #define PORT_CONTROL_TYPE_SELECT_PORT   1
124 #define PORT_CONTROL_TYPE_GAIN          2
125 #define PORT_CONTROL_TYPE_BALANCE       3
126 #define PORT_CONTROL_TYPE_MONITOR_GAIN  10
127 #define PORT_CONTROL_TYPE_OUTPUT_MUTED  11
128 #define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD
129 #define PORT_CONTROL_TYPE_MASK 0xFFFFFF
130 
131 
132 typedef struct tag_PortControlID {
133     PortInfo*  portInfo;
134     INT32                 controlType;  // PORT_CONTROL_TYPE_XX
135     uint_t                port;
136 } PortControlID;
137 
138 
139 ///// implemented functions of Ports.h
140 
PORT_GetPortMixerCount()141 INT32 PORT_GetPortMixerCount() {
142     return (INT32) getAudioDeviceCount();
143 }
144 
145 
PORT_GetPortMixerDescription(INT32 mixerIndex,PortMixerDescription * description)146 INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
147     AudioDeviceDescription desc;
148 
149     if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
150         strncpy(description->name, desc.name, PORT_STRING_LENGTH-1);
151         description->name[PORT_STRING_LENGTH-1] = 0;
152         strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1);
153         description->vendor[PORT_STRING_LENGTH-1] = 0;
154         strncpy(description->version, desc.version, PORT_STRING_LENGTH-1);
155         description->version[PORT_STRING_LENGTH-1] = 0;
156         /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/
157         strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1);
158         description->description[PORT_STRING_LENGTH-1] = 0;
159         return TRUE;
160     }
161     return FALSE;
162 }
163 
164 
PORT_Open(INT32 mixerIndex)165 void* PORT_Open(INT32 mixerIndex) {
166     PortInfo* info = NULL;
167     int fd = -1;
168     AudioDeviceDescription desc;
169     int success = FALSE;
170 
171     TRACE0("PORT_Open\n");
172     if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
173         fd = open(desc.pathctl, O_RDWR);
174     }
175     if (fd < 0) {
176         ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
177         return NULL;
178     }
179 
180     info = (PortInfo*) malloc(sizeof(PortInfo));
181     if (info != NULL) {
182         memset(info, 0, sizeof(PortInfo));
183         info->fd = fd;
184         success = TRUE;
185     }
186     if (!success) {
187         if (fd >= 0) {
188             close(fd);
189         }
190         PORT_Close((void*) info);
191         info = NULL;
192     }
193     return info;
194 }
195 
PORT_Close(void * id)196 void PORT_Close(void* id) {
197     TRACE0("PORT_Close\n");
198     if (id != NULL) {
199         PortInfo* info = (PortInfo*) id;
200         if (info->fd >= 0) {
201             close(info->fd);
202             info->fd = -1;
203         }
204         if (info->controlIDs) {
205             free(info->controlIDs);
206             info->controlIDs = NULL;
207         }
208         free(info);
209     }
210 }
211 
212 
213 
PORT_GetPortCount(void * id)214 INT32 PORT_GetPortCount(void* id) {
215     int ret = 0;
216     PortInfo* info = (PortInfo*) id;
217     if (info != NULL) {
218         if (!info->targetPortCount && !info->sourcePortCount) {
219             int i;
220             AUDIO_INITINFO(&info->audioInfo);
221             if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) {
222                 for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) {
223                     if (info->audioInfo.play.avail_ports & targetPorts[i]) {
224                         info->ports[info->targetPortCount] = i;
225                         info->targetPortCount++;
226                     }
227 #ifdef SOLARIS7_COMPATIBLE
228                     TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i],
229                            info->audioInfo.play.avail_ports & targetPorts[i]);
230 #else
231                     TRACE4("Target %d %s: avail=%d  mod=%d\n", i, targetPortNames[i],
232                            info->audioInfo.play.avail_ports & targetPorts[i],
233                            info->audioInfo.play.mod_ports & targetPorts[i]);
234 #endif
235                 }
236                 for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) {
237                     if (info->audioInfo.record.avail_ports & sourcePorts[i]) {
238                         info->ports[info->targetPortCount + info->sourcePortCount] = i;
239                         info->sourcePortCount++;
240                     }
241 #ifdef SOLARIS7_COMPATIBLE
242                     TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i],
243                            info->audioInfo.record.avail_ports & sourcePorts[i]);
244 #else
245                     TRACE4("Source %d %s: avail=%d  mod=%d\n", i, sourcePortNames[i],
246                            info->audioInfo.record.avail_ports & sourcePorts[i],
247                            info->audioInfo.record.mod_ports & sourcePorts[i]);
248 #endif
249                 }
250             }
251         }
252         ret = info->targetPortCount + info->sourcePortCount;
253     }
254     return ret;
255 }
256 
isSourcePort(PortInfo * info,INT32 portIndex)257 int isSourcePort(PortInfo* info, INT32 portIndex) {
258     return (portIndex >= info->targetPortCount);
259 }
260 
PORT_GetPortType(void * id,INT32 portIndex)261 INT32 PORT_GetPortType(void* id, INT32 portIndex) {
262     PortInfo* info = (PortInfo*) id;
263     if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
264         if (isSourcePort(info, portIndex)) {
265             return sourcePortJavaSoundMapping[info->ports[portIndex]];
266         } else {
267             return targetPortJavaSoundMapping[info->ports[portIndex]];
268         }
269     }
270     return 0;
271 }
272 
273 // pre-condition: portIndex must have been verified!
getPortName(PortInfo * info,INT32 portIndex)274 char* getPortName(PortInfo* info, INT32 portIndex) {
275     char* ret = NULL;
276 
277     if (isSourcePort(info, portIndex)) {
278         ret = sourcePortNames[info->ports[portIndex]];
279     } else {
280         ret = targetPortNames[info->ports[portIndex]];
281     }
282     return ret;
283 }
284 
PORT_GetPortName(void * id,INT32 portIndex,char * name,INT32 len)285 INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
286     PortInfo* info = (PortInfo*) id;
287     char* n;
288 
289     if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
290         n = getPortName(info, portIndex);
291         if (n) {
292             strncpy(name, n, len-1);
293             name[len-1] = 0;
294             return TRUE;
295         }
296     }
297     return FALSE;
298 }
299 
createPortControl(PortInfo * info,PortControlCreator * creator,INT32 portIndex,INT32 type,void ** controlObjects,int * controlCount)300 void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex,
301                        INT32 type, void** controlObjects, int* controlCount) {
302     PortControlID* controlID;
303     void* newControl = NULL;
304     int controlIndex;
305     char* jsType = NULL;
306     int isBoolean = FALSE;
307 
308     TRACE0(">createPortControl\n");
309 
310     // fill the ControlID structure and add this control
311     if (info->usedControlIDs >= info->maxControlCount) {
312         ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
313         return;
314     }
315     controlID = &(info->controlIDs[info->usedControlIDs]);
316     controlID->portInfo = info;
317     controlID->controlType = type;
318     controlIndex = info->ports[portIndex];
319     if (isSourcePort(info, portIndex)) {
320         controlID->port = sourcePorts[controlIndex];
321     } else {
322         controlID->port = targetPorts[controlIndex];
323     }
324     switch (type & PORT_CONTROL_TYPE_MASK) {
325     case PORT_CONTROL_TYPE_SELECT_PORT:
326         jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break;
327     case PORT_CONTROL_TYPE_GAIN:
328         jsType = CONTROL_TYPE_VOLUME;  break;
329     case PORT_CONTROL_TYPE_BALANCE:
330         jsType = CONTROL_TYPE_BALANCE; break;
331     case PORT_CONTROL_TYPE_MONITOR_GAIN:
332         jsType = CONTROL_TYPE_VOLUME; break;
333     case PORT_CONTROL_TYPE_OUTPUT_MUTED:
334         jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break;
335     }
336     if (isBoolean) {
337         TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
338         newControl = (creator->newBooleanControl)(creator, controlID, jsType);
339     }
340     else if (jsType == CONTROL_TYPE_BALANCE) {
341         TRACE0(" PORT_CONTROL_TYPE_BALANCE\n");
342         newControl = (creator->newFloatControl)(creator, controlID, jsType,
343                                                 -1.0f, 1.0f, 2.0f / 65.0f, "");
344     } else {
345         TRACE0(" PORT_CONTROL_TYPE_FLOAT\n");
346         newControl = (creator->newFloatControl)(creator, controlID, jsType,
347                                                 0.0f, 1.0f, 1.0f / 256.0f, "");
348     }
349     if (newControl) {
350         controlObjects[*controlCount] = newControl;
351         (*controlCount)++;
352         info->usedControlIDs++;
353     }
354     TRACE0("<createPortControl\n");
355 }
356 
357 
addCompoundControl(PortInfo * info,PortControlCreator * creator,char * name,void ** controlObjects,int * controlCount)358 void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
359     void* compControl;
360 
361     TRACE1(">addCompoundControl %d controls\n", *controlCount);
362     if (*controlCount) {
363         // create compound control and add it to the vector
364         compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount);
365         if (compControl) {
366             TRACE1(" addCompoundControl: calling addControl %p\n", compControl);
367             (creator->addControl)(creator, compControl);
368         }
369         *controlCount = 0;
370     }
371     TRACE0("<addCompoundControl\n");
372 }
373 
addAllControls(PortInfo * info,PortControlCreator * creator,void ** controlObjects,int * controlCount)374 void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
375     int i = 0;
376 
377     TRACE0(">addAllControl\n");
378     // go through all controls and add them to the vector
379     for (i = 0; i < *controlCount; i++) {
380         (creator->addControl)(creator, controlObjects[i]);
381     }
382     *controlCount = 0;
383     TRACE0("<addAllControl\n");
384 }
385 
PORT_GetControls(void * id,INT32 portIndex,PortControlCreator * creator)386 void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
387     PortInfo* info = (PortInfo*) id;
388     int portCount = PORT_GetPortCount(id);
389     void* controls[4];
390     int controlCount = 0;
391     INT32 type;
392     int selectable = 1;
393 
394     TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n",
395            id, portIndex, info->controlIDs, info->maxControlCount);
396     if ((portIndex >= 0) && (portIndex < portCount)) {
397         // if the memory isn't reserved for the control structures, allocate it
398         if (!info->controlIDs) {
399             int maxCount = 0;
400             TRACE0("getControl: allocate mem\n");
401             // get a maximum number of controls:
402             // each port has a select, balance, and volume control.
403             maxCount = 3 * portCount;
404             // then there is monitorGain and outputMuted
405             maxCount += (2 * info->targetPortCount);
406             info->maxControlCount = maxCount;
407             info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount);
408         }
409         if (!isSourcePort(info, portIndex)) {
410             type = PORT_CONTROL_TYPE_PLAY;
411             // add master mute control
412             createPortControl(info, creator, portIndex,
413                               type | PORT_CONTROL_TYPE_OUTPUT_MUTED,
414                               controls, &controlCount);
415             addAllControls(info, creator, controls, &controlCount);
416 #ifdef SOLARIS7_COMPATIBLE
417             selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]];
418 #else
419             selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]];
420 #endif
421         } else {
422             type = PORT_CONTROL_TYPE_RECORD;
423 #ifdef SOLARIS7_COMPATIBLE
424             selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]];
425 #else
426             selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]];
427 #endif
428         }
429         // add a mixer strip with volume, ...
430         createPortControl(info, creator, portIndex,
431                           type | PORT_CONTROL_TYPE_GAIN,
432                           controls, &controlCount);
433         // ... balance, ...
434         createPortControl(info, creator, portIndex,
435                           type | PORT_CONTROL_TYPE_BALANCE,
436                           controls, &controlCount);
437         // ... and select control (if not always on)...
438         if (selectable) {
439             createPortControl(info, creator, portIndex,
440                               type | PORT_CONTROL_TYPE_SELECT_PORT,
441                               controls, &controlCount);
442         }
443         // ... packaged in a compound control.
444         addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount);
445 
446         if (type == PORT_CONTROL_TYPE_PLAY) {
447             // add a single strip for source ports with monitor gain
448             createPortControl(info, creator, portIndex,
449                               type | PORT_CONTROL_TYPE_MONITOR_GAIN,
450                               controls, &controlCount);
451             // also in a compound control
452             addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount);
453         }
454     }
455     TRACE0("< PORT_getControls\n");
456 }
457 
PORT_GetIntValue(void * controlIDV)458 INT32 PORT_GetIntValue(void* controlIDV) {
459     PortControlID* controlID = (PortControlID*) controlIDV;
460     audio_info_t audioInfo;
461     audio_prinfo_t* prinfo;
462 
463     AUDIO_INITINFO(&audioInfo);
464     if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
465         if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
466             prinfo = &(audioInfo.play);
467         } else {
468             prinfo = &(audioInfo.record);
469         }
470         switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
471         case PORT_CONTROL_TYPE_SELECT_PORT:
472             return (prinfo->port & controlID->port)?TRUE:FALSE;
473         case PORT_CONTROL_TYPE_OUTPUT_MUTED:
474             return (audioInfo.output_muted)?TRUE:FALSE;
475         default:
476             ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
477         }
478     }
479     ERROR0("PORT_GetIntValue: Could not ioctl!\n");
480     return 0;
481 }
482 
PORT_SetIntValue(void * controlIDV,INT32 value)483 void PORT_SetIntValue(void* controlIDV, INT32 value) {
484     PortControlID* controlID = (PortControlID*) controlIDV;
485     audio_info_t audioInfo;
486     audio_prinfo_t* prinfo;
487     int setPort;
488 
489     if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
490         prinfo = &(audioInfo.play);
491     } else {
492         prinfo = &(audioInfo.record);
493     }
494     switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
495     case PORT_CONTROL_TYPE_SELECT_PORT:
496         // first try to just add this port. if that fails, set ONLY to this port.
497         AUDIO_INITINFO(&audioInfo);
498         if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
499             if (value) {
500                 setPort = (prinfo->port | controlID->port);
501             } else {
502                 setPort = (prinfo->port - controlID->port);
503             }
504             AUDIO_INITINFO(&audioInfo);
505             prinfo->port = setPort;
506             if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
507                 // didn't work. Either this line doesn't support to select several
508                 // ports at once (e.g. record), or a real error
509                 if (value) {
510                     // set to ONLY this port (and disable any other currently selected ports)
511                     AUDIO_INITINFO(&audioInfo);
512                     prinfo->port = controlID->port;
513                     if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
514                         ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port);
515                     }
516                 } else {
517                     // assume it's an error
518                     ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort);
519                 }
520             }
521             break;
522         case PORT_CONTROL_TYPE_OUTPUT_MUTED:
523             AUDIO_INITINFO(&audioInfo);
524             audioInfo.output_muted = (value?TRUE:FALSE);
525             if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
526                 ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value);
527             }
528             break;
529         default:
530             ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
531         }
532     }
533 }
534 
PORT_GetFloatValue(void * controlIDV)535 float PORT_GetFloatValue(void* controlIDV) {
536     PortControlID* controlID = (PortControlID*) controlIDV;
537     audio_info_t audioInfo;
538     audio_prinfo_t* prinfo;
539 
540     AUDIO_INITINFO(&audioInfo);
541     if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
542         if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
543             prinfo = &(audioInfo.play);
544         } else {
545             prinfo = &(audioInfo.record);
546         }
547         switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
548         case PORT_CONTROL_TYPE_GAIN:
549             return ((float) (prinfo->gain - AUDIO_MIN_GAIN))
550                 / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
551         case PORT_CONTROL_TYPE_BALANCE:
552             return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1))
553                 / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE));
554         case PORT_CONTROL_TYPE_MONITOR_GAIN:
555             return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN))
556                 / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
557         default:
558             ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
559         }
560     }
561     ERROR0("PORT_GetFloatValue: Could not ioctl!\n");
562     return 0.0f;
563 }
564 
PORT_SetFloatValue(void * controlIDV,float value)565 void PORT_SetFloatValue(void* controlIDV, float value) {
566     PortControlID* controlID = (PortControlID*) controlIDV;
567     audio_info_t audioInfo;
568     audio_prinfo_t* prinfo;
569 
570     AUDIO_INITINFO(&audioInfo);
571 
572     if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
573         prinfo = &(audioInfo.play);
574     } else {
575         prinfo = &(audioInfo.record);
576     }
577     switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
578     case PORT_CONTROL_TYPE_GAIN:
579         prinfo->gain = AUDIO_MIN_GAIN
580             + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
581         break;
582     case PORT_CONTROL_TYPE_BALANCE:
583         prinfo->balance =  AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE
584             + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f);
585         break;
586     case PORT_CONTROL_TYPE_MONITOR_GAIN:
587         audioInfo.monitor_gain = AUDIO_MIN_GAIN
588             + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
589         break;
590     default:
591         ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
592         return;
593     }
594     if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
595         ERROR0("PORT_SetFloatValue: Could not ioctl!\n");
596     }
597 }
598 
599 #endif // USE_PORTS
600