--- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 2018-03-15 02:00:53.030586466 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,626 +0,0 @@ -/* - * Copyright (c) 2003, 2013, 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" -#include "DirectAudio.h" - -#if USE_DAUDIO == TRUE - - -// The default buffer time -#define DEFAULT_PERIOD_TIME_MILLIS 50 - -///// implemented functions of DirectAudio.h - -INT32 DAUDIO_GetDirectAudioDeviceCount() { - return (INT32) getAudioDeviceCount(); -} - - -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, - DirectAudioDeviceDescription* description) { - AudioDeviceDescription desc; - - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { - description->maxSimulLines = desc.maxSimulLines; - strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1); - description->name[DAUDIO_STRING_LENGTH-1] = 0; - strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1); - description->vendor[DAUDIO_STRING_LENGTH-1] = 0; - strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1); - description->version[DAUDIO_STRING_LENGTH-1] = 0; - /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/ - strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1); - description->description[DAUDIO_STRING_LENGTH-1] = 0; - return TRUE; - } - return FALSE; - -} - -#define MAX_SAMPLE_RATES 20 - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { - int fd = -1; - AudioDeviceDescription desc; - am_sample_rates_t *sr; - /* hardcoded bits and channels */ - int bits[] = {8, 16}; - int bitsCount = 2; - int channels[] = {1, 2}; - int channelsCount = 2; - /* for querying sample rates */ - int err; - int ch, b, s; - - TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource); - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { - fd = open(desc.pathctl, O_RDONLY); - } - if (fd < 0) { - ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); - return; - } - - /* get sample rates */ - sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES)); - if (sr == NULL) { - ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex); - close(fd); - return; - } - - sr->num_samp_rates = MAX_SAMPLE_RATES; - sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD; - sr->samp_rates[0] = -2; - err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); - if (err < 0) { - ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", - (int)mixerIndex); - ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n", - (int) sr->num_samp_rates, - (int) sr->samp_rates[0]); - /* Some Solaris 8 drivers fail for get sample rates! - * Do as if we support all sample rates - */ - sr->flags = MIXER_SR_LIMITS; - } - if ((sr->flags & MIXER_SR_LIMITS) - || (sr->num_samp_rates > MAX_SAMPLE_RATES)) { -#ifdef USE_TRACE - if ((sr->flags & MIXER_SR_LIMITS)) { - TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", - (int)mixerIndex); - } - if (sr->num_samp_rates > MAX_SAMPLE_RATES) { - TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", - MAX_SAMPLE_RATES, (int)mixerIndex); - } -#endif - /* - * Fake it to have only one sample rate: -1 - */ - sr->num_samp_rates = 1; - sr->samp_rates[0] = -1; - } - close(fd); - - for (ch = 0; ch < channelsCount; ch++) { - for (b = 0; b < bitsCount; b++) { - for (s = 0; s < sr->num_samp_rates; s++) { - DAUDIO_AddAudioFormat(creator, - bits[b], /* significant bits */ - 0, /* frameSize: let it be calculated */ - channels[ch], - (float) ((int) sr->samp_rates[s]), - DAUDIO_PCM, /* encoding - let's only do PCM */ - (bits[b] > 8)?TRUE:TRUE, /* isSigned */ -#ifdef _LITTLE_ENDIAN - FALSE /* little endian */ -#else - (bits[b] > 8)?TRUE:FALSE /* big endian */ -#endif - ); - } - } - } - free(sr); -} - - -typedef struct { - int fd; - audio_info_t info; - int bufferSizeInBytes; - int frameSize; /* storage size in Bytes */ - /* how many bytes were written or read */ - INT32 transferedBytes; - /* if transferedBytes exceed 32-bit boundary, - * it will be reset and positionOffset will receive - * the offset - */ - INT64 positionOffset; -} SolPcmInfo; - - -void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, - int encoding, float sampleRate, int sampleSizeInBits, - int frameSize, int channels, - int isSigned, int isBigEndian, int bufferSizeInBytes) { - int err = 0; - int openMode; - AudioDeviceDescription desc; - SolPcmInfo* info; - - TRACE0("> DAUDIO_Open\n"); - if (encoding != DAUDIO_PCM) { - ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding); - return NULL; - } - if (channels <= 0) { - ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels); - return NULL; - } - - info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo)); - if (!info) { - ERROR0("Out of memory\n"); - return NULL; - } - memset(info, 0, sizeof(SolPcmInfo)); - info->frameSize = frameSize; - info->fd = -1; - - if (isSource) { - openMode = O_WRONLY; - } else { - openMode = O_RDONLY; - } - -#ifndef __linux__ - /* blackdown does not use NONBLOCK */ - openMode |= O_NONBLOCK; -#endif - - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { - info->fd = open(desc.path, openMode); - } - if (info->fd < 0) { - ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex); - free(info); - return NULL; - } - /* set to multiple open */ - if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) { - TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path); - } else { - ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path); - } - - AUDIO_INITINFO(&(info->info)); - /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */ - err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); - - /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */ - AUDIO_INITINFO(&(info->info)); - - if (isSource) { - info->info.play.sample_rate = sampleRate; - info->info.play.precision = sampleSizeInBits; - info->info.play.channels = channels; - info->info.play.encoding = AUDIO_ENCODING_LINEAR; - info->info.play.buffer_size = bufferSizeInBytes; - info->info.play.pause = 1; - } else { - info->info.record.sample_rate = sampleRate; - info->info.record.precision = sampleSizeInBits; - info->info.record.channels = channels; - info->info.record.encoding = AUDIO_ENCODING_LINEAR; - info->info.record.buffer_size = bufferSizeInBytes; - info->info.record.pause = 1; - } - err = ioctl(info->fd, AUDIO_SETINFO, &(info->info)); - if (err < 0) { - ERROR0("DAUDIO_Open: could not set info!\n"); - DAUDIO_Close((void*) info, isSource); - return NULL; - } - DAUDIO_Flush((void*) info, isSource); - - err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); - if (err >= 0) { - if (isSource) { - info->bufferSizeInBytes = info->info.play.buffer_size; - } else { - info->bufferSizeInBytes = info->info.record.buffer_size; - } - TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n", - (int) bufferSizeInBytes, - (int) info->bufferSizeInBytes); - } else { - ERROR0("DAUDIO_Open: cannot get info!\n"); - DAUDIO_Close((void*) info, isSource); - return NULL; - } - TRACE0("< DAUDIO_Open: Opened device successfully.\n"); - return (void*) info; -} - - -int DAUDIO_Start(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err, modified; - audio_info_t audioInfo; - - TRACE0("> DAUDIO_Start\n"); - - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - // unpause - modified = FALSE; - if (isSource && audioInfo.play.pause) { - audioInfo.play.pause = 0; - modified = TRUE; - } - if (!isSource && audioInfo.record.pause) { - audioInfo.record.pause = 0; - modified = TRUE; - } - if (modified) { - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - } - } - - TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error"); - return (err >= 0)?TRUE:FALSE; -} - -int DAUDIO_Stop(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err, modified; - audio_info_t audioInfo; - - TRACE0("> DAUDIO_Stop\n"); - - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - // pause - modified = FALSE; - if (isSource && !audioInfo.play.pause) { - audioInfo.play.pause = 1; - modified = TRUE; - } - if (!isSource && !audioInfo.record.pause) { - audioInfo.record.pause = 1; - modified = TRUE; - } - if (modified) { - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - } - } - - TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error"); - return (err >= 0)?TRUE:FALSE; -} - -void DAUDIO_Close(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - - TRACE0("DAUDIO_Close\n"); - if (info != NULL) { - if (info->fd >= 0) { - DAUDIO_Flush(id, isSource); - close(info->fd); - } - free(info); - } -} - -#ifndef USE_TRACE -/* close to 2^31 */ -#define POSITION_MAX 2000000000 -#else -/* for testing */ -#define POSITION_MAX 1000000 -#endif - -void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) { - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int err; - int offset = -1; - int underrun = FALSE; - int devBytes = 0; - - if (count > 0) { - info->transferedBytes += count; - - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - underrun = prinfo->error; - devBytes = prinfo->samples * info->frameSize; - } - AUDIO_INITINFO(&audioInfo); - if (underrun) { - /* if an underrun occurred, reset */ - ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n", - (devBytes - info->transferedBytes)); - ERROR1(" devBytes from %d to 0, ", devBytes); - ERROR2(" positionOffset from %d to %d ", - (int) info->positionOffset, - (int) (info->positionOffset + info->transferedBytes)); - ERROR1(" transferedBytes from %d to 0\n", - (int) info->transferedBytes); - prinfo->samples = 0; - info->positionOffset += info->transferedBytes; - info->transferedBytes = 0; - } - else if (info->transferedBytes > POSITION_MAX) { - /* we will reset transferedBytes and - * the samples field in prinfo - */ - offset = devBytes; - prinfo->samples = 0; - } - /* reset error flag */ - prinfo->error = 0; - - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - if (err >= 0) { - if (offset > 0) { - /* upon exit of AUDIO_SETINFO, the samples parameter - * was set to the previous value. This is our - * offset. - */ - TRACE1("Adjust samplePos: offset=%d, ", (int) offset); - TRACE2("transferedBytes=%d -> %d, ", - (int) info->transferedBytes, - (int) (info->transferedBytes - offset)); - TRACE2("positionOffset=%d -> %d\n", - (int) (info->positionOffset), - (int) (((int) info->positionOffset) + offset)); - info->transferedBytes -= offset; - info->positionOffset += offset; - } - } else { - ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n"); - } - } -} - -// returns -1 on error -int DAUDIO_Write(void* id, char* data, int byteSize) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = -1; - - TRACE1("> DAUDIO_Write %d bytes\n", byteSize); - if (info!=NULL) { - ret = write(info->fd, data, byteSize); - resetErrorFlagAndAdjustPosition(info, TRUE, ret); - /* sets ret to -1 if buffer full, no error! */ - if (ret < 0) { - ret = 0; - } - } - TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); - return ret; -} - -// returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = -1; - - TRACE1("> DAUDIO_Read %d bytes\n", byteSize); - if (info != NULL) { - ret = read(info->fd, data, byteSize); - resetErrorFlagAndAdjustPosition(info, TRUE, ret); - /* sets ret to -1 if buffer full, no error! */ - if (ret < 0) { - ret = 0; - } - } - TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); - return ret; -} - - -int DAUDIO_GetBufferSize(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - if (info) { - return info->bufferSizeInBytes; - } - return 0; -} - -int DAUDIO_StillDraining(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int ret = FALSE; - - if (info!=NULL) { - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - /* check error flag */ - AUDIO_INITINFO(&audioInfo); - ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - ret = (prinfo->error != 0)?FALSE:TRUE; - } - return ret; -} - - -int getDevicePosition(SolPcmInfo* info, int isSource) { - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int err; - - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - /*TRACE2("---> device paused: %d eof=%d\n", - prinfo->pause, prinfo->eof); - */ - return (int) (prinfo->samples * info->frameSize); - } - ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n"); - return -1; -} - -int DAUDIO_Flush(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err = -1; - int pos; - - TRACE0("DAUDIO_Flush\n"); - if (info) { - if (isSource) { - err = ioctl(info->fd, I_FLUSH, FLUSHW); - } else { - err = ioctl(info->fd, I_FLUSH, FLUSHR); - } - if (err >= 0) { - /* resets the transferedBytes parameter to - * the current samples count of the device - */ - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - info->transferedBytes = pos; - } - } - } - if (err < 0) { - ERROR0("ERROR in DAUDIO_Flush\n"); - } - return (err < 0)?FALSE:TRUE; -} - -int DAUDIO_GetAvailable(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = 0; - int pos; - - if (info) { - /* unfortunately, the STREAMS architecture - * seems to not have a method for querying - * the available bytes to read/write! - * estimate it... - */ - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - if (isSource) { - /* we usually have written more bytes - * to the queue than the device position should be - */ - ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos); - } else { - /* for record, the device stream should - * be usually ahead of our read actions - */ - ret = pos - info->transferedBytes; - } - if (ret > info->bufferSizeInBytes) { - ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n", - (int) ret, (int) info->bufferSizeInBytes); - ERROR2(" devicePos=%d, transferedBytes=%d\n", - (int) pos, (int) info->transferedBytes); - ret = info->bufferSizeInBytes; - } - else if (ret < 0) { - ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n", - (int) ret); - ERROR2(" devicePos=%d, transferedBytes=%d\n", - (int) pos, (int) info->transferedBytes); - ret = 0; - } - } - } - - TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); - return ret; -} - -INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret; - int pos; - INT64 result = javaBytePos; - - if (info) { - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - result = info->positionOffset + pos; - } - } - - //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); - return result; -} - - -void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret; - int pos; - - if (info) { - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - info->positionOffset = javaBytePos - pos; - } - } -} - -int DAUDIO_RequiresServicing(void* id, int isSource) { - // never need servicing on Solaris - return FALSE; -} - -void DAUDIO_Service(void* id, int isSource) { - // never need servicing on Solaris -} - - -#endif // USE_DAUDIO --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 2018-03-15 02:00:52.710586469 +0100 @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2003, 2013, 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" +#include "DirectAudio.h" + +#if USE_DAUDIO == TRUE + + +// The default buffer time +#define DEFAULT_PERIOD_TIME_MILLIS 50 + +///// implemented functions of DirectAudio.h + +INT32 DAUDIO_GetDirectAudioDeviceCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, + DirectAudioDeviceDescription* description) { + AudioDeviceDescription desc; + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { + description->maxSimulLines = desc.maxSimulLines; + strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1); + description->name[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1); + description->vendor[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1); + description->version[DAUDIO_STRING_LENGTH-1] = 0; + /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/ + strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1); + description->description[DAUDIO_STRING_LENGTH-1] = 0; + return TRUE; + } + return FALSE; + +} + +#define MAX_SAMPLE_RATES 20 + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { + int fd = -1; + AudioDeviceDescription desc; + am_sample_rates_t *sr; + /* hardcoded bits and channels */ + int bits[] = {8, 16}; + int bitsCount = 2; + int channels[] = {1, 2}; + int channelsCount = 2; + /* for querying sample rates */ + int err; + int ch, b, s; + + TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource); + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + fd = open(desc.pathctl, O_RDONLY); + } + if (fd < 0) { + ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); + return; + } + + /* get sample rates */ + sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES)); + if (sr == NULL) { + ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex); + close(fd); + return; + } + + sr->num_samp_rates = MAX_SAMPLE_RATES; + sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD; + sr->samp_rates[0] = -2; + err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); + if (err < 0) { + ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", + (int)mixerIndex); + ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n", + (int) sr->num_samp_rates, + (int) sr->samp_rates[0]); + /* Some Solaris 8 drivers fail for get sample rates! + * Do as if we support all sample rates + */ + sr->flags = MIXER_SR_LIMITS; + } + if ((sr->flags & MIXER_SR_LIMITS) + || (sr->num_samp_rates > MAX_SAMPLE_RATES)) { +#ifdef USE_TRACE + if ((sr->flags & MIXER_SR_LIMITS)) { + TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", + (int)mixerIndex); + } + if (sr->num_samp_rates > MAX_SAMPLE_RATES) { + TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", + MAX_SAMPLE_RATES, (int)mixerIndex); + } +#endif + /* + * Fake it to have only one sample rate: -1 + */ + sr->num_samp_rates = 1; + sr->samp_rates[0] = -1; + } + close(fd); + + for (ch = 0; ch < channelsCount; ch++) { + for (b = 0; b < bitsCount; b++) { + for (s = 0; s < sr->num_samp_rates; s++) { + DAUDIO_AddAudioFormat(creator, + bits[b], /* significant bits */ + 0, /* frameSize: let it be calculated */ + channels[ch], + (float) ((int) sr->samp_rates[s]), + DAUDIO_PCM, /* encoding - let's only do PCM */ + (bits[b] > 8)?TRUE:TRUE, /* isSigned */ +#ifdef _LITTLE_ENDIAN + FALSE /* little endian */ +#else + (bits[b] > 8)?TRUE:FALSE /* big endian */ +#endif + ); + } + } + } + free(sr); +} + + +typedef struct { + int fd; + audio_info_t info; + int bufferSizeInBytes; + int frameSize; /* storage size in Bytes */ + /* how many bytes were written or read */ + INT32 transferedBytes; + /* if transferedBytes exceed 32-bit boundary, + * it will be reset and positionOffset will receive + * the offset + */ + INT64 positionOffset; +} SolPcmInfo; + + +void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, + int encoding, float sampleRate, int sampleSizeInBits, + int frameSize, int channels, + int isSigned, int isBigEndian, int bufferSizeInBytes) { + int err = 0; + int openMode; + AudioDeviceDescription desc; + SolPcmInfo* info; + + TRACE0("> DAUDIO_Open\n"); + if (encoding != DAUDIO_PCM) { + ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding); + return NULL; + } + if (channels <= 0) { + ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels); + return NULL; + } + + info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo)); + if (!info) { + ERROR0("Out of memory\n"); + return NULL; + } + memset(info, 0, sizeof(SolPcmInfo)); + info->frameSize = frameSize; + info->fd = -1; + + if (isSource) { + openMode = O_WRONLY; + } else { + openMode = O_RDONLY; + } + +#ifndef __linux__ + /* blackdown does not use NONBLOCK */ + openMode |= O_NONBLOCK; +#endif + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + info->fd = open(desc.path, openMode); + } + if (info->fd < 0) { + ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex); + free(info); + return NULL; + } + /* set to multiple open */ + if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) { + TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path); + } else { + ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path); + } + + AUDIO_INITINFO(&(info->info)); + /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */ + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + + /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */ + AUDIO_INITINFO(&(info->info)); + + if (isSource) { + info->info.play.sample_rate = sampleRate; + info->info.play.precision = sampleSizeInBits; + info->info.play.channels = channels; + info->info.play.encoding = AUDIO_ENCODING_LINEAR; + info->info.play.buffer_size = bufferSizeInBytes; + info->info.play.pause = 1; + } else { + info->info.record.sample_rate = sampleRate; + info->info.record.precision = sampleSizeInBits; + info->info.record.channels = channels; + info->info.record.encoding = AUDIO_ENCODING_LINEAR; + info->info.record.buffer_size = bufferSizeInBytes; + info->info.record.pause = 1; + } + err = ioctl(info->fd, AUDIO_SETINFO, &(info->info)); + if (err < 0) { + ERROR0("DAUDIO_Open: could not set info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + DAUDIO_Flush((void*) info, isSource); + + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + if (err >= 0) { + if (isSource) { + info->bufferSizeInBytes = info->info.play.buffer_size; + } else { + info->bufferSizeInBytes = info->info.record.buffer_size; + } + TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n", + (int) bufferSizeInBytes, + (int) info->bufferSizeInBytes); + } else { + ERROR0("DAUDIO_Open: cannot get info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + TRACE0("< DAUDIO_Open: Opened device successfully.\n"); + return (void*) info; +} + + +int DAUDIO_Start(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Start\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // unpause + modified = FALSE; + if (isSource && audioInfo.play.pause) { + audioInfo.play.pause = 0; + modified = TRUE; + } + if (!isSource && audioInfo.record.pause) { + audioInfo.record.pause = 0; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +int DAUDIO_Stop(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Stop\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // pause + modified = FALSE; + if (isSource && !audioInfo.play.pause) { + audioInfo.play.pause = 1; + modified = TRUE; + } + if (!isSource && !audioInfo.record.pause) { + audioInfo.record.pause = 1; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +void DAUDIO_Close(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + + TRACE0("DAUDIO_Close\n"); + if (info != NULL) { + if (info->fd >= 0) { + DAUDIO_Flush(id, isSource); + close(info->fd); + } + free(info); + } +} + +#ifndef USE_TRACE +/* close to 2^31 */ +#define POSITION_MAX 2000000000 +#else +/* for testing */ +#define POSITION_MAX 1000000 +#endif + +void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + int offset = -1; + int underrun = FALSE; + int devBytes = 0; + + if (count > 0) { + info->transferedBytes += count; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + underrun = prinfo->error; + devBytes = prinfo->samples * info->frameSize; + } + AUDIO_INITINFO(&audioInfo); + if (underrun) { + /* if an underrun occurred, reset */ + ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n", + (devBytes - info->transferedBytes)); + ERROR1(" devBytes from %d to 0, ", devBytes); + ERROR2(" positionOffset from %d to %d ", + (int) info->positionOffset, + (int) (info->positionOffset + info->transferedBytes)); + ERROR1(" transferedBytes from %d to 0\n", + (int) info->transferedBytes); + prinfo->samples = 0; + info->positionOffset += info->transferedBytes; + info->transferedBytes = 0; + } + else if (info->transferedBytes > POSITION_MAX) { + /* we will reset transferedBytes and + * the samples field in prinfo + */ + offset = devBytes; + prinfo->samples = 0; + } + /* reset error flag */ + prinfo->error = 0; + + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + if (err >= 0) { + if (offset > 0) { + /* upon exit of AUDIO_SETINFO, the samples parameter + * was set to the previous value. This is our + * offset. + */ + TRACE1("Adjust samplePos: offset=%d, ", (int) offset); + TRACE2("transferedBytes=%d -> %d, ", + (int) info->transferedBytes, + (int) (info->transferedBytes - offset)); + TRACE2("positionOffset=%d -> %d\n", + (int) (info->positionOffset), + (int) (((int) info->positionOffset) + offset)); + info->transferedBytes -= offset; + info->positionOffset += offset; + } + } else { + ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n"); + } + } +} + +// returns -1 on error +int DAUDIO_Write(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Write %d bytes\n", byteSize); + if (info!=NULL) { + ret = write(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); + return ret; +} + +// returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Read %d bytes\n", byteSize); + if (info != NULL) { + ret = read(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); + return ret; +} + + +int DAUDIO_GetBufferSize(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + if (info) { + return info->bufferSizeInBytes; + } + return 0; +} + +int DAUDIO_StillDraining(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int ret = FALSE; + + if (info!=NULL) { + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + /* check error flag */ + AUDIO_INITINFO(&audioInfo); + ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + ret = (prinfo->error != 0)?FALSE:TRUE; + } + return ret; +} + + +int getDevicePosition(SolPcmInfo* info, int isSource) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + /*TRACE2("---> device paused: %d eof=%d\n", + prinfo->pause, prinfo->eof); + */ + return (int) (prinfo->samples * info->frameSize); + } + ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n"); + return -1; +} + +int DAUDIO_Flush(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err = -1; + int pos; + + TRACE0("DAUDIO_Flush\n"); + if (info) { + if (isSource) { + err = ioctl(info->fd, I_FLUSH, FLUSHW); + } else { + err = ioctl(info->fd, I_FLUSH, FLUSHR); + } + if (err >= 0) { + /* resets the transferedBytes parameter to + * the current samples count of the device + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->transferedBytes = pos; + } + } + } + if (err < 0) { + ERROR0("ERROR in DAUDIO_Flush\n"); + } + return (err < 0)?FALSE:TRUE; +} + +int DAUDIO_GetAvailable(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = 0; + int pos; + + if (info) { + /* unfortunately, the STREAMS architecture + * seems to not have a method for querying + * the available bytes to read/write! + * estimate it... + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + if (isSource) { + /* we usually have written more bytes + * to the queue than the device position should be + */ + ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos); + } else { + /* for record, the device stream should + * be usually ahead of our read actions + */ + ret = pos - info->transferedBytes; + } + if (ret > info->bufferSizeInBytes) { + ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n", + (int) ret, (int) info->bufferSizeInBytes); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = info->bufferSizeInBytes; + } + else if (ret < 0) { + ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n", + (int) ret); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = 0; + } + } + } + + TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); + return ret; +} + +INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + INT64 result = javaBytePos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + result = info->positionOffset + pos; + } + } + + //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); + return result; +} + + +void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->positionOffset = javaBytePos - pos; + } + } +} + +int DAUDIO_RequiresServicing(void* id, int isSource) { + // never need servicing on Solaris + return FALSE; +} + +void DAUDIO_Service(void* id, int isSource) { + // never need servicing on Solaris +} + + +#endif // USE_DAUDIO