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 "PLATFORM_API_SolarisOS_Utils.h"
  30 
  31 #define MAX_AUDIO_DEVICES 20
  32 
  33 // not thread safe...
  34 static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES];
  35 static int globalADCount = -1;
  36 static int globalADCacheTime = -1;
  37 /* how many seconds do we cache devices */
  38 #define AD_CACHE_TIME 30
  39 
  40 // return seconds
  41 long getTimeInSeconds() {
  42     struct timeval tv;
  43     gettimeofday(&tv, NULL);
  44     return tv.tv_sec;
  45 }
  46 
  47 
  48 int getAudioDeviceCount() {
  49     int count = MAX_AUDIO_DEVICES;
  50 
  51     getAudioDevices(globalADPaths, &count);
  52     return count;
  53 }
  54 
  55 /* returns TRUE if the path exists at all */
  56 int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) {
  57     int i;
  58     int found = 0;
  59     int fileExists = 0;
  60     // not thread safe...
  61     static struct stat statBuf;
  62 
  63     // get stats on the file
  64     if (stat(path, &statBuf) == 0) {
  65         // file exists.
  66         fileExists = 1;
  67         // If it is not yet in the adPath array, add it to the array
  68         for (i = 0; i < *count; i++) {
  69             if (adPath[i].st_ino == statBuf.st_ino
  70                 && adPath[i].st_dev == statBuf.st_dev) {
  71                 found = 1;
  72                 break;
  73             }
  74         }
  75         if (!found) {
  76             adPath[*count].st_ino = statBuf.st_ino;
  77             adPath[*count].st_dev = statBuf.st_dev;
  78             strncpy(adPath[*count].path, path, MAX_NAME_LENGTH);
  79             adPath[*count].path[MAX_NAME_LENGTH - 1] = 0;
  80             (*count)++;
  81             TRACE1("Added audio device %s\n", path);
  82         }
  83     }
  84     return fileExists;
  85 }
  86 
  87 
  88 void getAudioDevices(AudioDevicePath* adPath, int* count) {
  89     int maxCount = *count;
  90     char* audiodev;
  91     char devsound[15];
  92     int i;
  93     long timeInSeconds = getTimeInSeconds();
  94 
  95     if (globalADCount < 0
  96         || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME
  97         || (adPath != globalADPaths)) {
  98         *count = 0;
  99         // first device, if set, is AUDIODEV variable
 100         audiodev = getenv("AUDIODEV");
 101         if (audiodev != NULL && audiodev[0] != 0) {
 102             addAudioDevice(audiodev, adPath, count);
 103         }
 104         // then try /dev/audio
 105         addAudioDevice("/dev/audio", adPath, count);
 106         // then go through all of the /dev/sound/? devices
 107         for (i = 0; i < 100; i++) {
 108             sprintf(devsound, "/dev/sound/%d", i);
 109             if (!addAudioDevice(devsound, adPath, count)) {
 110                 break;
 111             }
 112         }
 113         if (adPath == globalADPaths) {
 114             /* commit cache */
 115             globalADCount = *count;
 116             /* set cache time */
 117             globalADCacheTime = timeInSeconds;
 118         }
 119     } else {
 120         /* return cache */
 121         *count = globalADCount;
 122     }
 123     // that's it
 124 }
 125 
 126 int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) {
 127     int count = MAX_AUDIO_DEVICES;
 128     int ret = 0;
 129 
 130     getAudioDevices(globalADPaths, &count);
 131     if (index>=0 && index < count) {
 132         ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames);
 133     }
 134     return ret;
 135 }
 136 
 137 int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) {
 138     int fd;
 139     int mixerMode;
 140     int len;
 141     audio_info_t info;
 142     audio_device_t deviceInfo;
 143 
 144     strncpy(adDesc->path, path, MAX_NAME_LENGTH);
 145     adDesc->path[MAX_NAME_LENGTH] = 0;
 146     strcpy(adDesc->pathctl, adDesc->path);
 147     strcat(adDesc->pathctl, "ctl");
 148     strcpy(adDesc->name, adDesc->path);
 149     adDesc->vendor[0] = 0;
 150     adDesc->version[0] = 0;
 151     adDesc->description[0] = 0;
 152     adDesc->maxSimulLines = 1;
 153 
 154     // try to open the pseudo device and get more information
 155     fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK);
 156     if (fd >= 0) {
 157         close(fd);
 158         if (getNames) {
 159             fd = open(adDesc->pathctl, O_RDONLY);
 160             if (fd >= 0) {
 161                 if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) {
 162                     strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN);
 163                     adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0;
 164                     strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN);
 165                     adDesc->version[MAX_AUDIO_DEV_LEN] = 0;
 166                     /* add config string to the dev name
 167                      * creates a string like "/dev/audio (onboard1)"
 168                      */
 169                     len = strlen(adDesc->name) + 1;
 170                     if (MAX_NAME_LENGTH - len > 3) {
 171                         strcat(adDesc->name, " (");
 172                         strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len);
 173                         strcat(adDesc->name, ")");
 174                     }
 175                     adDesc->name[MAX_NAME_LENGTH-1] = 0;
 176                 }
 177                 if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) {
 178                     if (mixerMode == AM_MIXER_MODE) {
 179                         TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path);
 180                         adDesc->maxSimulLines = -1;
 181                     }
 182                 } else {
 183                     ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path);
 184                 }
 185                 close(fd);
 186             } else {
 187                 ERROR1("could not open %s!\n", adDesc->pathctl);
 188             }
 189         }
 190         return 1;
 191     }
 192     return 0;
 193 }