| /* |
| * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #define USE_ERROR |
| #define USE_TRACE |
| |
| #include "PLATFORM_API_SolarisOS_Utils.h" |
| |
| #define MAX_AUDIO_DEVICES 20 |
| |
| // not thread safe... |
| static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES]; |
| static int globalADCount = -1; |
| static int globalADCacheTime = -1; |
| /* how many seconds do we cache devices */ |
| #define AD_CACHE_TIME 30 |
| |
| // return seconds |
| long getTimeInSeconds() { |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| return tv.tv_sec; |
| } |
| |
| |
| int getAudioDeviceCount() { |
| int count = MAX_AUDIO_DEVICES; |
| |
| getAudioDevices(globalADPaths, &count); |
| return count; |
| } |
| |
| /* returns TRUE if the path exists at all */ |
| int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) { |
| int i; |
| int found = 0; |
| int fileExists = 0; |
| // not thread safe... |
| static struct stat statBuf; |
| |
| // get stats on the file |
| if (stat(path, &statBuf) == 0) { |
| // file exists. |
| fileExists = 1; |
| // If it is not yet in the adPath array, add it to the array |
| for (i = 0; i < *count; i++) { |
| if (adPath[i].st_ino == statBuf.st_ino |
| && adPath[i].st_dev == statBuf.st_dev) { |
| found = 1; |
| break; |
| } |
| } |
| if (!found) { |
| adPath[*count].st_ino = statBuf.st_ino; |
| adPath[*count].st_dev = statBuf.st_dev; |
| strncpy(adPath[*count].path, path, MAX_NAME_LENGTH); |
| adPath[*count].path[MAX_NAME_LENGTH] = 0; |
| (*count)++; |
| TRACE1("Added audio device %s\n", path); |
| } |
| } |
| return fileExists; |
| } |
| |
| |
| void getAudioDevices(AudioDevicePath* adPath, int* count) { |
| int maxCount = *count; |
| char* audiodev; |
| char devsound[15]; |
| int i; |
| long timeInSeconds = getTimeInSeconds(); |
| |
| if (globalADCount < 0 |
| || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME |
| || (adPath != globalADPaths)) { |
| *count = 0; |
| // first device, if set, is AUDIODEV variable |
| audiodev = getenv("AUDIODEV"); |
| if (audiodev != NULL && audiodev[0] != 0) { |
| addAudioDevice(audiodev, adPath, count); |
| } |
| // then try /dev/audio |
| addAudioDevice("/dev/audio", adPath, count); |
| // then go through all of the /dev/sound/? devices |
| for (i = 0; i < 100; i++) { |
| sprintf(devsound, "/dev/sound/%d", i); |
| if (!addAudioDevice(devsound, adPath, count)) { |
| break; |
| } |
| } |
| if (adPath == globalADPaths) { |
| /* commit cache */ |
| globalADCount = *count; |
| /* set cache time */ |
| globalADCacheTime = timeInSeconds; |
| } |
| } else { |
| /* return cache */ |
| *count = globalADCount; |
| } |
| // that's it |
| } |
| |
| int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) { |
| int count = MAX_AUDIO_DEVICES; |
| int ret = 0; |
| |
| getAudioDevices(globalADPaths, &count); |
| if (index>=0 && index < count) { |
| ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames); |
| } |
| return ret; |
| } |
| |
| int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) { |
| int fd; |
| int mixerMode; |
| int len; |
| audio_info_t info; |
| audio_device_t deviceInfo; |
| |
| strncpy(adDesc->path, path, MAX_NAME_LENGTH); |
| adDesc->path[MAX_NAME_LENGTH] = 0; |
| strcpy(adDesc->pathctl, adDesc->path); |
| strcat(adDesc->pathctl, "ctl"); |
| strcpy(adDesc->name, adDesc->path); |
| adDesc->vendor[0] = 0; |
| adDesc->version[0] = 0; |
| adDesc->description[0] = 0; |
| adDesc->maxSimulLines = 1; |
| |
| // try to open the pseudo device and get more information |
| fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK); |
| if (fd >= 0) { |
| close(fd); |
| if (getNames) { |
| fd = open(adDesc->pathctl, O_RDONLY); |
| if (fd >= 0) { |
| if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) { |
| strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN); |
| adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0; |
| strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN); |
| adDesc->version[MAX_AUDIO_DEV_LEN] = 0; |
| /* add config string to the dev name |
| * creates a string like "/dev/audio (onboard1)" |
| */ |
| len = strlen(adDesc->name) + 1; |
| if (MAX_NAME_LENGTH - len > 3) { |
| strcat(adDesc->name, " ("); |
| strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len); |
| strcat(adDesc->name, ")"); |
| } |
| adDesc->name[MAX_NAME_LENGTH-1] = 0; |
| } |
| if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) { |
| if (mixerMode == AM_MIXER_MODE) { |
| TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path); |
| adDesc->maxSimulLines = -1; |
| } |
| } else { |
| ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path); |
| } |
| close(fd); |
| } else { |
| ERROR1("could not open %s!\n", adDesc->pathctl); |
| } |
| } |
| return 1; |
| } |
| return 0; |
| } |