1 /*
2  * Copyright (c) 2002, 2016, 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     memset(controls, 0, sizeof(controls));
394 
395     TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n",
396            id, portIndex, info->controlIDs, info->maxControlCount);
397     if ((portIndex >= 0) && (portIndex < portCount)) {
398         // if the memory isn't reserved for the control structures, allocate it
399         if (!info->controlIDs) {
400             int maxCount = 0;
401             TRACE0("getControl: allocate mem\n");
402             // get a maximum number of controls:
403             // each port has a select, balance, and volume control.
404             maxCount = 3 * portCount;
405             // then there is monitorGain and outputMuted
406             maxCount += (2 * info->targetPortCount);
407             info->maxControlCount = maxCount;
408             info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount);
409         }
410         if (!isSourcePort(info, portIndex)) {
411             type = PORT_CONTROL_TYPE_PLAY;
412             // add master mute control
413             createPortControl(info, creator, portIndex,
414                               type | PORT_CONTROL_TYPE_OUTPUT_MUTED,
415                               controls, &controlCount);
416             addAllControls(info, creator, controls, &controlCount);
417 #ifdef SOLARIS7_COMPATIBLE
418             selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]];
419 #else
420             selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]];
421 #endif
422         } else {
423             type = PORT_CONTROL_TYPE_RECORD;
424 #ifdef SOLARIS7_COMPATIBLE
425             selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]];
426 #else
427             selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]];
428 #endif
429         }
430         // add a mixer strip with volume, ...
431         createPortControl(info, creator, portIndex,
432                           type | PORT_CONTROL_TYPE_GAIN,
433                           controls, &controlCount);
434         // ... balance, ...
435         createPortControl(info, creator, portIndex,
436                           type | PORT_CONTROL_TYPE_BALANCE,
437                           controls, &controlCount);
438         // ... and select control (if not always on)...
439         if (selectable) {
440             createPortControl(info, creator, portIndex,
441                               type | PORT_CONTROL_TYPE_SELECT_PORT,
442                               controls, &controlCount);
443         }
444         // ... packaged in a compound control.
445         addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount);
446 
447         if (type == PORT_CONTROL_TYPE_PLAY) {
448             // add a single strip for source ports with monitor gain
449             createPortControl(info, creator, portIndex,
450                               type | PORT_CONTROL_TYPE_MONITOR_GAIN,
451                               controls, &controlCount);
452             // also in a compound control
453             addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount);
454         }
455     }
456     TRACE0("< PORT_getControls\n");
457 }
458 
PORT_GetIntValue(void * controlIDV)459 INT32 PORT_GetIntValue(void* controlIDV) {
460     PortControlID* controlID = (PortControlID*) controlIDV;
461     audio_info_t audioInfo;
462     audio_prinfo_t* prinfo;
463 
464     AUDIO_INITINFO(&audioInfo);
465     if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
466         if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
467             prinfo = &(audioInfo.play);
468         } else {
469             prinfo = &(audioInfo.record);
470         }
471         switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
472         case PORT_CONTROL_TYPE_SELECT_PORT:
473             return (prinfo->port & controlID->port)?TRUE:FALSE;
474         case PORT_CONTROL_TYPE_OUTPUT_MUTED:
475             return (audioInfo.output_muted)?TRUE:FALSE;
476         default:
477             ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
478         }
479     }
480     ERROR0("PORT_GetIntValue: Could not ioctl!\n");
481     return 0;
482 }
483 
PORT_SetIntValue(void * controlIDV,INT32 value)484 void PORT_SetIntValue(void* controlIDV, INT32 value) {
485     PortControlID* controlID = (PortControlID*) controlIDV;
486     audio_info_t audioInfo;
487     audio_prinfo_t* prinfo;
488     int setPort;
489 
490     if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
491         prinfo = &(audioInfo.play);
492     } else {
493         prinfo = &(audioInfo.record);
494     }
495     switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
496     case PORT_CONTROL_TYPE_SELECT_PORT:
497         // first try to just add this port. if that fails, set ONLY to this port.
498         AUDIO_INITINFO(&audioInfo);
499         if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
500             if (value) {
501                 setPort = (prinfo->port | controlID->port);
502             } else {
503                 setPort = (prinfo->port - controlID->port);
504             }
505             AUDIO_INITINFO(&audioInfo);
506             prinfo->port = setPort;
507             if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
508                 // didn't work. Either this line doesn't support to select several
509                 // ports at once (e.g. record), or a real error
510                 if (value) {
511                     // set to ONLY this port (and disable any other currently selected ports)
512                     AUDIO_INITINFO(&audioInfo);
513                     prinfo->port = controlID->port;
514                     if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
515                         ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port);
516                     }
517                 } else {
518                     // assume it's an error
519                     ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort);
520                 }
521             }
522             break;
523         case PORT_CONTROL_TYPE_OUTPUT_MUTED:
524             AUDIO_INITINFO(&audioInfo);
525             audioInfo.output_muted = (value?TRUE:FALSE);
526             if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
527                 ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value);
528             }
529             break;
530         default:
531             ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
532         }
533     }
534 }
535 
PORT_GetFloatValue(void * controlIDV)536 float PORT_GetFloatValue(void* controlIDV) {
537     PortControlID* controlID = (PortControlID*) controlIDV;
538     audio_info_t audioInfo;
539     audio_prinfo_t* prinfo;
540 
541     AUDIO_INITINFO(&audioInfo);
542     if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
543         if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
544             prinfo = &(audioInfo.play);
545         } else {
546             prinfo = &(audioInfo.record);
547         }
548         switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
549         case PORT_CONTROL_TYPE_GAIN:
550             return ((float) (prinfo->gain - AUDIO_MIN_GAIN))
551                 / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
552         case PORT_CONTROL_TYPE_BALANCE:
553             return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1))
554                 / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE));
555         case PORT_CONTROL_TYPE_MONITOR_GAIN:
556             return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN))
557                 / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
558         default:
559             ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
560         }
561     }
562     ERROR0("PORT_GetFloatValue: Could not ioctl!\n");
563     return 0.0f;
564 }
565 
PORT_SetFloatValue(void * controlIDV,float value)566 void PORT_SetFloatValue(void* controlIDV, float value) {
567     PortControlID* controlID = (PortControlID*) controlIDV;
568     audio_info_t audioInfo;
569     audio_prinfo_t* prinfo;
570 
571     AUDIO_INITINFO(&audioInfo);
572 
573     if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
574         prinfo = &(audioInfo.play);
575     } else {
576         prinfo = &(audioInfo.record);
577     }
578     switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
579     case PORT_CONTROL_TYPE_GAIN:
580         prinfo->gain = AUDIO_MIN_GAIN
581             + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
582         break;
583     case PORT_CONTROL_TYPE_BALANCE:
584         prinfo->balance =  AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE
585             + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f);
586         break;
587     case PORT_CONTROL_TYPE_MONITOR_GAIN:
588         audioInfo.monitor_gain = AUDIO_MIN_GAIN
589             + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
590         break;
591     default:
592         ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
593         return;
594     }
595     if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
596         ERROR0("PORT_SetFloatValue: Could not ioctl!\n");
597     }
598 }
599 
600 #endif // USE_PORTS
601