# HG changeset patch # User ihse # Date 1521795062 -3600 # Node ID 148e29df1644969d99972b3e68a9bfa94528ca41 # Parent 6e2d71029781b16a5753577fa1b27d65bf9fda77 8071469: Cleanup include and exclude of sound native libraries Reviewed-by: amenkov, erikj diff -r 6e2d71029781 -r 148e29df1644 make/lib/SoundLibraries.gmk --- a/make/lib/SoundLibraries.gmk Fri Mar 23 09:26:59 2018 +0100 +++ b/make/lib/SoundLibraries.gmk Fri Mar 23 09:51:02 2018 +0100 @@ -23,101 +23,50 @@ # questions. # -LIBJSOUND_SRC_DIRS := \ +LIBJSOUND_SRC_DIRS := $(wildcard \ $(TOPDIR)/src/java.desktop/share/native/libjsound \ - $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libjsound \ - # + $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libjsound \ + ) + LIBJSOUND_CFLAGS := \ -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ $(LIBJAVA_HEADER_FLAGS) \ $(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \ + -DUSE_PORTS=TRUE \ + -DUSE_DAUDIO=TRUE \ # -LIBJSOUND_SRC_FILES := Utilities.c Platform.c - -EXTRA_SOUND_JNI_LIBS := - -LIBJSOUND_MIDIFILES := \ - MidiInDevice.c \ - MidiInDeviceProvider.c \ - MidiOutDevice.c \ - MidiOutDeviceProvider.c \ - PlatformMidi.c - -# files needed for ports -LIBJSOUND_PORTFILES := \ - PortMixerProvider.c \ - PortMixer.c - -# files needed for direct audio -LIBJSOUND_DAUDIOFILES := \ - DirectAudioDeviceProvider.c \ - DirectAudioDevice.c +ifneq ($(OPENJDK_TARGET_OS), solaris) + LIBJSOUND_CFLAGS += \ + -DUSE_PLATFORM_MIDI_OUT=TRUE \ + -DUSE_PLATFORM_MIDI_IN=TRUE \ + # +endif ifeq ($(OPENJDK_TARGET_OS), windows) - EXTRA_SOUND_JNI_LIBS += jsoundds - LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS \ - -DUSE_PLATFORM_MIDI_OUT=TRUE \ - -DUSE_PLATFORM_MIDI_IN=TRUE \ - -DUSE_PORTS=TRUE - LIBJSOUND_SRC_FILES += \ - PLATFORM_API_WinOS_Charset_Util.cpp \ - PLATFORM_API_WinOS_MidiIn.cpp \ - PLATFORM_API_WinOS_MidiOut.c \ - PLATFORM_API_WinOS_Util.c \ - PLATFORM_API_WinOS_Ports.c - LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES) - LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES) -endif # OPENJDK_TARGET_OS windows + LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS +endif ifeq ($(OPENJDK_TARGET_OS), linux) - EXTRA_SOUND_JNI_LIBS += jsoundalsa LIBJSOUND_CFLAGS += -DX_PLATFORM=X_LINUX -endif # OPENJDK_TARGET_OS linux +endif ifeq ($(OPENJDK_TARGET_OS), aix) LIBJSOUND_CFLAGS += -DX_PLATFORM=X_AIX -endif # OPENJDK_TARGET_OS aix +endif ifeq ($(OPENJDK_TARGET_OS), macosx) LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX - LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX \ - -DUSE_PORTS=TRUE \ - -DUSE_DAUDIO=TRUE \ - -DUSE_PLATFORM_MIDI_OUT=TRUE \ - -DUSE_PLATFORM_MIDI_IN=TRUE - LIBJSOUND_SRC_DIRS += $(TOPDIR)/src/java.desktop/macosx/native/libjsound - LIBJSOUND_SRC_FILES += \ - PLATFORM_API_MacOSX_Utils.cpp \ - PLATFORM_API_MacOSX_PCM.cpp \ - PLATFORM_API_MacOSX_Ports.cpp \ - PLATFORM_API_MacOSX_MidiIn.c \ - PLATFORM_API_MacOSX_MidiOut.c \ - PLATFORM_API_MacOSX_MidiUtils.c - LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES) - LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES) - LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES) -endif # OPENJDK_TARGET_OS macosx + LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX +endif ifeq ($(OPENJDK_TARGET_OS), solaris) - LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS \ - -DUSE_PORTS=TRUE \ - -DUSE_DAUDIO=TRUE - LIBJSOUND_SRC_FILES += \ - PLATFORM_API_SolarisOS_Utils.c \ - PLATFORM_API_SolarisOS_Ports.c \ - PLATFORM_API_SolarisOS_PCM.c - LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES) - LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES) - LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES) -endif # OPENJDK_TARGET_OS solaris - -LIBJSOUND_CFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"' + LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS +endif $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUND, \ NAME := jsound, \ SRC := $(LIBJSOUND_SRC_DIRS), \ - INCLUDE_FILES := $(LIBJSOUND_SRC_FILES), \ TOOLCHAIN := $(LIBJSOUND_TOOLCHAIN), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ @@ -127,10 +76,11 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -ljava -ljvm, \ + LIBS_linux := $(ALSA_LIBS), \ LIBS_macosx := -framework CoreAudio -framework CoreFoundation \ - -framework CoreServices -framework AudioUnit $(LIBCXX) \ - -framework CoreMIDI -framework AudioToolbox, \ - LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib winmm.lib, \ + -framework CoreServices -framework AudioUnit \ + -framework CoreMIDI -framework AudioToolbox $(LIBCXX), \ + LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib dsound.lib winmm.lib user32.lib ole32.lib, \ )) $(BUILD_LIBJSOUND): $(call FindLib, java.base, java) @@ -138,61 +88,3 @@ TARGETS += $(BUILD_LIBJSOUND) ########################################################################################## - -ifneq ($(filter jsoundalsa, $(EXTRA_SOUND_JNI_LIBS)), ) - - $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDALSA, \ - NAME := jsoundalsa, \ - SRC := $(LIBJSOUND_SRC_DIRS), \ - INCLUDE_FILES := Utilities.c $(LIBJSOUND_MIDIFILES) $(LIBJSOUND_PORTFILES) \ - $(LIBJSOUND_DAUDIOFILES) \ - PLATFORM_API_LinuxOS_ALSA_CommonUtils.c \ - PLATFORM_API_LinuxOS_ALSA_PCM.c \ - PLATFORM_API_LinuxOS_ALSA_PCMUtils.c \ - PLATFORM_API_LinuxOS_ALSA_MidiIn.c \ - PLATFORM_API_LinuxOS_ALSA_MidiOut.c \ - PLATFORM_API_LinuxOS_ALSA_MidiUtils.c \ - PLATFORM_API_LinuxOS_ALSA_Ports.c, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \ - $(LIBJSOUND_CFLAGS) \ - -DUSE_DAUDIO=TRUE \ - -DUSE_PORTS=TRUE \ - -DUSE_PLATFORM_MIDI_OUT=TRUE \ - -DUSE_PLATFORM_MIDI_IN=TRUE, \ - MAPFILE := $(TOPDIR)/make/mapfiles/libjsoundalsa/mapfile-vers, \ - LDFLAGS := $(LDFLAGS_JDKLIB) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := $(ALSA_LIBS) -ljava -ljvm, \ - )) - - $(BUILD_LIBJSOUNDALSA): $(call FindLib, java.base, java) - - TARGETS += $(BUILD_LIBJSOUNDALSA) - -endif - -########################################################################################## - -ifneq ($(filter jsoundds, $(EXTRA_SOUND_JNI_LIBS)), ) - - $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDDS, \ - NAME := jsoundds, \ - SRC := $(LIBJSOUND_SRC_DIRS), \ - INCLUDE_FILES := Utilities.c $(LIBJSOUND_DAUDIOFILES) \ - PLATFORM_API_WinOS_Charset_Util.cpp \ - PLATFORM_API_WinOS_DirectSound.cpp, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - $(LIBJSOUND_CFLAGS) \ - -DUSE_DAUDIO=TRUE, \ - LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \ - $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := $(JDKLIB_LIBS) dsound.lib winmm.lib user32.lib ole32.lib, \ - )) - - $(BUILD_LIBJSOUNDDS): $(call FindLib, java.base, java) - - TARGETS += $(BUILD_LIBJSOUNDDS) - -endif diff -r 6e2d71029781 -r 148e29df1644 make/mapfiles/libjsound/mapfile-vers --- a/make/mapfiles/libjsound/mapfile-vers Fri Mar 23 09:26:59 2018 +0100 +++ b/make/mapfiles/libjsound/mapfile-vers Fri Mar 23 09:51:02 2018 +0100 @@ -65,8 +65,6 @@ Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices; Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor; Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion; - Java_com_sun_media_sound_Platform_nGetExtraLibraries; - Java_com_sun_media_sound_Platform_nGetLibraryForFeature; Java_com_sun_media_sound_Platform_nIsBigEndian; Java_com_sun_media_sound_PortMixer_nClose; Java_com_sun_media_sound_PortMixer_nControlGetFloatValue; diff -r 6e2d71029781 -r 148e29df1644 make/mapfiles/libjsoundalsa/mapfile-vers --- a/make/mapfiles/libjsoundalsa/mapfile-vers Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -# -# Copyright (c) 2005, 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 library interface. - -SUNWprivate_1.1 { - global: - Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices; - Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo; - Java_com_sun_media_sound_DirectAudioDevice_nAvailable; - Java_com_sun_media_sound_DirectAudioDevice_nClose; - Java_com_sun_media_sound_DirectAudioDevice_nFlush; - Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize; - Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition; - Java_com_sun_media_sound_DirectAudioDevice_nGetFormats; - Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining; - Java_com_sun_media_sound_DirectAudioDevice_nOpen; - Java_com_sun_media_sound_DirectAudioDevice_nRead; - Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing; - Java_com_sun_media_sound_DirectAudioDevice_nService; - Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition; - Java_com_sun_media_sound_DirectAudioDevice_nStart; - Java_com_sun_media_sound_DirectAudioDevice_nStop; - Java_com_sun_media_sound_DirectAudioDevice_nWrite; - Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription; - Java_com_sun_media_sound_MidiInDeviceProvider_nGetName; - Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices; - Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor; - Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion; - Java_com_sun_media_sound_MidiInDevice_nClose; - Java_com_sun_media_sound_MidiInDevice_nGetMessages; - Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp; - Java_com_sun_media_sound_MidiInDevice_nOpen; - Java_com_sun_media_sound_MidiInDevice_nStart; - Java_com_sun_media_sound_MidiInDevice_nStop; - Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription; - Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName; - Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices; - Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor; - Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion; - Java_com_sun_media_sound_MidiOutDevice_nClose; - Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp; - Java_com_sun_media_sound_MidiOutDevice_nOpen; - Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage; - Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage; - Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices; - Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo; - Java_com_sun_media_sound_PortMixer_nClose; - Java_com_sun_media_sound_PortMixer_nControlGetFloatValue; - Java_com_sun_media_sound_PortMixer_nControlGetIntValue; - Java_com_sun_media_sound_PortMixer_nControlSetFloatValue; - Java_com_sun_media_sound_PortMixer_nControlSetIntValue; - Java_com_sun_media_sound_PortMixer_nGetControls; - Java_com_sun_media_sound_PortMixer_nGetPortCount; - Java_com_sun_media_sound_PortMixer_nGetPortName; - Java_com_sun_media_sound_PortMixer_nGetPortType; - Java_com_sun_media_sound_PortMixer_nOpen; - local: - *; -}; diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003, 2015, 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_LinuxOS_ALSA_CommonUtils.h" + +static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) { +#ifdef USE_ERROR + va_list args; + va_start(args, fmt); + printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err)); + if (strlen(fmt) > 0) { + vprintf(fmt, args); + } + va_end(args); +#endif +} + +static int alsa_inited = 0; +static int alsa_enumerate_pcm_subdevices = FALSE; // default: no +static int alsa_enumerate_midi_subdevices = FALSE; // default: no + +/* + * Declare library specific JNI_Onload entry if static build + */ +DEF_STATIC_JNI_OnLoad + +void initAlsaSupport() { + char* enumerate; + if (!alsa_inited) { + alsa_inited = TRUE; + snd_lib_error_set_handler(&alsaDebugOutput); + + enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES); + if (enumerate != NULL && strlen(enumerate) > 0 + && (enumerate[0] != 'f') // false + && (enumerate[0] != 'F') // False + && (enumerate[0] != 'n') // no + && (enumerate[0] != 'N')) { // NO + alsa_enumerate_pcm_subdevices = TRUE; + } +#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES + alsa_enumerate_midi_subdevices = TRUE; +#endif + } +} + + +/* if true (non-zero), ALSA sub devices should be listed as separate devices + */ +int needEnumerateSubdevices(int isMidi) { + initAlsaSupport(); + return isMidi ? alsa_enumerate_midi_subdevices + : alsa_enumerate_pcm_subdevices; +} + + +/* + * deviceID contains packed card, device and subdevice numbers + * each number takes 10 bits + * "default" device has id == ALSA_DEFAULT_DEVICE_ID + */ +UINT32 encodeDeviceID(int card, int device, int subdevice) { + return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10) + | (subdevice & 0x3FF)) + 1; +} + + +void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, + int isMidi) { + deviceID--; + *card = (deviceID >> 20) & 0x3FF; + *device = (deviceID >> 10) & 0x3FF; + if (needEnumerateSubdevices(isMidi)) { + *subdevice = deviceID & 0x3FF; + } else { + *subdevice = -1; // ALSA will choose any subdevices + } +} + + +void getDeviceString(char* buffer, int card, int device, int subdevice, + int usePlugHw, int isMidi) { + if (needEnumerateSubdevices(isMidi)) { + sprintf(buffer, "%s:%d,%d,%d", + usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, + card, device, subdevice); + } else { + sprintf(buffer, "%s:%d,%d", + usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, + card, device); + } +} + + +void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, + int usePlugHw, int isMidi) { + int card, device, subdevice; + + if (deviceID == ALSA_DEFAULT_DEVICE_ID) { + strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME); + } else { + decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi); + getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi); + } +} + + +static int hasGottenALSAVersion = FALSE; +#define ALSAVersionString_LENGTH 200 +static char ALSAVersionString[ALSAVersionString_LENGTH]; + +void getALSAVersion(char* buffer, int len) { + if (!hasGottenALSAVersion) { + // get alsa version from proc interface + FILE* file; + int curr, len, totalLen, inVersionString; + file = fopen(ALSA_VERSION_PROC_FILE, "r"); + ALSAVersionString[0] = 0; + if (file) { + if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) { + // parse for version number + totalLen = strlen(ALSAVersionString); + inVersionString = FALSE; + len = 0; + curr = 0; + while (curr < totalLen) { + if (!inVersionString) { + // is this char the beginning of a version string ? + if (ALSAVersionString[curr] >= '0' + && ALSAVersionString[curr] <= '9') { + inVersionString = TRUE; + } + } + if (inVersionString) { + // the version string ends with white space + if (ALSAVersionString[curr] <= 32) { + break; + } + if (curr != len) { + // copy this char to the beginning of the string + ALSAVersionString[len] = ALSAVersionString[curr]; + } + len++; + } + curr++; + } + // remove trailing dots + while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { + len--; + } + // null terminate + ALSAVersionString[len] = 0; + } + fclose(file); + hasGottenALSAVersion = TRUE; + } + } + strncpy(buffer, ALSAVersionString, len); +} + + +/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 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. + */ + +#include +#include "Utilities.h" + +#ifndef PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED +#define PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED + +#define ALSA_VERSION_PROC_FILE "/proc/asound/version" +#define ALSA_HARDWARE "hw" +#define ALSA_HARDWARE_CARD ALSA_HARDWARE":%d" +#define ALSA_HARDWARE_DEVICE ALSA_HARDWARE_CARD",%d" +#define ALSA_HARDWARE_SUBDEVICE ALSA_HARDWARE_DEVICE",%d" + +#define ALSA_PLUGHARDWARE "plughw" +#define ALSA_DEFAULT_DEVICE_NAME "default" + +#define ALSA_DEFAULT_DEVICE_ID (0) + +#define ALSA_PCM (0) +#define ALSA_RAWMIDI (1) + +// for use in info objects +#define ALSA_VENDOR "ALSA (http://www.alsa-project.org)" + +// Environment variable for inclusion of subdevices in device listing. +// If this variable is unset or "no", then subdevices are ignored, and +// it's ALSA's choice which one to use (enables hardware mixing) +#define ENV_ENUMERATE_PCM_SUBDEVICES "ALSA_ENUMERATE_PCM_SUBDEVICES" + +// if defined, subdevices are listed. +//#undef ALSA_MIDI_ENUMERATE_SUBDEVICES +#define ALSA_MIDI_ENUMERATE_SUBDEVICES + +// must be called before any ALSA calls +void initAlsaSupport(); + +/* if true (non-zero), ALSA sub devices should be listed as separate devices + */ +int needEnumerateSubdevices(int isMidi); + + +/* + * deviceID contains packed card, device and subdevice numbers + * each number takes 10 bits + * "default" device has id == ALSA_DEFAULT_DEVICE_ID + */ +UINT32 encodeDeviceID(int card, int device, int subdevice); + +void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, + int isMidi); + +void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, + int usePlugHw, int isMidi); + +void getALSAVersion(char* buffer, int len); + + +#endif // PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2003, 2010, 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 + +#if USE_PLATFORM_MIDI_IN == TRUE + + +#include +#include "PlatformMidi.h" +#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" +#if defined(i586) +#include +#endif + +/* + * Helper methods + */ + +static inline UINT32 packMessage(int status, int data1, int data2) { + return ((status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16)); +} + + +static void setShortMessage(MidiMessage* message, + int status, int data1, int data2) { + message->type = SHORT_MESSAGE; + message->data.s.packedMsg = packMessage(status, data1, data2); +} + + +static void setRealtimeMessage(MidiMessage* message, int status) { + setShortMessage(message, status, 0, 0); +} + + +static void set14bitMessage(MidiMessage* message, int status, int value) { + TRACE3("14bit value: %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); + value &= 0x3FFF; + TRACE3("14bit value (2): %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); + setShortMessage(message, status, + value & 0x7F, + (value >> 7) & 0x7F); +} + + +/* + * implementation of the platform-dependent + * MIDI in functions declared in PlatformMidi.h + */ + +char* MIDI_IN_GetErrorStr(INT32 err) { + return (char*) getErrorStr(err); +} + +INT32 MIDI_IN_GetNumDevices() { +/* Workaround for 6842956: 32bit app on 64bit linux + * gets assertion failure trying to open midiIn ports. + * Untill the issue is fixed in ALSA + * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807) + * report no midi in devices in the configuration. + */ +#if defined(i586) + static int jre32onlinux64 = -1; + if (jre32onlinux64 < 0) { + jre32onlinux64 = 0; + /* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN" + * environment variable. + */ + if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) { + struct utsname u; + jre32onlinux64 = 0; + if (uname(&u) == 0) { + if (strstr(u.machine, "64") != NULL) { + TRACE0("jre32 on linux64 detected - report no midiIn devices\n"); + jre32onlinux64 = 1; + } + } + } + } + if (jre32onlinux64) { + return 0; + } +#endif + + TRACE0("MIDI_IN_GetNumDevices()\n"); + + return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT); +} + + +INT32 MIDI_IN_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { + int ret = getMidiDeviceName(SND_RAWMIDI_STREAM_INPUT, deviceIndex, + name, nameLength); + return ret; +} + + +INT32 MIDI_IN_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { + int ret = getMidiDeviceVendor(deviceIndex, name, nameLength); + return ret; +} + + +INT32 MIDI_IN_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { + int ret = getMidiDeviceDescription(SND_RAWMIDI_STREAM_INPUT, deviceIndex, + name, nameLength); + return ret; +} + + +INT32 MIDI_IN_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { + int ret = getMidiDeviceVersion(deviceIndex, name, nameLength); + return ret; +} + +/*************************************************************************/ + +INT32 MIDI_IN_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { + INT32 ret; + TRACE0("> MIDI_IN_OpenDevice\n"); + ret = openMidiDevice(SND_RAWMIDI_STREAM_INPUT, deviceIndex, handle); + TRACE1("< MIDI_IN_OpenDevice: returning %d\n", (int) ret); + return ret; +} + + +INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) { + INT32 ret; + TRACE0("> MIDI_IN_CloseDevice\n"); + ret = closeMidiDevice(handle); + TRACE1("< MIDI_IN_CloseDevice: returning %d\n", (int) ret); + return ret; +} + + +INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) { + TRACE0("MIDI_IN_StartDevice\n"); + return MIDI_SUCCESS; +} + + +INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) { + TRACE0("MIDI_IN_StopDevice\n"); + return MIDI_SUCCESS; +} + + +INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) { + return getMidiTimestamp(handle); +} + + +/* read the next message from the queue */ +MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) { + snd_seq_event_t alsa_message; + MidiMessage* jdk_message; + int err; + char buffer[1]; + int status; + + TRACE0("> MIDI_IN_GetMessage\n"); + if (!handle) { + ERROR0("< ERROR: MIDI_IN_GetMessage(): handle is NULL\n"); + return NULL; + } + if (!handle->deviceHandle) { + ERROR0("< ERROR: MIDI_IN_GetMessage(): native handle is NULL\n"); + return NULL; + } + if (!handle->platformData) { + ERROR0("< ERROR: MIDI_IN_GetMessage(): platformData is NULL\n"); + return NULL; + } + + /* For MIDI In, the device is left in non blocking mode. So if there is + no data from the device, snd_rawmidi_read() returns with -11 (EAGAIN). + This results in jumping back to the Java layer. */ + while (TRUE) { + TRACE0("before snd_rawmidi_read()\n"); + err = snd_rawmidi_read((snd_rawmidi_t*) handle->deviceHandle, buffer, 1); + TRACE0("after snd_rawmidi_read()\n"); + if (err != 1) { + ERROR2("< ERROR: MIDI_IN_GetMessage(): snd_rawmidi_read() returned %d : %s\n", err, snd_strerror(err)); + return NULL; + } + // printf("received byte: %d\n", buffer[0]); + err = snd_midi_event_encode_byte((snd_midi_event_t*) handle->platformData, + (int) buffer[0], + &alsa_message); + if (err == 1) { + break; + } else if (err < 0) { + ERROR1("< ERROR: MIDI_IN_GetMessage(): snd_midi_event_encode_byte() returned %d\n", err); + return NULL; + } + } + jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1); + if (!jdk_message) { + ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); + return NULL; + } + // TODO: tra + switch (alsa_message.type) { + case SND_SEQ_EVENT_NOTEON: + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + status = (alsa_message.type == SND_SEQ_EVENT_KEYPRESS) ? 0xA0 : + (alsa_message.type == SND_SEQ_EVENT_NOTEON) ? 0x90 : 0x80; + status |= alsa_message.data.note.channel; + setShortMessage(jdk_message, status, + alsa_message.data.note.note, + alsa_message.data.note.velocity); + break; + + case SND_SEQ_EVENT_CONTROLLER: + status = 0xB0 | alsa_message.data.control.channel; + setShortMessage(jdk_message, status, + alsa_message.data.control.param, + alsa_message.data.control.value); + break; + + case SND_SEQ_EVENT_PGMCHANGE: + case SND_SEQ_EVENT_CHANPRESS: + status = (alsa_message.type == SND_SEQ_EVENT_PGMCHANGE) ? 0xC0 : 0xD0; + status |= alsa_message.data.control.channel; + setShortMessage(jdk_message, status, + alsa_message.data.control.value, 0); + break; + + case SND_SEQ_EVENT_PITCHBEND: + status = 0xE0 | alsa_message.data.control.channel; + // $$mp 2003-09-23: + // possible hack to work around a bug in ALSA. Necessary for + // ALSA 0.9.2. May be fixed in newer versions of ALSA. + // alsa_message.data.control.value ^= 0x2000; + // TRACE1("pitchbend value: %d\n", alsa_message.data.control.value); + set14bitMessage(jdk_message, status, + alsa_message.data.control.value); + break; + + /* System exclusive messages */ + + case SND_SEQ_EVENT_SYSEX: + jdk_message->type = LONG_MESSAGE; + jdk_message->data.l.size = alsa_message.data.ext.len; + jdk_message->data.l.data = malloc(alsa_message.data.ext.len); + if (jdk_message->data.l.data == NULL) { + ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); + free(jdk_message); + jdk_message = NULL; + } else { + memcpy(jdk_message->data.l.data, alsa_message.data.ext.ptr, alsa_message.data.ext.len); + } + break; + + /* System common messages */ + + case SND_SEQ_EVENT_QFRAME: + setShortMessage(jdk_message, 0xF1, + alsa_message.data.control.value & 0x7F, 0); + break; + + case SND_SEQ_EVENT_SONGPOS: + set14bitMessage(jdk_message, 0xF2, + alsa_message.data.control.value); + break; + + case SND_SEQ_EVENT_SONGSEL: + setShortMessage(jdk_message, 0xF3, + alsa_message.data.control.value & 0x7F, 0); + break; + + case SND_SEQ_EVENT_TUNE_REQUEST: + setRealtimeMessage(jdk_message, 0xF6); + break; + + /* System realtime messages */ + + case SND_SEQ_EVENT_CLOCK: + setRealtimeMessage(jdk_message, 0xF8); + break; + + case SND_SEQ_EVENT_START: + setRealtimeMessage(jdk_message, 0xFA); + break; + + case SND_SEQ_EVENT_CONTINUE: + setRealtimeMessage(jdk_message, 0xFB); + break; + + case SND_SEQ_EVENT_STOP: + setRealtimeMessage(jdk_message, 0xFC); + break; + + case SND_SEQ_EVENT_SENSING: + setRealtimeMessage(jdk_message, 0xFE); + break; + + case SND_SEQ_EVENT_RESET: + setRealtimeMessage(jdk_message, 0xFF); + break; + + default: + ERROR0("< ERROR: MIDI_IN_GetMessage(): unhandled ALSA MIDI message type\n"); + free(jdk_message); + jdk_message = NULL; + + } + + // set timestamp + if (jdk_message != NULL) { + jdk_message->timestamp = getMidiTimestamp(handle); + } + TRACE1("< MIDI_IN_GetMessage: returning %p\n", jdk_message); + return jdk_message; +} + + +void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) { + if (!msg) { + ERROR0("< ERROR: MIDI_IN_ReleaseMessage(): message is NULL\n"); + return; + } + if (msg->type == LONG_MESSAGE && msg->data.l.data) { + free(msg->data.l.data); + } + free(msg); +} + +#endif /* USE_PLATFORM_MIDI_IN */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2003, 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 + +#if USE_PLATFORM_MIDI_OUT == TRUE + +#include +#include "PlatformMidi.h" +#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" + + + +static int CHANNEL_MESSAGE_LENGTH[] = { + -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 3, 3, 2, 2, 3 }; +/* 8x 9x Ax Bx Cx Dx Ex */ + +static int SYSTEM_MESSAGE_LENGTH[] = { + -1, 2, 3, 2, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1 }; +/* F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF */ + + +// the returned length includes the status byte. +// for illegal messages, -1 is returned. +static int getShortMessageLength(int status) { + int dataLength = 0; + if (status < 0xF0) { // channel voice message + dataLength = CHANNEL_MESSAGE_LENGTH[(status >> 4) & 0xF]; + } else { + dataLength = SYSTEM_MESSAGE_LENGTH[status & 0xF]; + } + return dataLength; +} + + +/* + * implementation of the platform-dependent + * MIDI out functions declared in PlatformMidi.h + */ +char* MIDI_OUT_GetErrorStr(INT32 err) { + return (char*) getErrorStr(err); +} + + +INT32 MIDI_OUT_GetNumDevices() { + TRACE0("MIDI_OUT_GetNumDevices()\n"); + return getMidiDeviceCount(SND_RAWMIDI_STREAM_OUTPUT); +} + + +INT32 MIDI_OUT_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { + TRACE0("MIDI_OUT_GetDeviceName()\n"); + return getMidiDeviceName(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, + name, nameLength); +} + + +INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { + TRACE0("MIDI_OUT_GetDeviceVendor()\n"); + return getMidiDeviceVendor(deviceIndex, name, nameLength); +} + + +INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { + TRACE0("MIDI_OUT_GetDeviceDescription()\n"); + return getMidiDeviceDescription(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, + name, nameLength); +} + + +INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { + TRACE0("MIDI_OUT_GetDeviceVersion()\n"); + return getMidiDeviceVersion(deviceIndex, name, nameLength); +} + + +/* *************************** MidiOutDevice implementation *************** */ + +INT32 MIDI_OUT_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { + TRACE1("MIDI_OUT_OpenDevice(): deviceIndex: %d\n", (int) deviceIndex); + return openMidiDevice(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, handle); +} + + +INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { + TRACE0("MIDI_OUT_CloseDevice()\n"); + return closeMidiDevice(handle); +} + + +INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { + return getMidiTimestamp(handle); +} + + +INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, + UINT32 timestamp) { + int err; + int status; + int data1; + int data2; + char buffer[3]; + + TRACE2("> MIDI_OUT_SendShortMessage() %x, time: %u\n", packedMsg, (unsigned int) timestamp); + if (!handle) { + ERROR0("< ERROR: MIDI_OUT_SendShortMessage(): handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + if (!handle->deviceHandle) { + ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + status = (packedMsg & 0xFF); + buffer[0] = (char) status; + buffer[1] = (char) ((packedMsg >> 8) & 0xFF); + buffer[2] = (char) ((packedMsg >> 16) & 0xFF); + TRACE4("status: %d, data1: %d, data2: %d, length: %d\n", (int) buffer[0], (int) buffer[1], (int) buffer[2], getShortMessageLength(status)); + err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, buffer, getShortMessageLength(status)); + if (err < 0) { + ERROR1(" ERROR: MIDI_OUT_SendShortMessage(): snd_rawmidi_write() returned %d\n", err); + } + + TRACE0("< MIDI_OUT_SendShortMessage()\n"); + return err; +} + + +INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, + UINT32 size, UINT32 timestamp) { + int err; + + TRACE2("> MIDI_OUT_SendLongMessage() size %u, time: %u\n", (unsigned int) size, (unsigned int) timestamp); + if (!handle) { + ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + if (!handle->deviceHandle) { + ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + if (!data) { + ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): data is NULL\n"); + return MIDI_INVALID_HANDLE; + } + err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, + data, size); + if (err < 0) { + ERROR1(" ERROR: MIDI_OUT_SendLongMessage(): snd_rawmidi_write() returned %d\n", err); + } + + TRACE0("< MIDI_OUT_SendLongMessage()\n"); + return err; +} + + +#endif /* USE_PLATFORM_MIDI_OUT */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2003, 2014, 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_LinuxOS_ALSA_MidiUtils.h" +#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" +#include +#include + +static INT64 getTimeInMicroseconds() { + struct timeval tv; + + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000UL) + tv.tv_usec; +} + + +const char* getErrorStr(INT32 err) { + return snd_strerror((int) err); +} + + + +// callback for iteration through devices +// returns TRUE if iteration should continue +typedef int (*DeviceIteratorPtr)(UINT32 deviceID, + snd_rawmidi_info_t* rawmidi_info, + snd_ctl_card_info_t* cardinfo, + void *userData); + +// for each ALSA device, call iterator. userData is passed to the iterator +// returns total number of iterations +static int iterateRawmidiDevices(snd_rawmidi_stream_t direction, + DeviceIteratorPtr iterator, + void* userData) { + int count = 0; + int subdeviceCount; + int card, dev, subDev; + char devname[16]; + int err; + snd_ctl_t *handle; + snd_rawmidi_t *rawmidi; + snd_rawmidi_info_t *rawmidi_info; + snd_ctl_card_info_t *card_info, *defcardinfo = NULL; + UINT32 deviceID; + int doContinue = TRUE; + + snd_rawmidi_info_malloc(&rawmidi_info); + snd_ctl_card_info_malloc(&card_info); + + // 1st try "default" device + if (direction == SND_RAWMIDI_STREAM_INPUT) { + err = snd_rawmidi_open(&rawmidi, NULL, ALSA_DEFAULT_DEVICE_NAME, + SND_RAWMIDI_NONBLOCK); + } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { + err = snd_rawmidi_open(NULL, &rawmidi, ALSA_DEFAULT_DEVICE_NAME, + SND_RAWMIDI_NONBLOCK); + } else { + ERROR0("ERROR: iterateRawmidiDevices(): direction is neither" + " SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); + err = MIDI_INVALID_ARGUMENT; + } + if (err < 0) { + ERROR1("ERROR: snd_rawmidi_open (\"default\"): %s\n", + snd_strerror(err)); + } else { + err = snd_rawmidi_info(rawmidi, rawmidi_info); + + snd_rawmidi_close(rawmidi); + if (err < 0) { + ERROR1("ERROR: snd_rawmidi_info (\"default\"): %s\n", + snd_strerror(err)); + } else { + // try to get card info + card = snd_rawmidi_info_get_card(rawmidi_info); + if (card >= 0) { + sprintf(devname, ALSA_HARDWARE_CARD, card); + if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { + if (snd_ctl_card_info(handle, card_info) >= 0) { + defcardinfo = card_info; + } + snd_ctl_close(handle); + } + } + // call calback function for the device + if (iterator != NULL) { + doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, rawmidi_info, + defcardinfo, userData); + } + count++; + } + } + + // iterate cards + card = -1; + TRACE0("testing for cards...\n"); + if (snd_card_next(&card) >= 0) { + TRACE1("Found card %d\n", card); + while (doContinue && (card >= 0)) { + sprintf(devname, ALSA_HARDWARE_CARD, card); + TRACE1("Opening control for alsa rawmidi device \"%s\"...\n", devname); + err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); + if (err < 0) { + ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); + } else { + TRACE0("snd_ctl_open() SUCCESS\n"); + err = snd_ctl_card_info(handle, card_info); + if (err < 0) { + ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err)); + } else { + TRACE0("snd_ctl_card_info() SUCCESS\n"); + dev = -1; + while (doContinue) { + if (snd_ctl_rawmidi_next_device(handle, &dev) < 0) { + ERROR0("snd_ctl_rawmidi_next_device\n"); + } + TRACE0("snd_ctl_rawmidi_next_device() SUCCESS\n"); + if (dev < 0) { + break; + } + snd_rawmidi_info_set_device(rawmidi_info, dev); + snd_rawmidi_info_set_subdevice(rawmidi_info, 0); + snd_rawmidi_info_set_stream(rawmidi_info, direction); + err = snd_ctl_rawmidi_info(handle, rawmidi_info); + TRACE0("after snd_ctl_rawmidi_info()\n"); + if (err < 0) { + if (err != -ENOENT) { + ERROR2("ERROR: snd_ctl_rawmidi_info, card=%d: %s", card, snd_strerror(err)); + } + } else { + TRACE0("snd_ctl_rawmidi_info() SUCCESS\n"); + subdeviceCount = needEnumerateSubdevices(ALSA_RAWMIDI) + ? snd_rawmidi_info_get_subdevices_count(rawmidi_info) + : 1; + if (iterator!=NULL) { + for (subDev = 0; subDev < subdeviceCount; subDev++) { + TRACE3(" Iterating %d,%d,%d\n", card, dev, subDev); + deviceID = encodeDeviceID(card, dev, subDev); + doContinue = (*iterator)(deviceID, rawmidi_info, + card_info, userData); + count++; + TRACE0("returned from iterator\n"); + if (!doContinue) { + break; + } + } + } else { + count += subdeviceCount; + } + } + } // of while(doContinue) + } + snd_ctl_close(handle); + } + if (snd_card_next(&card) < 0) { + break; + } + } + } else { + ERROR0("No cards found!\n"); + } + snd_ctl_card_info_free(card_info); + snd_rawmidi_info_free(rawmidi_info); + return count; +} + + + +int getMidiDeviceCount(snd_rawmidi_stream_t direction) { + int deviceCount; + TRACE0("> getMidiDeviceCount()\n"); + initAlsaSupport(); + deviceCount = iterateRawmidiDevices(direction, NULL, NULL); + TRACE0("< getMidiDeviceCount()\n"); + return deviceCount; +} + + + +/* + userData is assumed to be a pointer to ALSA_MIDIDeviceDescription. + ALSA_MIDIDeviceDescription->index has to be set to the index of the device + we want to get information of before this method is called the first time via + iterateRawmidiDevices(). On each call of this method, + ALSA_MIDIDeviceDescription->index is decremented. If it is equal to zero, + we have reached the desired device, so action is taken. + So after successful completion of iterateRawmidiDevices(), + ALSA_MIDIDeviceDescription->index is zero. If it isn't, this is an + indication of an error. +*/ +static int deviceInfoIterator(UINT32 deviceID, snd_rawmidi_info_t *rawmidi_info, + snd_ctl_card_info_t *cardinfo, void *userData) { + char buffer[300]; + ALSA_MIDIDeviceDescription* desc = (ALSA_MIDIDeviceDescription*)userData; +#ifdef ALSA_MIDI_USE_PLUGHW + int usePlugHw = 1; +#else + int usePlugHw = 0; +#endif + + TRACE0("deviceInfoIterator\n"); + initAlsaSupport(); + if (desc->index == 0) { + // we found the device with correct index + desc->deviceID = deviceID; + + buffer[0]=' '; buffer[1]='['; + // buffer[300] is enough to store the actual device string w/o overrun + getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_RAWMIDI); + strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); + strncpy(desc->name, + (cardinfo != NULL) + ? snd_ctl_card_info_get_id(cardinfo) + : snd_rawmidi_info_get_id(rawmidi_info), + desc->strLen - strlen(buffer)); + strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); + desc->description[0] = 0; + if (cardinfo != NULL) { + strncpy(desc->description, snd_ctl_card_info_get_name(cardinfo), + desc->strLen); + strncat(desc->description, ", ", + desc->strLen - strlen(desc->description)); + } + strncat(desc->description, snd_rawmidi_info_get_id(rawmidi_info), + desc->strLen - strlen(desc->description)); + strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); + strncat(desc->description, snd_rawmidi_info_get_name(rawmidi_info), + desc->strLen - strlen(desc->description)); + TRACE2("Returning %s, %s\n", desc->name, desc->description); + return FALSE; // do not continue iteration + } + desc->index--; + return TRUE; +} + + +static int getMIDIDeviceDescriptionByIndex(snd_rawmidi_stream_t direction, + ALSA_MIDIDeviceDescription* desc) { + initAlsaSupport(); + TRACE1(" getMIDIDeviceDescriptionByIndex (index = %d)\n", desc->index); + iterateRawmidiDevices(direction, &deviceInfoIterator, desc); + return (desc->index == 0) ? MIDI_SUCCESS : MIDI_INVALID_DEVICEID; +} + + + +int initMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc, int index) { + int ret = MIDI_SUCCESS; + desc->index = index; + desc->strLen = 200; + desc->name = (char*) calloc(desc->strLen + 1, 1); + desc->description = (char*) calloc(desc->strLen + 1, 1); + if (! desc->name || + ! desc->description) { + ret = MIDI_OUT_OF_MEMORY; + } + return ret; +} + + +void freeMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc) { + if (desc->name) { + free(desc->name); + } + if (desc->description) { + free(desc->description); + } +} + + +int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, char *name, + UINT32 nameLength) { + ALSA_MIDIDeviceDescription desc; + int ret; + + TRACE1("getMidiDeviceName: nameLength: %d\n", (int) nameLength); + ret = initMIDIDeviceDescription(&desc, index); + if (ret == MIDI_SUCCESS) { + TRACE0("getMidiDeviceName: initMIDIDeviceDescription() SUCCESS\n"); + ret = getMIDIDeviceDescriptionByIndex(direction, &desc); + if (ret == MIDI_SUCCESS) { + TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); + strncpy(name, desc.name, nameLength - 1); + name[nameLength - 1] = 0; + } + } + freeMIDIDeviceDescription(&desc); + return ret; +} + + +int getMidiDeviceVendor(int index, char *name, UINT32 nameLength) { + strncpy(name, ALSA_VENDOR, nameLength - 1); + name[nameLength - 1] = 0; + return MIDI_SUCCESS; +} + + +int getMidiDeviceDescription(snd_rawmidi_stream_t direction, + int index, char *name, UINT32 nameLength) { + ALSA_MIDIDeviceDescription desc; + int ret; + + ret = initMIDIDeviceDescription(&desc, index); + if (ret == MIDI_SUCCESS) { + ret = getMIDIDeviceDescriptionByIndex(direction, &desc); + if (ret == MIDI_SUCCESS) { + strncpy(name, desc.description, nameLength - 1); + name[nameLength - 1] = 0; + } + } + freeMIDIDeviceDescription(&desc); + return ret; +} + + +int getMidiDeviceVersion(int index, char *name, UINT32 nameLength) { + getALSAVersion(name, nameLength); + return MIDI_SUCCESS; +} + + +static int getMidiDeviceID(snd_rawmidi_stream_t direction, int index, + UINT32* deviceID) { + ALSA_MIDIDeviceDescription desc; + int ret; + + ret = initMIDIDeviceDescription(&desc, index); + if (ret == MIDI_SUCCESS) { + ret = getMIDIDeviceDescriptionByIndex(direction, &desc); + if (ret == MIDI_SUCCESS) { + // TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); + *deviceID = desc.deviceID; + } + } + freeMIDIDeviceDescription(&desc); + return ret; +} + + +/* + direction has to be either SND_RAWMIDI_STREAM_INPUT or + SND_RAWMIDI_STREAM_OUTPUT. + Returns 0 on success. Otherwise, MIDI_OUT_OF_MEMORY, MIDI_INVALID_ARGUMENT + or a negative ALSA error code is returned. +*/ +INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, + MidiDeviceHandle** handle) { + snd_rawmidi_t* native_handle; + snd_midi_event_t* event_parser = NULL; + int err; + UINT32 deviceID = 0; + char devicename[100]; +#ifdef ALSA_MIDI_USE_PLUGHW + int usePlugHw = 1; +#else + int usePlugHw = 0; +#endif + + TRACE0("> openMidiDevice()\n"); + + (*handle) = (MidiDeviceHandle*) calloc(sizeof(MidiDeviceHandle), 1); + if (!(*handle)) { + ERROR0("ERROR: openDevice: out of memory\n"); + return MIDI_OUT_OF_MEMORY; + } + + // TODO: iterate to get dev ID from index + err = getMidiDeviceID(direction, deviceIndex, &deviceID); + TRACE1(" openMidiDevice(): deviceID: %d\n", (int) deviceID); + getDeviceStringFromDeviceID(devicename, deviceID, + usePlugHw, ALSA_RAWMIDI); + TRACE1(" openMidiDevice(): deviceString: %s\n", devicename); + + // finally open the device + if (direction == SND_RAWMIDI_STREAM_INPUT) { + err = snd_rawmidi_open(&native_handle, NULL, devicename, + SND_RAWMIDI_NONBLOCK); + } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { + err = snd_rawmidi_open(NULL, &native_handle, devicename, + SND_RAWMIDI_NONBLOCK); + } else { + ERROR0(" ERROR: openMidiDevice(): direction is neither SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); + err = MIDI_INVALID_ARGUMENT; + } + if (err < 0) { + ERROR1("< ERROR: openMidiDevice(): snd_rawmidi_open() returned %d\n", err); + free(*handle); + (*handle) = NULL; + return err; + } + /* We opened with non-blocking behaviour to not get hung if the device + is used by a different process. Writing, however, should + be blocking. So we change it here. */ + if (direction == SND_RAWMIDI_STREAM_OUTPUT) { + err = snd_rawmidi_nonblock(native_handle, 0); + if (err < 0) { + ERROR1(" ERROR: openMidiDevice(): snd_rawmidi_nonblock() returned %d\n", err); + snd_rawmidi_close(native_handle); + free(*handle); + (*handle) = NULL; + return err; + } + } + if (direction == SND_RAWMIDI_STREAM_INPUT) { + err = snd_midi_event_new(EVENT_PARSER_BUFSIZE, &event_parser); + if (err < 0) { + ERROR1(" ERROR: openMidiDevice(): snd_midi_event_new() returned %d\n", err); + snd_rawmidi_close(native_handle); + free(*handle); + (*handle) = NULL; + return err; + } + } + + (*handle)->deviceHandle = (void*) native_handle; + (*handle)->startTime = getTimeInMicroseconds(); + (*handle)->platformData = event_parser; + TRACE0("< openMidiDevice(): succeeded\n"); + return err; +} + + + +INT32 closeMidiDevice(MidiDeviceHandle* handle) { + int err; + + TRACE0("> closeMidiDevice()\n"); + if (!handle) { + ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + if (!handle->deviceHandle) { + ERROR0("< ERROR: closeMidiDevice(): native handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + err = snd_rawmidi_close((snd_rawmidi_t*) handle->deviceHandle); + TRACE1(" snd_rawmidi_close() returns %d\n", err); + if (handle->platformData) { + snd_midi_event_free((snd_midi_event_t*) handle->platformData); + } + free(handle); + TRACE0("< closeMidiDevice: succeeded\n"); + return err; +} + + +INT64 getMidiTimestamp(MidiDeviceHandle* handle) { + if (!handle) { + ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); + return MIDI_INVALID_HANDLE; + } + return getTimeInMicroseconds() - handle->startTime; +} + + +/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2003, 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. + */ + +#include +#include "Utilities.h" +#include "PlatformMidi.h" + + +#ifndef PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED +#define PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED + +#define EVENT_PARSER_BUFSIZE (2048) + +// if this is defined, use plughw: devices +//#define ALSA_MIDI_USE_PLUGHW +#undef ALSA_MIDI_USE_PLUGHW + +typedef struct tag_ALSA_MIDIDeviceDescription { + int index; // in + int strLen; // in + INT32 deviceID; // out + char* name; // out + char* description; // out +} ALSA_MIDIDeviceDescription; + + +const char* getErrorStr(INT32 err); + +/* Returns the number of devices. */ +/* direction is either SND_RAWMIDI_STREAM_OUTPUT or + SND_RAWMIDI_STREAM_INPUT. */ +int getMidiDeviceCount(snd_rawmidi_stream_t direction); + +/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ +/* direction is either SND_RAWMIDI_STREAM_OUTPUT or + SND_RAWMIDI_STREAM_INPUT. */ +int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, + char *name, UINT32 nameLength); + +/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ +int getMidiDeviceVendor(int index, char *name, UINT32 nameLength); + +/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ +/* direction is either SND_RAWMIDI_STREAM_OUTPUT or + SND_RAWMIDI_STREAM_INPUT. */ +int getMidiDeviceDescription(snd_rawmidi_stream_t direction, int index, + char *name, UINT32 nameLength); + +/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ +int getMidiDeviceVersion(int index, char *name, UINT32 nameLength); + +// returns 0 on success, otherwise MIDI_OUT_OF_MEMORY or ALSA error code +/* direction is either SND_RAWMIDI_STREAM_OUTPUT or + SND_RAWMIDI_STREAM_INPUT. */ +INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, + MidiDeviceHandle** handle); + +// returns 0 on success, otherwise a (negative) ALSA error code +INT32 closeMidiDevice(MidiDeviceHandle* handle); + +INT64 getMidiTimestamp(MidiDeviceHandle* handle); + +#endif // PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2002, 2011, 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_LinuxOS_ALSA_PCMUtils.h" +#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" +#include "DirectAudio.h" + +#if USE_DAUDIO == TRUE + +// GetPosition method 1: based on how many bytes are passed to the kernel driver +// + does not need much processor resources +// - not very exact, "jumps" +// GetPosition method 2: ask kernel about actual position of playback. +// - very exact +// - switch to kernel layer for each call +// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA +// quick tests on a Pentium 200MMX showed max. 1.5% processor usage +// for playing back a CD-quality file and printing 20x per second a line +// on the console with the current time. So I guess performance is not such a +// factor here. +//#define GET_POSITION_METHOD1 +#define GET_POSITION_METHOD2 + + +// The default time for a period in microseconds. +// For very small buffers, only 2 periods are used. +#define DEFAULT_PERIOD_TIME 20000 /* 20ms */ + +///// implemented functions of DirectAudio.h + +INT32 DAUDIO_GetDirectAudioDeviceCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) { + ALSA_AudioDeviceDescription adesc; + + adesc.index = (int) mixerIndex; + adesc.strLen = DAUDIO_STRING_LENGTH; + + adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines)); + adesc.deviceID = &(description->deviceID); + adesc.name = description->name; + adesc.vendor = description->vendor; + adesc.description = description->description; + adesc.version = description->version; + + return getAudioDeviceDescriptionByIndex(&adesc); +} + +#define MAX_BIT_INDEX 6 +// returns +// 6: for anything above 24-bit +// 5: for 4 bytes sample size, 24-bit +// 4: for 3 bytes sample size, 24-bit +// 3: for 3 bytes sample size, 20-bit +// 2: for 2 bytes sample size, 16-bit +// 1: for 1 byte sample size, 8-bit +// 0: for anything else +int getBitIndex(int sampleSizeInBytes, int significantBits) { + if (significantBits > 24) return 6; + if (sampleSizeInBytes == 4 && significantBits == 24) return 5; + if (sampleSizeInBytes == 3) { + if (significantBits == 24) return 4; + if (significantBits == 20) return 3; + } + if (sampleSizeInBytes == 2 && significantBits == 16) return 2; + if (sampleSizeInBytes == 1 && significantBits == 8) return 1; + return 0; +} + +int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) { + switch(bitIndex) { + case 1: return 1; + case 2: return 2; + case 3: /* fall through */ + case 4: return 3; + case 5: return 4; + } + return sampleSizeInBytes; +} + +int getSignificantBits(int bitIndex, int significantBits) { + switch(bitIndex) { + case 1: return 8; + case 2: return 16; + case 3: return 20; + case 4: /* fall through */ + case 5: return 24; + } + return significantBits; +} + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { + snd_pcm_t* handle; + snd_pcm_format_mask_t* formatMask; + snd_pcm_format_t format; + snd_pcm_hw_params_t* hwParams; + int handledBits[MAX_BIT_INDEX+1]; + + int ret; + int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; + int origSampleSizeInBytes, origSignificantBits; + unsigned int channels, minChannels, maxChannels; + int rate, bitIndex; + + for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; + if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { + return; + } + ret = snd_pcm_format_mask_malloc(&formatMask); + if (ret != 0) { + ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); + } else { + ret = snd_pcm_hw_params_malloc(&hwParams); + if (ret != 0) { + ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); + } else { + ret = snd_pcm_hw_params_any(handle, hwParams); + /* snd_pcm_hw_params_any can return a positive value on success too */ + if (ret < 0) { + ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); + } else { + /* for the logic following this code, set ret to 0 to indicate success */ + ret = 0; + } + } + snd_pcm_hw_params_get_format_mask(hwParams, formatMask); + if (ret == 0) { + ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); + if (ret != 0) { + ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); + } + } + if (ret == 0) { + ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); + if (ret != 0) { + ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); + } + } + + // since we queried the hw: device, for many soundcards, it will only + // report the maximum number of channels (which is the only way to talk + // to the hw: device). Since we will, however, open the plughw: device + // when opening the Source/TargetDataLine, we can safely assume that + // also the channels 1..maxChannels are available. +#ifdef ALSA_PCM_USE_PLUGHW + minChannels = 1; +#endif + if (ret == 0) { + // plughw: supports any sample rate + rate = -1; + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (snd_pcm_format_mask_test(formatMask, format)) { + // format exists + if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, + &origSignificantBits, + &isSigned, &isBigEndian, &enc)) { + // now if we use plughw:, we can use any bit size below the + // natively supported ones. Some ALSA drivers only support the maximum + // bit size, so we add any sample rates below the reported one. + // E.g. this iteration reports support for 16-bit. + // getBitIndex will return 2, so it will add entries for + // 16-bit (bitIndex=2) and in the next do-while loop iteration, + // it will decrease bitIndex and will therefore add 8-bit support. + bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); + do { + if (bitIndex == 0 + || bitIndex == MAX_BIT_INDEX + || !handledBits[bitIndex]) { + handledBits[bitIndex] = TRUE; + sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); + significantBits = getSignificantBits(bitIndex, origSignificantBits); + if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { + // avoid too many channels explicitly listed + // just add -1, min, and max + DAUDIO_AddAudioFormat(creator, significantBits, + -1, -1, rate, + enc, isSigned, isBigEndian); + DAUDIO_AddAudioFormat(creator, significantBits, + sampleSizeInBytes * minChannels, + minChannels, rate, + enc, isSigned, isBigEndian); + DAUDIO_AddAudioFormat(creator, significantBits, + sampleSizeInBytes * maxChannels, + maxChannels, rate, + enc, isSigned, isBigEndian); + } else { + for (channels = minChannels; channels <= maxChannels; channels++) { + DAUDIO_AddAudioFormat(creator, significantBits, + sampleSizeInBytes * channels, + channels, rate, + enc, isSigned, isBigEndian); + } + } + } +#ifndef ALSA_PCM_USE_PLUGHW + // without plugin, do not add fake formats + break; +#endif + } while (--bitIndex > 0); + } else { + TRACE1("could not get format from alsa for format %d\n", format); + } + } else { + //TRACE1("Format %d not supported\n", format); + } + } // for loop + snd_pcm_hw_params_free(hwParams); + } + snd_pcm_format_mask_free(formatMask); + } + snd_pcm_close(handle); +} + +/** Workaround for cr 7033899, 7030629: + * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty + * (just opened, underruned or already flushed). + * Sometimes it causes PCM falls to -EBADFD error, + * sometimes causes bufferSize change. + * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used. + */ +/* ******* ALSA PCM INFO ******************** */ +typedef struct tag_AlsaPcmInfo { + snd_pcm_t* handle; + snd_pcm_hw_params_t* hwParams; + snd_pcm_sw_params_t* swParams; + int bufferSizeInBytes; + int frameSize; // storage size in Bytes + unsigned int periods; + snd_pcm_uframes_t periodSize; + short int isRunning; // see comment above + short int isFlushed; // see comment above +#ifdef GET_POSITION_METHOD2 + // to be used exclusively by getBytePosition! + snd_pcm_status_t* positionStatus; +#endif +} AlsaPcmInfo; + + +int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) { + int ret; + int threshold; + + if (useThreshold) { + // start device whenever anything is written to the buffer + threshold = 1; + } else { + // never start the device automatically + threshold = 2000000000; /* near UINT_MAX */ + } + ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold); + if (ret < 0) { + ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret)); + return FALSE; + } + return TRUE; +} + +int setStartThreshold(AlsaPcmInfo* info, int useThreshold) { + int ret = 0; + + if (!setStartThresholdNoCommit(info, useThreshold)) { + ret = -1; + } + if (ret == 0) { + // commit it + ret = snd_pcm_sw_params(info->handle, info->swParams); + if (ret < 0) { + ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); + } + } + return (ret == 0)?TRUE:FALSE; +} + + +// returns TRUE if successful +int setHWParams(AlsaPcmInfo* info, + float sampleRate, + int channels, + int bufferSizeInFrames, + snd_pcm_format_t format) { + unsigned int rrate, periodTime, periods; + int ret, dir; + snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; + + /* choose all parameters */ + ret = snd_pcm_hw_params_any(info->handle, info->hwParams); + if (ret < 0) { + ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret)); + return FALSE; + } + /* set the interleaved read/write format */ + ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); + if (ret < 0) { + ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret)); + return FALSE; + } + /* set the sample format */ + ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format); + if (ret < 0) { + ERROR1("Sample format not available: %s\n", snd_strerror(ret)); + return FALSE; + } + /* set the count of channels */ + ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels); + if (ret < 0) { + ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret)); + return FALSE; + } + /* set the stream rate */ + rrate = (int) (sampleRate + 0.5f); + dir = 0; + ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); + if (ret < 0) { + ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); + return FALSE; + } + if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) { + ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate); + return FALSE; + } + /* set the buffer time */ + ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); + if (ret < 0) { + ERROR2("Unable to set buffer size to %d frames: %s\n", + (int) alsaBufferSizeInFrames, snd_strerror(ret)); + return FALSE; + } + bufferSizeInFrames = (int) alsaBufferSizeInFrames; + /* set the period time */ + if (bufferSizeInFrames > 1024) { + dir = 0; + periodTime = DEFAULT_PERIOD_TIME; + ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); + if (ret < 0) { + ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); + return FALSE; + } + } else { + /* set the period count for very small buffer sizes to 2 */ + dir = 0; + periods = 2; + ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); + if (ret < 0) { + ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); + return FALSE; + } + } + /* write the parameters to device */ + ret = snd_pcm_hw_params(info->handle, info->hwParams); + if (ret < 0) { + ERROR1("Unable to set hw params: %s\n", snd_strerror(ret)); + return FALSE; + } + return TRUE; +} + +// returns 1 if successful +int setSWParams(AlsaPcmInfo* info) { + int ret; + + /* get the current swparams */ + ret = snd_pcm_sw_params_current(info->handle, info->swParams); + if (ret < 0) { + ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret)); + return FALSE; + } + /* never start the transfer automatically */ + if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) { + return FALSE; + } + + /* allow the transfer when at least period_size samples can be processed */ + ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize); + if (ret < 0) { + ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); + return FALSE; + } + /* write the parameters to the playback device */ + ret = snd_pcm_sw_params(info->handle, info->swParams); + if (ret < 0) { + ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); + return FALSE; + } + return TRUE; +} + +static snd_output_t* ALSA_OUTPUT = NULL; + +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) { + snd_pcm_format_mask_t* formatMask; + snd_pcm_format_t format; + int dir; + int ret = 0; + AlsaPcmInfo* info = NULL; + /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ + snd_pcm_uframes_t alsaBufferSizeInFrames = 0; + + + TRACE0("> DAUDIO_Open\n"); +#ifdef USE_TRACE + // for using ALSA debug dump methods + if (ALSA_OUTPUT == NULL) { + snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); + } +#endif + if (channels <= 0) { + ERROR1("ERROR: Invalid number of channels=%d!\n", channels); + return NULL; + } + info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); + if (!info) { + ERROR0("Out of memory\n"); + return NULL; + } + memset(info, 0, sizeof(AlsaPcmInfo)); + // initial values are: stopped, flushed + info->isRunning = 0; + info->isFlushed = 1; + + ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); + if (ret == 0) { + // set to blocking mode + snd_pcm_nonblock(info->handle, 0); + ret = snd_pcm_hw_params_malloc(&(info->hwParams)); + if (ret != 0) { + ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); + } else { + ret = -1; + if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, + isSigned, isBigEndian, encoding)) { + if (setHWParams(info, + sampleRate, + channels, + bufferSizeInBytes / frameSize, + format)) { + info->frameSize = frameSize; + ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); + if (ret < 0) { + ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); + } + snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); + snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); + info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; + TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", + (int) info->periodSize, info->periods, info->bufferSizeInBytes); + } + } + } + if (ret == 0) { + // set software parameters + ret = snd_pcm_sw_params_malloc(&(info->swParams)); + if (ret != 0) { + ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); + } else { + if (!setSWParams(info)) { + ret = -1; + } + } + } + if (ret == 0) { + // prepare device + ret = snd_pcm_prepare(info->handle); + if (ret < 0) { + ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); + } + } + +#ifdef GET_POSITION_METHOD2 + if (ret == 0) { + ret = snd_pcm_status_malloc(&(info->positionStatus)); + if (ret != 0) { + ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); + } + } +#endif + } + if (ret != 0) { + DAUDIO_Close((void*) info, isSource); + info = NULL; + } else { + // set to non-blocking mode + snd_pcm_nonblock(info->handle, 1); + TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", + (void*) info->handle); + } + return (void*) info; +} + +#ifdef USE_TRACE +void printState(snd_pcm_state_t state) { + if (state == SND_PCM_STATE_OPEN) { + TRACE0("State: SND_PCM_STATE_OPEN\n"); + } + else if (state == SND_PCM_STATE_SETUP) { + TRACE0("State: SND_PCM_STATE_SETUP\n"); + } + else if (state == SND_PCM_STATE_PREPARED) { + TRACE0("State: SND_PCM_STATE_PREPARED\n"); + } + else if (state == SND_PCM_STATE_RUNNING) { + TRACE0("State: SND_PCM_STATE_RUNNING\n"); + } + else if (state == SND_PCM_STATE_XRUN) { + TRACE0("State: SND_PCM_STATE_XRUN\n"); + } + else if (state == SND_PCM_STATE_DRAINING) { + TRACE0("State: SND_PCM_STATE_DRAINING\n"); + } + else if (state == SND_PCM_STATE_PAUSED) { + TRACE0("State: SND_PCM_STATE_PAUSED\n"); + } + else if (state == SND_PCM_STATE_SUSPENDED) { + TRACE0("State: SND_PCM_STATE_SUSPENDED\n"); + } +} +#endif + +int DAUDIO_Start(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret; + snd_pcm_state_t state; + + TRACE0("> DAUDIO_Start\n"); + // set to blocking mode + snd_pcm_nonblock(info->handle, 0); + // set start mode so that it always starts as soon as data is there + setStartThreshold(info, TRUE /* use threshold */); + state = snd_pcm_state(info->handle); + if (state == SND_PCM_STATE_PAUSED) { + // in case it was stopped previously + TRACE0(" Un-pausing...\n"); + ret = snd_pcm_pause(info->handle, FALSE); + if (ret != 0) { + ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret)); + } + } + if (state == SND_PCM_STATE_SUSPENDED) { + TRACE0(" Resuming...\n"); + ret = snd_pcm_resume(info->handle); + if (ret < 0) { + if ((ret != -EAGAIN) && (ret != -ENOSYS)) { + ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret)); + } + } + } + if (state == SND_PCM_STATE_SETUP) { + TRACE0("need to call prepare again...\n"); + // prepare device + ret = snd_pcm_prepare(info->handle); + if (ret < 0) { + ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); + } + } + // in case there is still data in the buffers + ret = snd_pcm_start(info->handle); + if (ret != 0) { + if (ret != -EPIPE) { + ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret)); + } + } + // set to non-blocking mode + ret = snd_pcm_nonblock(info->handle, 1); + if (ret != 0) { + ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret)); + } + state = snd_pcm_state(info->handle); +#ifdef USE_TRACE + printState(state); +#endif + ret = (state == SND_PCM_STATE_PREPARED) + || (state == SND_PCM_STATE_RUNNING) + || (state == SND_PCM_STATE_XRUN) + || (state == SND_PCM_STATE_SUSPENDED); + if (ret) { + info->isRunning = 1; + // source line should keep isFlushed value until Write() is called; + // for target data line reset it right now. + if (!isSource) { + info->isFlushed = 0; + } + } + TRACE1("< DAUDIO_Start %s\n", ret?"success":"error"); + return ret?TRUE:FALSE; +} + +int DAUDIO_Stop(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret; + + TRACE0("> DAUDIO_Stop\n"); + // set to blocking mode + snd_pcm_nonblock(info->handle, 0); + setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun + ret = snd_pcm_pause(info->handle, 1); + // set to non-blocking mode + snd_pcm_nonblock(info->handle, 1); + if (ret != 0) { + ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret)); + return FALSE; + } + info->isRunning = 0; + TRACE0("< DAUDIO_Stop success\n"); + return TRUE; +} + +void DAUDIO_Close(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + + TRACE0("DAUDIO_Close\n"); + if (info != NULL) { + if (info->handle != NULL) { + snd_pcm_close(info->handle); + } + if (info->hwParams) { + snd_pcm_hw_params_free(info->hwParams); + } + if (info->swParams) { + snd_pcm_sw_params_free(info->swParams); + } +#ifdef GET_POSITION_METHOD2 + if (info->positionStatus) { + snd_pcm_status_free(info->positionStatus); + } +#endif + free(info); + } +} + +/* + * Underrun and suspend recovery + * returns + * 0: exit native and return 0 + * 1: try again to write/read + * -1: error - exit native with return value -1 + */ +int xrun_recovery(AlsaPcmInfo* info, int err) { + int ret; + + if (err == -EPIPE) { /* underrun / overflow */ + TRACE0("xrun_recovery: underrun/overflow.\n"); + ret = snd_pcm_prepare(info->handle); + if (ret < 0) { + ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); + return -1; + } + return 1; + } else if (err == -ESTRPIPE) { + TRACE0("xrun_recovery: suspended.\n"); + ret = snd_pcm_resume(info->handle); + if (ret < 0) { + if (ret == -EAGAIN) { + return 0; /* wait until the suspend flag is released */ + } + return -1; + } + ret = snd_pcm_prepare(info->handle); + if (ret < 0) { + ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); + return -1; + } + return 1; + } else if (err == -EAGAIN) { + TRACE0("xrun_recovery: EAGAIN try again flag.\n"); + return 0; + } + + TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err)); + return -1; +} + +// returns -1 on error +int DAUDIO_Write(void* id, char* data, int byteSize) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret, count; + snd_pcm_sframes_t frameSize, writtenFrames; + + TRACE1("> DAUDIO_Write %d bytes\n", byteSize); + + /* sanity */ + if (byteSize <= 0 || info->frameSize <= 0) { + ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n", + (int) byteSize, (int) info->frameSize); + TRACE0("< DAUDIO_Write returning -1\n"); + return -1; + } + + count = 2; // maximum number of trials to recover from underrun + //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); + frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); + do { + writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize); + + if (writtenFrames < 0) { + ret = xrun_recovery(info, (int) writtenFrames); + if (ret <= 0) { + TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret); + return ret; + } + if (count-- <= 0) { + ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n"); + return -1; + } + } else { + break; + } + } while (TRUE); + //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames); + + if (writtenFrames > 0) { + // reset "flushed" flag + info->isFlushed = 0; + } + + ret = (int) (writtenFrames * info->frameSize); + TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); + return ret; +} + +// returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret, count; + snd_pcm_sframes_t frameSize, readFrames; + + TRACE1("> DAUDIO_Read %d bytes\n", byteSize); + /*TRACE3(" info=%p, data=%p, byteSize=%d\n", + (void*) info, (void*) data, (int) byteSize); + TRACE2(" info->frameSize=%d, info->handle=%p\n", + (int) info->frameSize, (void*) info->handle); + */ + /* sanity */ + if (byteSize <= 0 || info->frameSize <= 0) { + ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n", + (int) byteSize, (int) info->frameSize); + TRACE0("< DAUDIO_Read returning -1\n"); + return -1; + } + if (!info->isRunning && info->isFlushed) { + // PCM has nothing to read + return 0; + } + + count = 2; // maximum number of trials to recover from error + //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); + frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); + do { + readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize); + if (readFrames < 0) { + ret = xrun_recovery(info, (int) readFrames); + if (ret <= 0) { + TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret); + return ret; + } + if (count-- <= 0) { + ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n"); + return -1; + } + } else { + break; + } + } while (TRUE); + //ret = snd_pcm_frames_to_bytes(info->handle, readFrames); + ret = (int) (readFrames * info->frameSize); + TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); + return ret; +} + + +int DAUDIO_GetBufferSize(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + + return info->bufferSizeInBytes; +} + +int DAUDIO_StillDraining(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + snd_pcm_state_t state; + + state = snd_pcm_state(info->handle); + //printState(state); + //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE"); + return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE; +} + + +int DAUDIO_Flush(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret; + + TRACE0("DAUDIO_Flush\n"); + + if (info->isFlushed) { + // nothing to drop + return 1; + } + + ret = snd_pcm_drop(info->handle); + if (ret != 0) { + ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret)); + return FALSE; + } + + info->isFlushed = 1; + if (info->isRunning) { + ret = DAUDIO_Start(id, isSource); + } + return ret; +} + +int DAUDIO_GetAvailable(void* id, int isSource) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + snd_pcm_sframes_t availableInFrames; + snd_pcm_state_t state; + int ret; + + state = snd_pcm_state(info->handle); + if (info->isFlushed || state == SND_PCM_STATE_XRUN) { + // if in xrun state then we have the entire buffer available, + // not 0 as alsa reports + ret = info->bufferSizeInBytes; + } else { + availableInFrames = snd_pcm_avail_update(info->handle); + if (availableInFrames < 0) { + ret = 0; + } else { + //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames); + ret = (int) (availableInFrames * info->frameSize); + } + } + TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); + return ret; +} + +INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) { + // estimate the current position with the buffer size and + // the available bytes to read or write in the buffer. + // not an elegant solution - bytePos will stop on xruns, + // and in race conditions it may jump backwards + // Advantage is that it is indeed based on the samples that go through + // the system (rather than time-based methods) + if (isSource) { + // javaBytePos is the position that is reached when the current + // buffer is played completely + return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes); + } else { + // javaBytePos is the position that was when the current buffer was empty + return (INT64) (javaBytePos + availInBytes); + } +} + +INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { + AlsaPcmInfo* info = (AlsaPcmInfo*) id; + int ret; + INT64 result = javaBytePos; + snd_pcm_state_t state; + state = snd_pcm_state(info->handle); + + if (!info->isFlushed && state != SND_PCM_STATE_XRUN) { +#ifdef GET_POSITION_METHOD2 + snd_timestamp_t* ts; + snd_pcm_uframes_t framesAvail; + + // note: slight race condition if this is called simultaneously from 2 threads + ret = snd_pcm_status(info->handle, info->positionStatus); + if (ret != 0) { + ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret)); + result = javaBytePos; + } else { + // calculate from time value, or from available bytes + framesAvail = snd_pcm_status_get_avail(info->positionStatus); + result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); + } +#endif +#ifdef GET_POSITION_METHOD3 + snd_pcm_uframes_t framesAvail; + ret = snd_pcm_avail(info->handle, &framesAvail); + if (ret != 0) { + ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret)); + result = javaBytePos; + } else { + result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); + } +#endif +#ifdef GET_POSITION_METHOD1 + result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource)); +#endif + } + //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); + return result; +} + + + +void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { + /* save to ignore, since GetBytePosition + * takes the javaBytePos param into account + */ +} + +int DAUDIO_RequiresServicing(void* id, int isSource) { + // never need servicing on Linux + return FALSE; +} + +void DAUDIO_Service(void* id, int isSource) { + // never need servicing on Linux +} + + +#endif // USE_DAUDIO diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2003, 2014, 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_LinuxOS_ALSA_PCMUtils.h" +#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" + + + +// callback for iteration through devices +// returns TRUE if iteration should continue +// NOTE: cardinfo may be NULL (for "default" device) +typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo, + snd_ctl_card_info_t* cardinfo, void *userData); + +// for each ALSA device, call iterator. userData is passed to the iterator +// returns total number of iterations +int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) { + int count = 0; + int subdeviceCount; + int card, dev, subDev; + char devname[16]; + int err; + snd_ctl_t *handle; + snd_pcm_t *pcm; + snd_pcm_info_t* pcminfo; + snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL; + UINT32 deviceID; + int doContinue = TRUE; + + snd_pcm_info_malloc(&pcminfo); + snd_ctl_card_info_malloc(&cardinfo); + + // 1st try "default" device + err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + if (err < 0) { + // try with the other direction + err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, + SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); + } + if (err < 0) { + ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err)); + } else { + err = snd_pcm_info(pcm, pcminfo); + snd_pcm_close(pcm); + if (err < 0) { + ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n", + snd_strerror(err)); + } else { + // try to get card info + card = snd_pcm_info_get_card(pcminfo); + if (card >= 0) { + sprintf(devname, ALSA_HARDWARE_CARD, card); + if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { + if (snd_ctl_card_info(handle, cardinfo) >= 0) { + defcardinfo = cardinfo; + } + snd_ctl_close(handle); + } + } + // call callback function for the device + if (iterator != NULL) { + doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo, + defcardinfo, userData); + } + count++; + } + } + + // iterate cards + card = -1; + while (doContinue) { + if (snd_card_next(&card) < 0) { + break; + } + if (card < 0) { + break; + } + sprintf(devname, ALSA_HARDWARE_CARD, card); + TRACE1("Opening alsa device \"%s\"...\n", devname); + err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); + if (err < 0) { + ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", + card, snd_strerror(err)); + } else { + err = snd_ctl_card_info(handle, cardinfo); + if (err < 0) { + ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", + card, snd_strerror(err)); + } else { + dev = -1; + while (doContinue) { + if (snd_ctl_pcm_next_device(handle, &dev) < 0) { + ERROR0("snd_ctl_pcm_next_device\n"); + } + if (dev < 0) { + break; + } + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); + err = snd_ctl_pcm_info(handle, pcminfo); + if (err == -ENOENT) { + // try with the other direction + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); + err = snd_ctl_pcm_info(handle, pcminfo); + } + if (err < 0) { + if (err != -ENOENT) { + ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s", + card, snd_strerror(err)); + } + } else { + subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ? + snd_pcm_info_get_subdevices_count(pcminfo) : 1; + if (iterator!=NULL) { + for (subDev = 0; subDev < subdeviceCount; subDev++) { + deviceID = encodeDeviceID(card, dev, subDev); + doContinue = (*iterator)(deviceID, pcminfo, + cardinfo, userData); + count++; + if (!doContinue) { + break; + } + } + } else { + count += subdeviceCount; + } + } + } // of while(doContinue) + } + snd_ctl_close(handle); + } + } + snd_ctl_card_info_free(cardinfo); + snd_pcm_info_free(pcminfo); + return count; +} + +int getAudioDeviceCount() { + initAlsaSupport(); + return iteratePCMDevices(NULL, NULL); +} + +int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo, + snd_ctl_card_info_t* cardinfo, void* userData) { + char buffer[300]; + ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData; +#ifdef ALSA_PCM_USE_PLUGHW + int usePlugHw = 1; +#else + int usePlugHw = 0; +#endif + + initAlsaSupport(); + if (desc->index == 0) { + // we found the device with correct index + *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ? + 1 : snd_pcm_info_get_subdevices_count(pcminfo); + *desc->deviceID = deviceID; + buffer[0]=' '; buffer[1]='['; + // buffer[300] is enough to store the actual device string w/o overrun + getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM); + strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); + strncpy(desc->name, + (cardinfo != NULL) + ? snd_ctl_card_info_get_id(cardinfo) + : snd_pcm_info_get_id(pcminfo), + desc->strLen - strlen(buffer)); + strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); + strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen); + strncpy(desc->description, + (cardinfo != NULL) + ? snd_ctl_card_info_get_name(cardinfo) + : snd_pcm_info_get_name(pcminfo), + desc->strLen); + strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); + strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description)); + strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); + strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description)); + getALSAVersion(desc->version, desc->strLen); + TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version); + return FALSE; // do not continue iteration + } + desc->index--; + return TRUE; +} + +// returns 0 if successful +int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) { + char buffer[200]; + int ret; + + initAlsaSupport(); + getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM); + + TRACE1("Opening ALSA device %s\n", buffer); + ret = snd_pcm_open(handle, buffer, + isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE, + SND_PCM_NONBLOCK); + if (ret != 0) { + ERROR1("snd_pcm_open returned error code %d \n", ret); + *handle = NULL; + } + return ret; +} + + +int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) { + initAlsaSupport(); + TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index); + iteratePCMDevices(&deviceInfoIterator, desc); + return (desc->index == 0)?TRUE:FALSE; +} + +// returns 1 if successful +// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) +int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, + int* sampleSizeInBytes, int* significantBits, + int* isSigned, int* isBigEndian, int* enc) { + + *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8; + *significantBits = snd_pcm_format_width(alsaFormat); + + // defaults + *enc = 0; // PCM + *isSigned = (snd_pcm_format_signed(alsaFormat) > 0); + *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0); + + // non-PCM formats + if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law + *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes; + } + else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law + *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes; + } + else if (snd_pcm_format_linear(alsaFormat) < 1) { + return 0; + } + return (*sampleSizeInBytes > 0); +} + +// returns 1 if successful +int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, + int sampleSizeInBytes, int significantBits, + int isSigned, int isBigEndian, int enc) { + *alsaFormat = SND_PCM_FORMAT_UNKNOWN; + + if (enc == 0) { + *alsaFormat = snd_pcm_build_linear_format(significantBits, + sampleSizeInBytes * 8, + isSigned?0:1, + isBigEndian?1:0); + } + else if ((sampleSizeInBytes == 1) && (significantBits == 8)) { + if (enc == 1) { // ULAW + *alsaFormat = SND_PCM_FORMAT_MU_LAW; + } + else if (enc == 2) { // ALAW + *alsaFormat = SND_PCM_FORMAT_A_LAW; + } + } + return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1; +} + + +/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003, 2010, 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 this with a later version of ALSA than 0.9.0rc3 +// (starting from 1.0.0 it became default behaviour) +#define ALSA_PCM_NEW_HW_PARAMS_API +#include +#include "Utilities.h" + +#ifndef PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED +#define PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED + +// if this is defined, use plughw: devices +#define ALSA_PCM_USE_PLUGHW +//#undef ALSA_PCM_USE_PLUGHW + + +// maximum number of channels that is listed in the formats. If more, than +// just -1 for channel count is used. +#define MAXIMUM_LISTED_CHANNELS 32 + +typedef struct tag_ALSA_AudioDeviceDescription { + int index; // in + int strLen; // in + INT32* deviceID; // out + int* maxSimultaneousLines; // out + char* name; // out + char* vendor; // out + char* description; // out + char* version; // out +} ALSA_AudioDeviceDescription; + + + +int getAudioDeviceCount(); +int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc); + +// returns ALSA error code, or 0 if successful +int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware); + +// returns 1 if successful +// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) +int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, + int* sampleSizeInBytes, int* significantBits, + int* isSigned, int* isBigEndian, int* enc); + +int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, + int sampleSizeInBytes, int significantBits, + int isSigned, int isBigEndian, int enc); + +#endif // PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2003, 2016, 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 "Ports.h" +#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" +#include + +#if USE_PORTS == TRUE + +#define MAX_ELEMS (300) +#define MAX_CONTROLS (MAX_ELEMS * 4) + +#define CHANNELS_MONO (SND_MIXER_SCHN_LAST + 1) +#define CHANNELS_STEREO (SND_MIXER_SCHN_LAST + 2) + +typedef struct { + snd_mixer_elem_t* elem; + INT32 portType; /* one of PORT_XXX_xx */ + char* controlType; /* one of CONTROL_TYPE_xx */ + /* Values: either SND_MIXER_SCHN_FRONT_xx, CHANNELS_MONO or CHANNELS_STEREO. + For SND_MIXER_SCHN_FRONT_xx, exactly this channel is set/retrieved directly. + For CHANNELS_MONO, ALSA channel SND_MIXER_SCHN_MONO is set/retrieved directly. + For CHANNELS_STEREO, ALSA channels SND_MIXER_SCHN_FRONT_LEFT and SND_MIXER_SCHN_FRONT_RIGHT + are set after a calculation that takes balance into account. Retrieved? Average of both + channels? (Using a cached value is not a good idea since the value in the HW may have been + altered.) */ + INT32 channel; +} PortControl; + + +typedef struct tag_PortMixer { + snd_mixer_t* mixer_handle; + /* Number of array elements used in elems and types. */ + int numElems; + snd_mixer_elem_t** elems; + /* Array of port types (PORT_SRC_UNKNOWN etc.). Indices are the same as in elems. */ + INT32* types; + /* Number of array elements used in controls. */ + int numControls; + PortControl* controls; +} PortMixer; + + +///// implemented functions of Ports.h + +INT32 PORT_GetPortMixerCount() { + INT32 mixerCount; + int card; + char devname[16]; + int err; + snd_ctl_t *handle; + snd_ctl_card_info_t* info; + + TRACE0("> PORT_GetPortMixerCount\n"); + + initAlsaSupport(); + + snd_ctl_card_info_malloc(&info); + card = -1; + mixerCount = 0; + if (snd_card_next(&card) >= 0) { + while (card >= 0) { + sprintf(devname, ALSA_HARDWARE_CARD, card); + TRACE1("PORT_GetPortMixerCount: Opening alsa device \"%s\"...\n", devname); + err = snd_ctl_open(&handle, devname, 0); + if (err < 0) { + ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); + } else { + mixerCount++; + snd_ctl_close(handle); + } + if (snd_card_next(&card) < 0) { + break; + } + } + } + snd_ctl_card_info_free(info); + TRACE0("< PORT_GetPortMixerCount\n"); + return mixerCount; +} + + +INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { + snd_ctl_t* handle; + snd_ctl_card_info_t* card_info; + char devname[16]; + int err; + char buffer[100]; + + TRACE0("> PORT_GetPortMixerDescription\n"); + snd_ctl_card_info_malloc(&card_info); + + sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); + TRACE1("Opening alsa device \"%s\"...\n", devname); + err = snd_ctl_open(&handle, devname, 0); + if (err < 0) { + ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); + return FALSE; + } + err = snd_ctl_card_info(handle, card_info); + if (err < 0) { + ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); + } + strncpy(description->name, snd_ctl_card_info_get_id(card_info), PORT_STRING_LENGTH - 1); + sprintf(buffer, " [%s]", devname); + strncat(description->name, buffer, PORT_STRING_LENGTH - 1 - strlen(description->name)); + strncpy(description->vendor, "ALSA (http://www.alsa-project.org)", PORT_STRING_LENGTH - 1); + strncpy(description->description, snd_ctl_card_info_get_name(card_info), PORT_STRING_LENGTH - 1); + strncat(description->description, ", ", PORT_STRING_LENGTH - 1 - strlen(description->description)); + strncat(description->description, snd_ctl_card_info_get_mixername(card_info), PORT_STRING_LENGTH - 1 - strlen(description->description)); + getALSAVersion(description->version, PORT_STRING_LENGTH - 1); + + snd_ctl_close(handle); + snd_ctl_card_info_free(card_info); + TRACE0("< PORT_GetPortMixerDescription\n"); + return TRUE; +} + + +void* PORT_Open(INT32 mixerIndex) { + char devname[16]; + snd_mixer_t* mixer_handle; + int err; + PortMixer* handle; + + TRACE0("> PORT_Open\n"); + sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); + if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) { + ERROR2("Mixer %s open error: %s", devname, snd_strerror(err)); + return NULL; + } + if ((err = snd_mixer_attach(mixer_handle, devname)) < 0) { + ERROR2("Mixer attach %s error: %s", devname, snd_strerror(err)); + snd_mixer_close(mixer_handle); + return NULL; + } + if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0) { + ERROR1("Mixer register error: %s", snd_strerror(err)); + snd_mixer_close(mixer_handle); + return NULL; + } + err = snd_mixer_load(mixer_handle); + if (err < 0) { + ERROR2("Mixer %s load error: %s", devname, snd_strerror(err)); + snd_mixer_close(mixer_handle); + return NULL; + } + handle = (PortMixer*) calloc(1, sizeof(PortMixer)); + if (handle == NULL) { + ERROR0("malloc() failed."); + snd_mixer_close(mixer_handle); + return NULL; + } + handle->numElems = 0; + handle->elems = (snd_mixer_elem_t**) calloc(MAX_ELEMS, sizeof(snd_mixer_elem_t*)); + if (handle->elems == NULL) { + ERROR0("malloc() failed."); + snd_mixer_close(mixer_handle); + free(handle); + return NULL; + } + handle->types = (INT32*) calloc(MAX_ELEMS, sizeof(INT32)); + if (handle->types == NULL) { + ERROR0("malloc() failed."); + snd_mixer_close(mixer_handle); + free(handle->elems); + free(handle); + return NULL; + } + handle->controls = (PortControl*) calloc(MAX_CONTROLS, sizeof(PortControl)); + if (handle->controls == NULL) { + ERROR0("malloc() failed."); + snd_mixer_close(mixer_handle); + free(handle->elems); + free(handle->types); + free(handle); + return NULL; + } + handle->mixer_handle = mixer_handle; + // necessary to initialize data structures + PORT_GetPortCount(handle); + TRACE0("< PORT_Open\n"); + return handle; +} + + +void PORT_Close(void* id) { + TRACE0("> PORT_Close\n"); + if (id != NULL) { + PortMixer* handle = (PortMixer*) id; + if (handle->mixer_handle != NULL) { + snd_mixer_close(handle->mixer_handle); + } + if (handle->elems != NULL) { + free(handle->elems); + } + if (handle->types != NULL) { + free(handle->types); + } + if (handle->controls != NULL) { + free(handle->controls); + } + free(handle); + } + TRACE0("< PORT_Close\n"); +} + + + +INT32 PORT_GetPortCount(void* id) { + PortMixer* portMixer; + snd_mixer_elem_t *elem; + + TRACE0("> PORT_GetPortCount\n"); + if (id == NULL) { + // $$mp: Should become a descriptive error code (invalid handle). + return -1; + } + portMixer = (PortMixer*) id; + if (portMixer->numElems == 0) { + for (elem = snd_mixer_first_elem(portMixer->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { + if (!snd_mixer_selem_is_active(elem)) + continue; + TRACE2("Simple mixer control '%s',%i\n", + snd_mixer_selem_get_name(elem), + snd_mixer_selem_get_index(elem)); + if (snd_mixer_selem_has_playback_volume(elem)) { + portMixer->elems[portMixer->numElems] = elem; + portMixer->types[portMixer->numElems] = PORT_DST_UNKNOWN; + portMixer->numElems++; + } + // to prevent buffer overflow + if (portMixer->numElems >= MAX_ELEMS) { + break; + } + /* If an element has both playback an capture volume, it is put into the arrays + twice. */ + if (snd_mixer_selem_has_capture_volume(elem)) { + portMixer->elems[portMixer->numElems] = elem; + portMixer->types[portMixer->numElems] = PORT_SRC_UNKNOWN; + portMixer->numElems++; + } + // to prevent buffer overflow + if (portMixer->numElems >= MAX_ELEMS) { + break; + } + } + } + TRACE0("< PORT_GetPortCount\n"); + return portMixer->numElems; +} + + +INT32 PORT_GetPortType(void* id, INT32 portIndex) { + PortMixer* portMixer; + INT32 type; + TRACE0("> PORT_GetPortType\n"); + if (id == NULL) { + // $$mp: Should become a descriptive error code (invalid handle). + return -1; + } + portMixer = (PortMixer*) id; + if (portIndex < 0 || portIndex >= portMixer->numElems) { + // $$mp: Should become a descriptive error code (index out of bounds). + return -1; + } + type = portMixer->types[portIndex]; + TRACE0("< PORT_GetPortType\n"); + return type; +} + + +INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { + PortMixer* portMixer; + const char* nam; + + TRACE0("> PORT_GetPortName\n"); + if (id == NULL) { + // $$mp: Should become a descriptive error code (invalid handle). + return -1; + } + portMixer = (PortMixer*) id; + if (portIndex < 0 || portIndex >= portMixer->numElems) { + // $$mp: Should become a descriptive error code (index out of bounds). + return -1; + } + nam = snd_mixer_selem_get_name(portMixer->elems[portIndex]); + strncpy(name, nam, len - 1); + name[len - 1] = 0; + TRACE0("< PORT_GetPortName\n"); + return TRUE; +} + + +static int isPlaybackFunction(INT32 portType) { + return (portType & PORT_DST_MASK); +} + + +/* Sets portControl to a pointer to the next free array element in the PortControl (pointer) + array of the passed portMixer. Returns TRUE if successful. May return FALSE if there is no + free slot. In this case, portControl is not altered */ +static int getControlSlot(PortMixer* portMixer, PortControl** portControl) { + if (portMixer->numControls >= MAX_CONTROLS) { + return FALSE; + } else { + *portControl = &(portMixer->controls[portMixer->numControls]); + portMixer->numControls++; + return TRUE; + } +} + + +/* Protect against illegal min-max values, preventing divisions by zero. + */ +inline static long getRange(long min, long max) { + if (max > min) { + return max - min; + } else { + return 1; + } +} + + +/* Idea: we may specify that if unit is an empty string, the values are linear and if unit is "dB", + the values are logarithmic. +*/ +static void* createVolumeControl(PortControlCreator* creator, + PortControl* portControl, + snd_mixer_elem_t* elem, int isPlayback) { + void* control; + float precision; + long min, max; + + if (isPlayback) { + snd_mixer_selem_get_playback_volume_range(elem, &min, &max); + } else { + snd_mixer_selem_get_capture_volume_range(elem, &min, &max); + } + /* $$mp: The volume values retrieved with the ALSA API are strongly supposed to be logarithmic. + So the following calculation is wrong. However, there is no correct calculation, since + for equal-distant logarithmic steps, the precision expressed in linear varies over the + scale. */ + precision = 1.0F / getRange(min, max); + control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_VOLUME, 0.0F, +1.0F, precision, ""); + return control; +} + + +void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { + PortMixer* portMixer; + snd_mixer_elem_t* elem; + void* control; + PortControl* portControl; + void* controls[10]; + int numControls; + char* portName; + int isPlayback = 0; + int isMono; + int isStereo; + char* type; + snd_mixer_selem_channel_id_t channel; + memset(controls, 0, sizeof(controls)); + + TRACE0("> PORT_GetControls\n"); + if (id == NULL) { + ERROR0("Invalid handle!"); + // $$mp: an error code should be returned. + return; + } + portMixer = (PortMixer*) id; + if (portIndex < 0 || portIndex >= portMixer->numElems) { + ERROR0("Port index out of range!"); + // $$mp: an error code should be returned. + return; + } + numControls = 0; + elem = portMixer->elems[portIndex]; + if (snd_mixer_selem_has_playback_volume(elem) || snd_mixer_selem_has_capture_volume(elem)) { + /* Since we've split/duplicated elements with both playback and capture on the recovery + of elements, we now can assume that we handle only to deal with either playback or + capture. */ + isPlayback = isPlaybackFunction(portMixer->types[portIndex]); + isMono = (isPlayback && snd_mixer_selem_is_playback_mono(elem)) || + (!isPlayback && snd_mixer_selem_is_capture_mono(elem)); + isStereo = (isPlayback && + snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && + snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)) || + (!isPlayback && + snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && + snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)); + // single volume control + if (isMono || isStereo) { + if (getControlSlot(portMixer, &portControl)) { + portControl->elem = elem; + portControl->portType = portMixer->types[portIndex]; + portControl->controlType = CONTROL_TYPE_VOLUME; + if (isMono) { + portControl->channel = CHANNELS_MONO; + } else { + portControl->channel = CHANNELS_STEREO; + } + control = createVolumeControl(creator, portControl, elem, isPlayback); + if (control != NULL) { + controls[numControls++] = control; + } + } + } else { // more than two channels, each channels has its own control. + for (channel = SND_MIXER_SCHN_FRONT_LEFT; channel <= SND_MIXER_SCHN_LAST; channel++) { + if ((isPlayback && snd_mixer_selem_has_playback_channel(elem, channel)) || + (!isPlayback && snd_mixer_selem_has_capture_channel(elem, channel))) { + if (getControlSlot(portMixer, &portControl)) { + portControl->elem = elem; + portControl->portType = portMixer->types[portIndex]; + portControl->controlType = CONTROL_TYPE_VOLUME; + portControl->channel = channel; + control = createVolumeControl(creator, portControl, elem, isPlayback); + // We wrap in a compound control to provide the channel name. + if (control != NULL) { + /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the + declaration of PORT_NewCompoundControlPtr in Ports.h should be changed + to take a const char* parameter. */ + control = (creator->newCompoundControl)(creator, (char*) snd_mixer_selem_channel_name(channel), &control, 1); + } + if (control != NULL) { + controls[numControls++] = control; + } + } + } + } + } + // BALANCE control + if (isStereo) { + if (getControlSlot(portMixer, &portControl)) { + portControl->elem = elem; + portControl->portType = portMixer->types[portIndex]; + portControl->controlType = CONTROL_TYPE_BALANCE; + portControl->channel = CHANNELS_STEREO; + /* $$mp: The value for precision is chosen more or less arbitrarily. */ + control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_BALANCE, -1.0F, 1.0F, 0.01F, ""); + if (control != NULL) { + controls[numControls++] = control; + } + } + } + } + if (snd_mixer_selem_has_playback_switch(elem) || snd_mixer_selem_has_capture_switch(elem)) { + if (getControlSlot(portMixer, &portControl)) { + type = isPlayback ? CONTROL_TYPE_MUTE : CONTROL_TYPE_SELECT; + portControl->elem = elem; + portControl->portType = portMixer->types[portIndex]; + portControl->controlType = type; + control = (creator->newBooleanControl)(creator, portControl, type); + if (control != NULL) { + controls[numControls++] = control; + } + } + } + /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the + declaration of PORT_NewCompoundControlPtr in Ports.h should be changed + to take a const char* parameter. */ + portName = (char*) snd_mixer_selem_get_name(elem); + control = (creator->newCompoundControl)(creator, portName, controls, numControls); + if (control != NULL) { + (creator->addControl)(creator, control); + } + TRACE0("< PORT_GetControls\n"); +} + + +INT32 PORT_GetIntValue(void* controlIDV) { + PortControl* portControl = (PortControl*) controlIDV; + int value = 0; + snd_mixer_selem_channel_id_t channel; + + if (portControl != NULL) { + switch (portControl->channel) { + case CHANNELS_MONO: + channel = SND_MIXER_SCHN_MONO; + break; + + case CHANNELS_STEREO: + channel = SND_MIXER_SCHN_FRONT_LEFT; + break; + + default: + channel = portControl->channel; + } + if (portControl->controlType == CONTROL_TYPE_MUTE || + portControl->controlType == CONTROL_TYPE_SELECT) { + if (isPlaybackFunction(portControl->portType)) { + snd_mixer_selem_get_playback_switch(portControl->elem, channel, &value); + } else { + snd_mixer_selem_get_capture_switch(portControl->elem, channel, &value); + } + if (portControl->controlType == CONTROL_TYPE_MUTE) { + value = ! value; + } + } else { + ERROR1("PORT_GetIntValue(): inappropriate control type: %s\n", + portControl->controlType); + } + } + return (INT32) value; +} + + +void PORT_SetIntValue(void* controlIDV, INT32 value) { + PortControl* portControl = (PortControl*) controlIDV; + snd_mixer_selem_channel_id_t channel; + + if (portControl != NULL) { + if (portControl->controlType == CONTROL_TYPE_MUTE) { + value = ! value; + } + if (portControl->controlType == CONTROL_TYPE_MUTE || + portControl->controlType == CONTROL_TYPE_SELECT) { + if (isPlaybackFunction(portControl->portType)) { + snd_mixer_selem_set_playback_switch_all(portControl->elem, value); + } else { + snd_mixer_selem_set_capture_switch_all(portControl->elem, value); + } + } else { + ERROR1("PORT_SetIntValue(): inappropriate control type: %s\n", + portControl->controlType); + } + } +} + + +static float scaleVolumeValueToNormalized(long value, long min, long max) { + return (float) (value - min) / getRange(min, max); +} + + +static long scaleVolumeValueToHardware(float value, long min, long max) { + return (long)(value * getRange(min, max) + min); +} + + +float getRealVolume(PortControl* portControl, + snd_mixer_selem_channel_id_t channel) { + float fValue; + long lValue = 0; + long min = 0; + long max = 0; + + if (isPlaybackFunction(portControl->portType)) { + snd_mixer_selem_get_playback_volume_range(portControl->elem, + &min, &max); + snd_mixer_selem_get_playback_volume(portControl->elem, + channel, &lValue); + } else { + snd_mixer_selem_get_capture_volume_range(portControl->elem, + &min, &max); + snd_mixer_selem_get_capture_volume(portControl->elem, + channel, &lValue); + } + fValue = scaleVolumeValueToNormalized(lValue, min, max); + return fValue; +} + + +void setRealVolume(PortControl* portControl, + snd_mixer_selem_channel_id_t channel, float value) { + long lValue = 0; + long min = 0; + long max = 0; + + if (isPlaybackFunction(portControl->portType)) { + snd_mixer_selem_get_playback_volume_range(portControl->elem, + &min, &max); + lValue = scaleVolumeValueToHardware(value, min, max); + snd_mixer_selem_set_playback_volume(portControl->elem, + channel, lValue); + } else { + snd_mixer_selem_get_capture_volume_range(portControl->elem, + &min, &max); + lValue = scaleVolumeValueToHardware(value, min, max); + snd_mixer_selem_set_capture_volume(portControl->elem, + channel, lValue); + } +} + + +static float getFakeBalance(PortControl* portControl) { + float volL, volR; + + // pan is the ratio of left and right + volL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); + volR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); + if (volL > volR) { + return -1.0f + (volR / volL); + } + else if (volR > volL) { + return 1.0f - (volL / volR); + } + return 0.0f; +} + + +static float getFakeVolume(PortControl* portControl) { + float valueL; + float valueR; + float value; + + valueL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); + valueR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); + // volume is the greater value of both + value = valueL > valueR ? valueL : valueR ; + return value; +} + + +/* + * sets the unsigned values for left and right volume according to + * the given volume (0...1) and balance (-1..0..+1) + */ +static void setFakeVolume(PortControl* portControl, float vol, float bal) { + float volumeLeft; + float volumeRight; + + if (bal < 0.0f) { + volumeLeft = vol; + volumeRight = vol * (bal + 1.0f); + } else { + volumeLeft = vol * (1.0f - bal); + volumeRight = vol; + } + setRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT, volumeLeft); + setRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT, volumeRight); +} + + +float PORT_GetFloatValue(void* controlIDV) { + PortControl* portControl = (PortControl*) controlIDV; + float value = 0.0F; + + if (portControl != NULL) { + if (portControl->controlType == CONTROL_TYPE_VOLUME) { + switch (portControl->channel) { + case CHANNELS_MONO: + value = getRealVolume(portControl, SND_MIXER_SCHN_MONO); + break; + + case CHANNELS_STEREO: + value = getFakeVolume(portControl); + break; + + default: + value = getRealVolume(portControl, portControl->channel); + } + } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { + if (portControl->channel == CHANNELS_STEREO) { + value = getFakeBalance(portControl); + } else { + ERROR0("PORT_GetFloatValue(): Balance only allowed for stereo channels!\n"); + } + } else { + ERROR1("PORT_GetFloatValue(): inappropriate control type: %s!\n", + portControl->controlType); + } + } + return value; +} + + +void PORT_SetFloatValue(void* controlIDV, float value) { + PortControl* portControl = (PortControl*) controlIDV; + + if (portControl != NULL) { + if (portControl->controlType == CONTROL_TYPE_VOLUME) { + switch (portControl->channel) { + case CHANNELS_MONO: + setRealVolume(portControl, SND_MIXER_SCHN_MONO, value); + break; + + case CHANNELS_STEREO: + setFakeVolume(portControl, value, getFakeBalance(portControl)); + break; + + default: + setRealVolume(portControl, portControl->channel, value); + } + } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { + if (portControl->channel == CHANNELS_STEREO) { + setFakeVolume(portControl, getFakeVolume(portControl), value); + } else { + ERROR0("PORT_SetFloatValue(): Balance only allowed for stereo channels!\n"); + } + } else { + ERROR1("PORT_SetFloatValue(): inappropriate control type: %s!\n", + portControl->controlType); + } + } +} + + +#endif // USE_PORTS diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/share/classes/com/sun/media/sound/Platform.java --- a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java Fri Mar 23 09:26:59 2018 +0100 +++ b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java Fri Mar 23 09:51:02 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, 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 @@ -38,23 +38,9 @@ final class Platform { // native library we need to load - private static final String libNameMain = "jsound"; - private static final String libNameALSA = "jsoundalsa"; - private static final String libNameDSound = "jsoundds"; - - // extra libs handling: bit flags for each different library - public static final int LIB_MAIN = 1; - public static final int LIB_ALSA = 2; - public static final int LIB_DSOUND = 4; + private static final String libName = "jsound"; - // bit field of the constants above. Willbe set in loadLibraries - private static int loadedLibs = 0; - - // features: the main native library jsound reports which feature is - // contained in which lib - public static final int FEATURE_MIDIIO = 1; - public static final int FEATURE_PORTS = 2; - public static final int FEATURE_DIRECT_AUDIO = 3; + private static boolean isNativeLibLoaded; // SYSTEM CHARACTERISTICS // vary according to hardware architecture @@ -66,7 +52,6 @@ if(Printer.trace)Printer.trace(">> Platform.java: static"); loadLibraries(); - readProperties(); } /** @@ -95,72 +80,37 @@ private static void loadLibraries() { if(Printer.trace)Printer.trace(">>Platform.loadLibraries"); - // load the main library - AccessController.doPrivileged((PrivilegedAction) () -> { - System.loadLibrary(libNameMain); - return null; - }); - // just for the heck of it... - loadedLibs |= LIB_MAIN; - - // now try to load extra libs. They are defined at compile time in the Makefile - // with the define EXTRA_SOUND_JNI_LIBS - String extraLibs = nGetExtraLibraries(); - // the string is the libraries, separated by white space - StringTokenizer st = new StringTokenizer(extraLibs); - while (st.hasMoreTokens()) { - final String lib = st.nextToken(); - try { - AccessController.doPrivileged((PrivilegedAction) () -> { - System.loadLibrary(lib); - return null; - }); - - if (lib.equals(libNameALSA)) { - loadedLibs |= LIB_ALSA; - if (Printer.debug) Printer.debug("Loaded ALSA lib successfully."); - } else if (lib.equals(libNameDSound)) { - loadedLibs |= LIB_DSOUND; - if (Printer.debug) Printer.debug("Loaded DirectSound lib successfully."); - } else { - if (Printer.err) Printer.err("Loaded unknown lib '"+lib+"' successfully."); - } - } catch (Throwable t) { - if (Printer.err) Printer.err("Couldn't load library "+lib+": "+t.toString()); - } + // load the native library + isNativeLibLoaded = true; + try { + AccessController.doPrivileged((PrivilegedAction) () -> { + System.loadLibrary(libName); + return null; + }); + } catch (Throwable t) { + if (Printer.err) Printer.err("Couldn't load library "+libName+": "+t.toString()); + isNativeLibLoaded = false; + } + if (isNativeLibLoaded) { + bigEndian = nIsBigEndian(); } } static boolean isMidiIOEnabled() { - return isFeatureLibLoaded(FEATURE_MIDIIO); + if (Printer.debug) Printer.debug("Platform: Checking for MidiIO; library is loaded=" + isNativeLibLoaded); + return isNativeLibLoaded; } static boolean isPortsEnabled() { - return isFeatureLibLoaded(FEATURE_PORTS); + if (Printer.debug) Printer.debug("Platform: Checking for Ports; library is loaded=" + isNativeLibLoaded); + return isNativeLibLoaded; } static boolean isDirectAudioEnabled() { - return isFeatureLibLoaded(FEATURE_DIRECT_AUDIO); - } - - private static boolean isFeatureLibLoaded(int feature) { - if (Printer.debug) Printer.debug("Platform: Checking for feature "+feature+"..."); - int requiredLib = nGetLibraryForFeature(feature); - boolean isLoaded = (requiredLib != 0) && ((loadedLibs & requiredLib) == requiredLib); - if (Printer.debug) Printer.debug(" ...needs library "+requiredLib+". Result is loaded="+isLoaded); - return isLoaded; + if (Printer.debug) Printer.debug("Platform: Checking for DirectAudio; library is loaded=" + isNativeLibLoaded); + return isNativeLibLoaded; } - // the following native methods are implemented in Platform.c + // the following native method is implemented in Platform.c private static native boolean nIsBigEndian(); - private static native String nGetExtraLibraries(); - private static native int nGetLibraryForFeature(int feature); - - /** - * Read the required system properties. - */ - private static void readProperties() { - // $$fb 2002-03-06: implement check for endianness in native. Facilitates porting ! - bigEndian = nIsBigEndian(); - } } diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/share/native/libjsound/Platform.c --- a/src/java.desktop/share/native/libjsound/Platform.c Fri Mar 23 09:26:59 2018 +0100 +++ b/src/java.desktop/share/native/libjsound/Platform.c Fri Mar 23 09:51:02 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, 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 @@ -41,83 +41,3 @@ JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_Platform_nIsBigEndian(JNIEnv *env, jclass clss) { return UTIL_IsBigEndianPlatform(); } - -/* - * Class: com_sun_media_sound_Platform - * Method: nGetExtraLibraries - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_sun_media_sound_Platform_nGetExtraLibraries(JNIEnv *env, jclass clss) { - return (*env)->NewStringUTF(env, EXTRA_SOUND_JNI_LIBS); -} - -/* - * Class: com_sun_media_sound_Platform - * Method: nGetLibraryForFeature - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_com_sun_media_sound_Platform_nGetLibraryForFeature - (JNIEnv *env, jclass clazz, jint feature) { - -// for every OS -#if X_PLATFORM == X_WINDOWS - switch (feature) { - case com_sun_media_sound_Platform_FEATURE_MIDIIO: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - return com_sun_media_sound_Platform_LIB_DSOUND; - } -#endif -#if (X_PLATFORM == X_SOLARIS) - switch (feature) { - case com_sun_media_sound_Platform_FEATURE_MIDIIO: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - return com_sun_media_sound_Platform_LIB_MAIN; - } -#endif -#if (X_PLATFORM == X_LINUX) - switch (feature) { - case com_sun_media_sound_Platform_FEATURE_MIDIIO: - return com_sun_media_sound_Platform_LIB_ALSA; - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_ALSA; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - return com_sun_media_sound_Platform_LIB_ALSA; - } -#endif -#if (X_PLATFORM == X_MACOSX) - switch (feature) { - case com_sun_media_sound_Platform_FEATURE_MIDIIO: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - return com_sun_media_sound_Platform_LIB_MAIN; - } -#endif -#if (X_PLATFORM == X_BSD) - switch (feature) { - case com_sun_media_sound_Platform_FEATURE_MIDIIO: - return com_sun_media_sound_Platform_LIB_MAIN; -#ifdef __FreeBSD__ - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_ALSA; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - return com_sun_media_sound_Platform_LIB_ALSA; -#else - case com_sun_media_sound_Platform_FEATURE_PORTS: - return com_sun_media_sound_Platform_LIB_MAIN; - case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO: - // XXXBSD: When native Direct Audio support is ported change - // this back to returning com_sun_media_sound_Platform_LIB_MAIN - return 0; -#endif - } -#endif - return 0; -} diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c Fri Mar 23 09:51:02 2018 +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 diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2002, 2016, 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 "Ports.h" +#include "PLATFORM_API_SolarisOS_Utils.h" + +#if USE_PORTS == TRUE + +#define MONITOR_GAIN_STRING "Monitor Gain" + +#define ALL_TARGET_PORT_COUNT 6 + +// define the following to not use audio_prinfo_t.mod_ports +#define SOLARIS7_COMPATIBLE + +// Solaris audio defines +static int targetPorts[ALL_TARGET_PORT_COUNT] = { + AUDIO_SPEAKER, + AUDIO_HEADPHONE, + AUDIO_LINE_OUT, + AUDIO_AUX1_OUT, + AUDIO_AUX2_OUT, + AUDIO_SPDIF_OUT +}; + +static char* targetPortNames[ALL_TARGET_PORT_COUNT] = { + "Speaker", + "Headphone", + "Line Out", + "AUX1 Out", + "AUX2 Out", + "SPDIF Out" +}; + +// defined in Ports.h +static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = { + PORT_DST_SPEAKER, + PORT_DST_HEADPHONE, + PORT_DST_LINE_OUT, + PORT_DST_UNKNOWN, + PORT_DST_UNKNOWN, + PORT_DST_UNKNOWN, +}; + +#define ALL_SOURCE_PORT_COUNT 7 + +// Solaris audio defines +static int sourcePorts[ALL_SOURCE_PORT_COUNT] = { + AUDIO_MICROPHONE, + AUDIO_LINE_IN, + AUDIO_CD, + AUDIO_AUX1_IN, + AUDIO_AUX2_IN, + AUDIO_SPDIF_IN, + AUDIO_CODEC_LOOPB_IN +}; + +static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = { + "Microphone In", + "Line In", + "Compact Disc In", + "AUX1 In", + "AUX2 In", + "SPDIF In", + "Internal Loopback" +}; + +// Ports.h defines +static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = { + PORT_SRC_MICROPHONE, + PORT_SRC_LINE_IN, + PORT_SRC_COMPACT_DISC, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN +}; + +struct tag_PortControlID; + +typedef struct tag_PortInfo { + int fd; // file descriptor of the pseudo device + audio_info_t audioInfo; + // ports + int targetPortCount; + int sourcePortCount; + // indexes to sourcePorts/targetPorts + // contains first target ports, then source ports + int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT]; + // controls + int maxControlCount; // upper bound of number of controls + int usedControlIDs; // number of items already filled in controlIDs + struct tag_PortControlID* controlIDs; // the control IDs themselves +} PortInfo; + +#define PORT_CONTROL_TYPE_PLAY 0x4000000 +#define PORT_CONTROL_TYPE_RECORD 0x8000000 +#define PORT_CONTROL_TYPE_SELECT_PORT 1 +#define PORT_CONTROL_TYPE_GAIN 2 +#define PORT_CONTROL_TYPE_BALANCE 3 +#define PORT_CONTROL_TYPE_MONITOR_GAIN 10 +#define PORT_CONTROL_TYPE_OUTPUT_MUTED 11 +#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD +#define PORT_CONTROL_TYPE_MASK 0xFFFFFF + + +typedef struct tag_PortControlID { + PortInfo* portInfo; + INT32 controlType; // PORT_CONTROL_TYPE_XX + uint_t port; +} PortControlID; + + +///// implemented functions of Ports.h + +INT32 PORT_GetPortMixerCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { + AudioDeviceDescription desc; + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { + strncpy(description->name, desc.name, PORT_STRING_LENGTH-1); + description->name[PORT_STRING_LENGTH-1] = 0; + strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1); + description->vendor[PORT_STRING_LENGTH-1] = 0; + strncpy(description->version, desc.version, PORT_STRING_LENGTH-1); + description->version[PORT_STRING_LENGTH-1] = 0; + /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/ + strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1); + description->description[PORT_STRING_LENGTH-1] = 0; + return TRUE; + } + return FALSE; +} + + +void* PORT_Open(INT32 mixerIndex) { + PortInfo* info = NULL; + int fd = -1; + AudioDeviceDescription desc; + int success = FALSE; + + TRACE0("PORT_Open\n"); + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + fd = open(desc.pathctl, O_RDWR); + } + if (fd < 0) { + ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); + return NULL; + } + + info = (PortInfo*) malloc(sizeof(PortInfo)); + if (info != NULL) { + memset(info, 0, sizeof(PortInfo)); + info->fd = fd; + success = TRUE; + } + if (!success) { + if (fd >= 0) { + close(fd); + } + PORT_Close((void*) info); + info = NULL; + } + return info; +} + +void PORT_Close(void* id) { + TRACE0("PORT_Close\n"); + if (id != NULL) { + PortInfo* info = (PortInfo*) id; + if (info->fd >= 0) { + close(info->fd); + info->fd = -1; + } + if (info->controlIDs) { + free(info->controlIDs); + info->controlIDs = NULL; + } + free(info); + } +} + + + +INT32 PORT_GetPortCount(void* id) { + int ret = 0; + PortInfo* info = (PortInfo*) id; + if (info != NULL) { + if (!info->targetPortCount && !info->sourcePortCount) { + int i; + AUDIO_INITINFO(&info->audioInfo); + if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) { + for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) { + if (info->audioInfo.play.avail_ports & targetPorts[i]) { + info->ports[info->targetPortCount] = i; + info->targetPortCount++; + } +#ifdef SOLARIS7_COMPATIBLE + TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i], + info->audioInfo.play.avail_ports & targetPorts[i]); +#else + TRACE4("Target %d %s: avail=%d mod=%d\n", i, targetPortNames[i], + info->audioInfo.play.avail_ports & targetPorts[i], + info->audioInfo.play.mod_ports & targetPorts[i]); +#endif + } + for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) { + if (info->audioInfo.record.avail_ports & sourcePorts[i]) { + info->ports[info->targetPortCount + info->sourcePortCount] = i; + info->sourcePortCount++; + } +#ifdef SOLARIS7_COMPATIBLE + TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i], + info->audioInfo.record.avail_ports & sourcePorts[i]); +#else + TRACE4("Source %d %s: avail=%d mod=%d\n", i, sourcePortNames[i], + info->audioInfo.record.avail_ports & sourcePorts[i], + info->audioInfo.record.mod_ports & sourcePorts[i]); +#endif + } + } + } + ret = info->targetPortCount + info->sourcePortCount; + } + return ret; +} + +int isSourcePort(PortInfo* info, INT32 portIndex) { + return (portIndex >= info->targetPortCount); +} + +INT32 PORT_GetPortType(void* id, INT32 portIndex) { + PortInfo* info = (PortInfo*) id; + if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { + if (isSourcePort(info, portIndex)) { + return sourcePortJavaSoundMapping[info->ports[portIndex]]; + } else { + return targetPortJavaSoundMapping[info->ports[portIndex]]; + } + } + return 0; +} + +// pre-condition: portIndex must have been verified! +char* getPortName(PortInfo* info, INT32 portIndex) { + char* ret = NULL; + + if (isSourcePort(info, portIndex)) { + ret = sourcePortNames[info->ports[portIndex]]; + } else { + ret = targetPortNames[info->ports[portIndex]]; + } + return ret; +} + +INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { + PortInfo* info = (PortInfo*) id; + char* n; + + if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { + n = getPortName(info, portIndex); + if (n) { + strncpy(name, n, len-1); + name[len-1] = 0; + return TRUE; + } + } + return FALSE; +} + +void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex, + INT32 type, void** controlObjects, int* controlCount) { + PortControlID* controlID; + void* newControl = NULL; + int controlIndex; + char* jsType = NULL; + int isBoolean = FALSE; + + TRACE0(">createPortControl\n"); + + // fill the ControlID structure and add this control + if (info->usedControlIDs >= info->maxControlCount) { + ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount); + return; + } + controlID = &(info->controlIDs[info->usedControlIDs]); + controlID->portInfo = info; + controlID->controlType = type; + controlIndex = info->ports[portIndex]; + if (isSourcePort(info, portIndex)) { + controlID->port = sourcePorts[controlIndex]; + } else { + controlID->port = targetPorts[controlIndex]; + } + switch (type & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break; + case PORT_CONTROL_TYPE_GAIN: + jsType = CONTROL_TYPE_VOLUME; break; + case PORT_CONTROL_TYPE_BALANCE: + jsType = CONTROL_TYPE_BALANCE; break; + case PORT_CONTROL_TYPE_MONITOR_GAIN: + jsType = CONTROL_TYPE_VOLUME; break; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break; + } + if (isBoolean) { + TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n"); + newControl = (creator->newBooleanControl)(creator, controlID, jsType); + } + else if (jsType == CONTROL_TYPE_BALANCE) { + TRACE0(" PORT_CONTROL_TYPE_BALANCE\n"); + newControl = (creator->newFloatControl)(creator, controlID, jsType, + -1.0f, 1.0f, 2.0f / 65.0f, ""); + } else { + TRACE0(" PORT_CONTROL_TYPE_FLOAT\n"); + newControl = (creator->newFloatControl)(creator, controlID, jsType, + 0.0f, 1.0f, 1.0f / 256.0f, ""); + } + if (newControl) { + controlObjects[*controlCount] = newControl; + (*controlCount)++; + info->usedControlIDs++; + } + TRACE0("addCompoundControl %d controls\n", *controlCount); + if (*controlCount) { + // create compound control and add it to the vector + compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount); + if (compControl) { + TRACE1(" addCompoundControl: calling addControl %p\n", compControl); + (creator->addControl)(creator, compControl); + } + *controlCount = 0; + } + TRACE0("addAllControl\n"); + // go through all controls and add them to the vector + for (i = 0; i < *controlCount; i++) { + (creator->addControl)(creator, controlObjects[i]); + } + *controlCount = 0; + TRACE0("PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", + id, portIndex, info->controlIDs, info->maxControlCount); + if ((portIndex >= 0) && (portIndex < portCount)) { + // if the memory isn't reserved for the control structures, allocate it + if (!info->controlIDs) { + int maxCount = 0; + TRACE0("getControl: allocate mem\n"); + // get a maximum number of controls: + // each port has a select, balance, and volume control. + maxCount = 3 * portCount; + // then there is monitorGain and outputMuted + maxCount += (2 * info->targetPortCount); + info->maxControlCount = maxCount; + info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount); + } + if (!isSourcePort(info, portIndex)) { + type = PORT_CONTROL_TYPE_PLAY; + // add master mute control + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_OUTPUT_MUTED, + controls, &controlCount); + addAllControls(info, creator, controls, &controlCount); +#ifdef SOLARIS7_COMPATIBLE + selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]]; +#else + selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]]; +#endif + } else { + type = PORT_CONTROL_TYPE_RECORD; +#ifdef SOLARIS7_COMPATIBLE + selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]]; +#else + selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]]; +#endif + } + // add a mixer strip with volume, ... + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_GAIN, + controls, &controlCount); + // ... balance, ... + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_BALANCE, + controls, &controlCount); + // ... and select control (if not always on)... + if (selectable) { + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_SELECT_PORT, + controls, &controlCount); + } + // ... packaged in a compound control. + addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount); + + if (type == PORT_CONTROL_TYPE_PLAY) { + // add a single strip for source ports with monitor gain + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_MONITOR_GAIN, + controls, &controlCount); + // also in a compound control + addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount); + } + } + TRACE0("< PORT_getControls\n"); +} + +INT32 PORT_GetIntValue(void* controlIDV) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + return (prinfo->port & controlID->port)?TRUE:FALSE; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + return (audioInfo.output_muted)?TRUE:FALSE; + default: + ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } + ERROR0("PORT_GetIntValue: Could not ioctl!\n"); + return 0; +} + +void PORT_SetIntValue(void* controlIDV, INT32 value) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int setPort; + + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + // first try to just add this port. if that fails, set ONLY to this port. + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (value) { + setPort = (prinfo->port | controlID->port); + } else { + setPort = (prinfo->port - controlID->port); + } + AUDIO_INITINFO(&audioInfo); + prinfo->port = setPort; + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + // didn't work. Either this line doesn't support to select several + // ports at once (e.g. record), or a real error + if (value) { + // set to ONLY this port (and disable any other currently selected ports) + AUDIO_INITINFO(&audioInfo); + prinfo->port = controlID->port; + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port); + } + } else { + // assume it's an error + ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort); + } + } + break; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + AUDIO_INITINFO(&audioInfo); + audioInfo.output_muted = (value?TRUE:FALSE); + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value); + } + break; + default: + ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } +} + +float PORT_GetFloatValue(void* controlIDV) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_GAIN: + return ((float) (prinfo->gain - AUDIO_MIN_GAIN)) + / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); + case PORT_CONTROL_TYPE_BALANCE: + return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1)) + / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE)); + case PORT_CONTROL_TYPE_MONITOR_GAIN: + return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN)) + / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); + default: + ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } + ERROR0("PORT_GetFloatValue: Could not ioctl!\n"); + return 0.0f; +} + +void PORT_SetFloatValue(void* controlIDV, float value) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_GAIN: + prinfo->gain = AUDIO_MIN_GAIN + + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); + break; + case PORT_CONTROL_TYPE_BALANCE: + prinfo->balance = AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE + + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f); + break; + case PORT_CONTROL_TYPE_MONITOR_GAIN: + audioInfo.monitor_gain = AUDIO_MIN_GAIN + + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); + break; + default: + ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + return; + } + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR0("PORT_SetFloatValue: Could not ioctl!\n"); + } +} + +#endif // USE_PORTS diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,193 @@ +/* + * 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 - 1] = 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; +} diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h Fri Mar 23 09:51:02 2018 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002, 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. + */ + +#include +#include +#include +#include +/* does not work on Solaris 2.7 */ +#include +#include +#include +#ifndef __linux__ +#include +#endif +#include +#include +#include + +#ifndef PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED +#define PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED + +/* defines for Solaris 2.7 + #ifndef AUDIO_AUX1_OUT + #define AUDIO_AUX1_OUT (0x08) // output to aux1 out + #define AUDIO_AUX2_OUT (0x10) // output to aux2 out + #define AUDIO_SPDIF_OUT (0x20) // output to SPDIF port + #define AUDIO_AUX1_IN (0x08) // input from aux1 in + #define AUDIO_AUX2_IN (0x10) // input from aux2 in + #define AUDIO_SPDIF_IN (0x20) // input from SPDIF port + #endif +*/ + +/* input from Codec inter. loopback */ +#ifndef AUDIO_CODEC_LOOPB_IN +#define AUDIO_CODEC_LOOPB_IN (0x40) +#endif + + +#define MAX_NAME_LENGTH 300 + +typedef struct tag_AudioDevicePath { + char path[MAX_NAME_LENGTH]; + ino_t st_ino; // inode number to detect duplicate devices + dev_t st_dev; // device ID to detect duplicate audio devices +} AudioDevicePath; + +typedef struct tag_AudioDeviceDescription { + INT32 maxSimulLines; + char path[MAX_NAME_LENGTH+1]; + char pathctl[MAX_NAME_LENGTH+4]; + char name[MAX_NAME_LENGTH+1]; + char vendor[MAX_NAME_LENGTH+1]; + char version[MAX_NAME_LENGTH+1]; + char description[MAX_NAME_LENGTH+1]; +} AudioDeviceDescription; + +int getAudioDeviceCount(); + +/* + * adPath is an array of AudioDevicePath structures + * count contains initially the number of elements in adPath + * and will be set to the returned number of paths. + */ +void getAudioDevices(AudioDevicePath* adPath, int* count); + +/* + * fills adDesc from the audio device given in path + * returns 0 if an error occurred + * if getNames is 0, only path and pathctl are filled + */ +int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames); +int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames); + + +#endif // PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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_BsdOS_ALSA_CommonUtils.h" - -static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) { -#ifdef USE_ERROR - va_list args; - va_start(args, fmt); - printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err)); - if (strlen(fmt) > 0) { - vprintf(fmt, args); - } - va_end(args); -#endif -} - -static int alsa_inited = 0; -static int alsa_enumerate_pcm_subdevices = FALSE; // default: no -static int alsa_enumerate_midi_subdevices = FALSE; // default: no - -void initAlsaSupport() { - char* enumerate; - if (!alsa_inited) { - alsa_inited = TRUE; - snd_lib_error_set_handler(&alsaDebugOutput); - - enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES); - if (enumerate != NULL && strlen(enumerate) > 0 - && (enumerate[0] != 'f') // false - && (enumerate[0] != 'F') // False - && (enumerate[0] != 'n') // no - && (enumerate[0] != 'N')) { // NO - alsa_enumerate_pcm_subdevices = TRUE; - } -#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES - alsa_enumerate_midi_subdevices = TRUE; -#endif - } -} - - -/* if true (non-zero), ALSA sub devices should be listed as separate devices - */ -int needEnumerateSubdevices(int isMidi) { - initAlsaSupport(); - return isMidi ? alsa_enumerate_midi_subdevices - : alsa_enumerate_pcm_subdevices; -} - - -/* - * deviceID contains packed card, device and subdevice numbers - * each number takes 10 bits - * "default" device has id == ALSA_DEFAULT_DEVICE_ID - */ -UINT32 encodeDeviceID(int card, int device, int subdevice) { - return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10) - | (subdevice & 0x3FF)) + 1; -} - - -void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, - int isMidi) { - deviceID--; - *card = (deviceID >> 20) & 0x3FF; - *device = (deviceID >> 10) & 0x3FF; - if (needEnumerateSubdevices(isMidi)) { - *subdevice = deviceID & 0x3FF; - } else { - *subdevice = -1; // ALSA will choose any subdevices - } -} - - -void getDeviceString(char* buffer, int card, int device, int subdevice, - int usePlugHw, int isMidi) { - if (needEnumerateSubdevices(isMidi)) { - sprintf(buffer, "%s:%d,%d,%d", - usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, - card, device, subdevice); - } else { - sprintf(buffer, "%s:%d,%d", - usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, - card, device); - } -} - - -void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, - int usePlugHw, int isMidi) { - int card, device, subdevice; - - if (deviceID == ALSA_DEFAULT_DEVICE_ID) { - strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME); - } else { - decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi); - getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi); - } -} - - -static int hasGottenALSAVersion = FALSE; -#define ALSAVersionString_LENGTH 200 -static char ALSAVersionString[ALSAVersionString_LENGTH]; - -void getALSAVersion(char* buffer, int len) { - if (!hasGottenALSAVersion) { - // get alsa version from proc interface - FILE* file; - int curr, len, totalLen, inVersionString; - file = fopen(ALSA_VERSION_PROC_FILE, "r"); - ALSAVersionString[0] = 0; - if (file) { - if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) { - // parse for version number - totalLen = strlen(ALSAVersionString); - inVersionString = FALSE; - len = 0; - curr = 0; - while (curr < totalLen) { - if (!inVersionString) { - // is this char the beginning of a version string ? - if (ALSAVersionString[curr] >= '0' - && ALSAVersionString[curr] <= '9') { - inVersionString = TRUE; - } - } - if (inVersionString) { - // the version string ends with white space - if (ALSAVersionString[curr] <= 32) { - break; - } - if (curr != len) { - // copy this char to the beginning of the string - ALSAVersionString[len] = ALSAVersionString[curr]; - } - len++; - } - curr++; - } - // remove trailing dots - while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { - len--; - } - // null terminate - ALSAVersionString[len] = 0; - } - fclose(file); - hasGottenALSAVersion = TRUE; - } - } - strncpy(buffer, ALSAVersionString, len); -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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. - */ - -#include -#include "Utilities.h" - -#ifndef PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED -#define PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED - -#define ALSA_VERSION_PROC_FILE "/proc/asound/version" -#define ALSA_HARDWARE "hw" -#define ALSA_HARDWARE_CARD ALSA_HARDWARE":%d" -#define ALSA_HARDWARE_DEVICE ALSA_HARDWARE_CARD",%d" -#define ALSA_HARDWARE_SUBDEVICE ALSA_HARDWARE_DEVICE",%d" - -#define ALSA_PLUGHARDWARE "plughw" -#define ALSA_DEFAULT_DEVICE_NAME "default" - -#define ALSA_DEFAULT_DEVICE_ID (0) - -#define ALSA_PCM (0) -#define ALSA_RAWMIDI (1) - -// for use in info objects -#define ALSA_VENDOR "ALSA (http://www.alsa-project.org)" - -// Environment variable for inclusion of subdevices in device listing. -// If this variable is unset or "no", then subdevices are ignored, and -// it's ALSA's choice which one to use (enables hardware mixing) -#define ENV_ENUMERATE_PCM_SUBDEVICES "ALSA_ENUMERATE_PCM_SUBDEVICES" - -// if defined, subdevices are listed. -//#undef ALSA_MIDI_ENUMERATE_SUBDEVICES -#define ALSA_MIDI_ENUMERATE_SUBDEVICES - -// must be called before any ALSA calls -void initAlsaSupport(); - -/* if true (non-zero), ALSA sub devices should be listed as separate devices - */ -int needEnumerateSubdevices(int isMidi); - - -/* - * deviceID contains packed card, device and subdevice numbers - * each number takes 10 bits - * "default" device has id == ALSA_DEFAULT_DEVICE_ID - */ -UINT32 encodeDeviceID(int card, int device, int subdevice); - -void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, - int isMidi); - -void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, - int usePlugHw, int isMidi); - -void getALSAVersion(char* buffer, int len); - - -#endif // PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiIn.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiIn.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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 - -#if USE_PLATFORM_MIDI_IN == TRUE - - -#include -#include "PlatformMidi.h" -#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h" -#if defined(i586) -#include -#endif - -/* - * Helper methods - */ - -static inline UINT32 packMessage(int status, int data1, int data2) { - return ((status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16)); -} - - -static void setShortMessage(MidiMessage* message, - int status, int data1, int data2) { - message->type = SHORT_MESSAGE; - message->data.s.packedMsg = packMessage(status, data1, data2); -} - - -static void setRealtimeMessage(MidiMessage* message, int status) { - setShortMessage(message, status, 0, 0); -} - - -static void set14bitMessage(MidiMessage* message, int status, int value) { - TRACE3("14bit value: %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); - value &= 0x3FFF; - TRACE3("14bit value (2): %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); - setShortMessage(message, status, - value & 0x7F, - (value >> 7) & 0x7F); -} - - -/* - * implementation of the platform-dependent - * MIDI in functions declared in PlatformMidi.h - */ - -char* MIDI_IN_GetErrorStr(INT32 err) { - return (char*) getErrorStr(err); -} - -INT32 MIDI_IN_GetNumDevices() { -/* Workaround for 6842956: 32bit app on 64bit bsd - * gets assertion failure trying to open midiIn ports. - * Untill the issue is fixed in ALSA - * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807) - * report no midi in devices in the configuration. - */ -#if defined(i586) - static int jre32onbsd64 = -1; - if (jre32onbsd64 < 0) { - jre32onbsd64 = 0; - /* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN" - * environment variable. - */ - if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) { - struct utsname u; - jre32onbsd64 = 0; - if (uname(&u) == 0) { - if (strstr(u.machine, "64") != NULL) { - TRACE0("jre32 on bsd64 detected - report no midiIn devices\n"); - jre32onbsd64 = 1; - } - } - } - } - if (jre32onbsd64) { - return 0; - } -#endif - - TRACE0("MIDI_IN_GetNumDevices()\n"); - - return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT); -} - - -INT32 MIDI_IN_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceName(SND_RAWMIDI_STREAM_INPUT, deviceIndex, - name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceVendor(deviceIndex, name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceDescription(SND_RAWMIDI_STREAM_INPUT, deviceIndex, - name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceVersion(deviceIndex, name, nameLength); - return ret; -} - -/*************************************************************************/ - -INT32 MIDI_IN_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { - INT32 ret; - TRACE0("> MIDI_IN_OpenDevice\n"); - ret = openMidiDevice(SND_RAWMIDI_STREAM_INPUT, deviceIndex, handle); - TRACE1("< MIDI_IN_OpenDevice: returning %d\n", (int) ret); - return ret; -} - - -INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) { - INT32 ret; - TRACE0("> MIDI_IN_CloseDevice\n"); - ret = closeMidiDevice(handle); - TRACE1("< MIDI_IN_CloseDevice: returning %d\n", (int) ret); - return ret; -} - - -INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_IN_StartDevice\n"); - return MIDI_SUCCESS; -} - - -INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_IN_StopDevice\n"); - return MIDI_SUCCESS; -} - - -INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) { - return getMidiTimestamp(handle); -} - - -/* read the next message from the queue */ -MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) { - snd_seq_event_t alsa_message; - MidiMessage* jdk_message; - int err; - char buffer[1]; - int status; - - TRACE0("> MIDI_IN_GetMessage\n"); - if (!handle) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): handle is NULL\n"); - return NULL; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): native handle is NULL\n"); - return NULL; - } - if (!handle->platformData) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): platformData is NULL\n"); - return NULL; - } - - /* For MIDI In, the device is left in non blocking mode. So if there is - no data from the device, snd_rawmidi_read() returns with -11 (EAGAIN). - This results in jumping back to the Java layer. */ - while (TRUE) { - TRACE0("before snd_rawmidi_read()\n"); - err = snd_rawmidi_read((snd_rawmidi_t*) handle->deviceHandle, buffer, 1); - TRACE0("after snd_rawmidi_read()\n"); - if (err != 1) { - ERROR2("< ERROR: MIDI_IN_GetMessage(): snd_rawmidi_read() returned %d : %s\n", err, snd_strerror(err)); - return NULL; - } - // printf("received byte: %d\n", buffer[0]); - err = snd_midi_event_encode_byte((snd_midi_event_t*) handle->platformData, - (int) buffer[0], - &alsa_message); - if (err == 1) { - break; - } else if (err < 0) { - ERROR1("< ERROR: MIDI_IN_GetMessage(): snd_midi_event_encode_byte() returned %d\n", err); - return NULL; - } - } - jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1); - if (!jdk_message) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); - return NULL; - } - // TODO: tra - switch (alsa_message.type) { - case SND_SEQ_EVENT_NOTEON: - case SND_SEQ_EVENT_NOTEOFF: - case SND_SEQ_EVENT_KEYPRESS: - status = (alsa_message.type == SND_SEQ_EVENT_KEYPRESS) ? 0xA0 : - (alsa_message.type == SND_SEQ_EVENT_NOTEON) ? 0x90 : 0x80; - status |= alsa_message.data.note.channel; - setShortMessage(jdk_message, status, - alsa_message.data.note.note, - alsa_message.data.note.velocity); - break; - - case SND_SEQ_EVENT_CONTROLLER: - status = 0xB0 | alsa_message.data.control.channel; - setShortMessage(jdk_message, status, - alsa_message.data.control.param, - alsa_message.data.control.value); - break; - - case SND_SEQ_EVENT_PGMCHANGE: - case SND_SEQ_EVENT_CHANPRESS: - status = (alsa_message.type == SND_SEQ_EVENT_PGMCHANGE) ? 0xC0 : 0xD0; - status |= alsa_message.data.control.channel; - setShortMessage(jdk_message, status, - alsa_message.data.control.value, 0); - break; - - case SND_SEQ_EVENT_PITCHBEND: - status = 0xE0 | alsa_message.data.control.channel; - // $$mp 2003-09-23: - // possible hack to work around a bug in ALSA. Necessary for - // ALSA 0.9.2. May be fixed in newer versions of ALSA. - // alsa_message.data.control.value ^= 0x2000; - // TRACE1("pitchbend value: %d\n", alsa_message.data.control.value); - set14bitMessage(jdk_message, status, - alsa_message.data.control.value); - break; - - /* System exclusive messages */ - - case SND_SEQ_EVENT_SYSEX: - jdk_message->type = LONG_MESSAGE; - jdk_message->data.l.size = alsa_message.data.ext.len; - jdk_message->data.l.data = malloc(alsa_message.data.ext.len); - if (jdk_message->data.l.data == NULL) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); - free(jdk_message); - jdk_message = NULL; - } else { - memcpy(jdk_message->data.l.data, alsa_message.data.ext.ptr, alsa_message.data.ext.len); - } - break; - - /* System common messages */ - - case SND_SEQ_EVENT_QFRAME: - setShortMessage(jdk_message, 0xF1, - alsa_message.data.control.value & 0x7F, 0); - break; - - case SND_SEQ_EVENT_SONGPOS: - set14bitMessage(jdk_message, 0xF2, - alsa_message.data.control.value); - break; - - case SND_SEQ_EVENT_SONGSEL: - setShortMessage(jdk_message, 0xF3, - alsa_message.data.control.value & 0x7F, 0); - break; - - case SND_SEQ_EVENT_TUNE_REQUEST: - setRealtimeMessage(jdk_message, 0xF6); - break; - - /* System realtime messages */ - - case SND_SEQ_EVENT_CLOCK: - setRealtimeMessage(jdk_message, 0xF8); - break; - - case SND_SEQ_EVENT_START: - setRealtimeMessage(jdk_message, 0xFA); - break; - - case SND_SEQ_EVENT_CONTINUE: - setRealtimeMessage(jdk_message, 0xFB); - break; - - case SND_SEQ_EVENT_STOP: - setRealtimeMessage(jdk_message, 0xFC); - break; - - case SND_SEQ_EVENT_SENSING: - setRealtimeMessage(jdk_message, 0xFE); - break; - - case SND_SEQ_EVENT_RESET: - setRealtimeMessage(jdk_message, 0xFF); - break; - - default: - ERROR0("< ERROR: MIDI_IN_GetMessage(): unhandled ALSA MIDI message type\n"); - free(jdk_message); - jdk_message = NULL; - - } - - // set timestamp - if (jdk_message != NULL) { - jdk_message->timestamp = getMidiTimestamp(handle); - } - TRACE1("< MIDI_IN_GetMessage: returning %p\n", jdk_message); - return jdk_message; -} - - -void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) { - if (!msg) { - ERROR0("< ERROR: MIDI_IN_ReleaseMessage(): message is NULL\n"); - return; - } - if (msg->type == LONG_MESSAGE && msg->data.l.data) { - free(msg->data.l.data); - } - free(msg); -} - -#endif /* USE_PLATFORM_MIDI_IN */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiOut.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiOut.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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 - -#if USE_PLATFORM_MIDI_OUT == TRUE - -#include -#include "PlatformMidi.h" -#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h" - - - -static int CHANNEL_MESSAGE_LENGTH[] = { - -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 3, 3, 2, 2, 3 }; -/* 8x 9x Ax Bx Cx Dx Ex */ - -static int SYSTEM_MESSAGE_LENGTH[] = { - -1, 2, 3, 2, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1 }; -/* F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF */ - - -// the returned length includes the status byte. -// for illegal messages, -1 is returned. -static int getShortMessageLength(int status) { - int dataLength = 0; - if (status < 0xF0) { // channel voice message - dataLength = CHANNEL_MESSAGE_LENGTH[(status >> 4) & 0xF]; - } else { - dataLength = SYSTEM_MESSAGE_LENGTH[status & 0xF]; - } - return dataLength; -} - - -/* - * implementation of the platform-dependent - * MIDI out functions declared in PlatformMidi.h - */ -char* MIDI_OUT_GetErrorStr(INT32 err) { - return (char*) getErrorStr(err); -} - - -INT32 MIDI_OUT_GetNumDevices() { - TRACE0("MIDI_OUT_GetNumDevices()\n"); - return getMidiDeviceCount(SND_RAWMIDI_STREAM_OUTPUT); -} - - -INT32 MIDI_OUT_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceName()\n"); - return getMidiDeviceName(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, - name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceVendor()\n"); - return getMidiDeviceVendor(deviceIndex, name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceDescription()\n"); - return getMidiDeviceDescription(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, - name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceVersion()\n"); - return getMidiDeviceVersion(deviceIndex, name, nameLength); -} - - -/* *************************** MidiOutDevice implementation *************** */ - -INT32 MIDI_OUT_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { - TRACE1("MIDI_OUT_OpenDevice(): deviceIndex: %d\n", (int) deviceIndex); - return openMidiDevice(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, handle); -} - - -INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_OUT_CloseDevice()\n"); - return closeMidiDevice(handle); -} - - -INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { - return getMidiTimestamp(handle); -} - - -INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, - UINT32 timestamp) { - int err; - int status; - int data1; - int data2; - char buffer[3]; - - TRACE2("> MIDI_OUT_SendShortMessage() %x, time: %u\n", packedMsg, (unsigned int) timestamp); - if (!handle) { - ERROR0("< ERROR: MIDI_OUT_SendShortMessage(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - status = (packedMsg & 0xFF); - buffer[0] = (char) status; - buffer[1] = (char) ((packedMsg >> 8) & 0xFF); - buffer[2] = (char) ((packedMsg >> 16) & 0xFF); - TRACE4("status: %d, data1: %d, data2: %d, length: %d\n", (int) buffer[0], (int) buffer[1], (int) buffer[2], getShortMessageLength(status)); - err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, buffer, getShortMessageLength(status)); - if (err < 0) { - ERROR1(" ERROR: MIDI_OUT_SendShortMessage(): snd_rawmidi_write() returned %d\n", err); - } - - TRACE0("< MIDI_OUT_SendShortMessage()\n"); - return err; -} - - -INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, - UINT32 size, UINT32 timestamp) { - int err; - - TRACE2("> MIDI_OUT_SendLongMessage() size %u, time: %u\n", (unsigned int) size, (unsigned int) timestamp); - if (!handle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!data) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): data is NULL\n"); - return MIDI_INVALID_HANDLE; - } - err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, - data, size); - if (err < 0) { - ERROR1(" ERROR: MIDI_OUT_SendLongMessage(): snd_rawmidi_write() returned %d\n", err); - } - - TRACE0("< MIDI_OUT_SendLongMessage()\n"); - return err; -} - - -#endif /* USE_PLATFORM_MIDI_OUT */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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_BsdOS_ALSA_MidiUtils.h" -#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h" -#include -#include - -static INT64 getTimeInMicroseconds() { - struct timeval tv; - - gettimeofday(&tv, NULL); - return (tv.tv_sec * 1000000UL) + tv.tv_usec; -} - - -const char* getErrorStr(INT32 err) { - return snd_strerror((int) err); -} - - - -// callback for iteration through devices -// returns TRUE if iteration should continue -typedef int (*DeviceIteratorPtr)(UINT32 deviceID, - snd_rawmidi_info_t* rawmidi_info, - snd_ctl_card_info_t* cardinfo, - void *userData); - -// for each ALSA device, call iterator. userData is passed to the iterator -// returns total number of iterations -static int iterateRawmidiDevices(snd_rawmidi_stream_t direction, - DeviceIteratorPtr iterator, - void* userData) { - int count = 0; - int subdeviceCount; - int card, dev, subDev; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_rawmidi_t *rawmidi; - snd_rawmidi_info_t *rawmidi_info; - snd_ctl_card_info_t *card_info, *defcardinfo = NULL; - UINT32 deviceID; - int doContinue = TRUE; - - snd_rawmidi_info_malloc(&rawmidi_info); - snd_ctl_card_info_malloc(&card_info); - - // 1st try "default" device - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_rawmidi_open(&rawmidi, NULL, ALSA_DEFAULT_DEVICE_NAME, - SND_RAWMIDI_NONBLOCK); - } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_open(NULL, &rawmidi, ALSA_DEFAULT_DEVICE_NAME, - SND_RAWMIDI_NONBLOCK); - } else { - ERROR0("ERROR: iterateRawmidiDevices(): direction is neither" - " SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); - err = MIDI_INVALID_ARGUMENT; - } - if (err < 0) { - ERROR1("ERROR: snd_rawmidi_open (\"default\"): %s\n", - snd_strerror(err)); - } else { - err = snd_rawmidi_info(rawmidi, rawmidi_info); - - snd_rawmidi_close(rawmidi); - if (err < 0) { - ERROR1("ERROR: snd_rawmidi_info (\"default\"): %s\n", - snd_strerror(err)); - } else { - // try to get card info - card = snd_rawmidi_info_get_card(rawmidi_info); - if (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { - if (snd_ctl_card_info(handle, card_info) >= 0) { - defcardinfo = card_info; - } - snd_ctl_close(handle); - } - } - // call calback function for the device - if (iterator != NULL) { - doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, rawmidi_info, - defcardinfo, userData); - } - count++; - } - } - - // iterate cards - card = -1; - TRACE0("testing for cards...\n"); - if (snd_card_next(&card) >= 0) { - TRACE1("Found card %d\n", card); - while (doContinue && (card >= 0)) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("Opening control for alsa rawmidi device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); - } else { - TRACE0("snd_ctl_open() SUCCESS\n"); - err = snd_ctl_card_info(handle, card_info); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err)); - } else { - TRACE0("snd_ctl_card_info() SUCCESS\n"); - dev = -1; - while (doContinue) { - if (snd_ctl_rawmidi_next_device(handle, &dev) < 0) { - ERROR0("snd_ctl_rawmidi_next_device\n"); - } - TRACE0("snd_ctl_rawmidi_next_device() SUCCESS\n"); - if (dev < 0) { - break; - } - snd_rawmidi_info_set_device(rawmidi_info, dev); - snd_rawmidi_info_set_subdevice(rawmidi_info, 0); - snd_rawmidi_info_set_stream(rawmidi_info, direction); - err = snd_ctl_rawmidi_info(handle, rawmidi_info); - TRACE0("after snd_ctl_rawmidi_info()\n"); - if (err < 0) { - if (err != -ENOENT) { - ERROR2("ERROR: snd_ctl_rawmidi_info, card=%d: %s", card, snd_strerror(err)); - } - } else { - TRACE0("snd_ctl_rawmidi_info() SUCCESS\n"); - subdeviceCount = needEnumerateSubdevices(ALSA_RAWMIDI) - ? snd_rawmidi_info_get_subdevices_count(rawmidi_info) - : 1; - if (iterator!=NULL) { - for (subDev = 0; subDev < subdeviceCount; subDev++) { - TRACE3(" Iterating %d,%d,%d\n", card, dev, subDev); - deviceID = encodeDeviceID(card, dev, subDev); - doContinue = (*iterator)(deviceID, rawmidi_info, - card_info, userData); - count++; - TRACE0("returned from iterator\n"); - if (!doContinue) { - break; - } - } - } else { - count += subdeviceCount; - } - } - } // of while(doContinue) - } - snd_ctl_close(handle); - } - if (snd_card_next(&card) < 0) { - break; - } - } - } else { - ERROR0("No cards found!\n"); - } - snd_ctl_card_info_free(card_info); - snd_rawmidi_info_free(rawmidi_info); - return count; -} - - - -int getMidiDeviceCount(snd_rawmidi_stream_t direction) { - int deviceCount; - TRACE0("> getMidiDeviceCount()\n"); - initAlsaSupport(); - deviceCount = iterateRawmidiDevices(direction, NULL, NULL); - TRACE0("< getMidiDeviceCount()\n"); - return deviceCount; -} - - - -/* - userData is assumed to be a pointer to ALSA_MIDIDeviceDescription. - ALSA_MIDIDeviceDescription->index has to be set to the index of the device - we want to get information of before this method is called the first time via - iterateRawmidiDevices(). On each call of this method, - ALSA_MIDIDeviceDescription->index is decremented. If it is equal to zero, - we have reached the desired device, so action is taken. - So after successful completion of iterateRawmidiDevices(), - ALSA_MIDIDeviceDescription->index is zero. If it isn't, this is an - indication of an error. -*/ -static int deviceInfoIterator(UINT32 deviceID, snd_rawmidi_info_t *rawmidi_info, - snd_ctl_card_info_t *cardinfo, void *userData) { - char buffer[300]; - ALSA_MIDIDeviceDescription* desc = (ALSA_MIDIDeviceDescription*)userData; -#ifdef ALSA_MIDI_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - TRACE0("deviceInfoIterator\n"); - initAlsaSupport(); - if (desc->index == 0) { - // we found the device with correct index - desc->deviceID = deviceID; - - buffer[0]=' '; buffer[1]='['; - // buffer[300] is enough to store the actual device string w/o overrun - getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_RAWMIDI); - strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); - strncpy(desc->name, - (cardinfo != NULL) - ? snd_ctl_card_info_get_id(cardinfo) - : snd_rawmidi_info_get_id(rawmidi_info), - desc->strLen - strlen(buffer)); - strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); - desc->description[0] = 0; - if (cardinfo != NULL) { - strncpy(desc->description, snd_ctl_card_info_get_name(cardinfo), - desc->strLen); - strncat(desc->description, ", ", - desc->strLen - strlen(desc->description)); - } - strncat(desc->description, snd_rawmidi_info_get_id(rawmidi_info), - desc->strLen - strlen(desc->description)); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_rawmidi_info_get_name(rawmidi_info), - desc->strLen - strlen(desc->description)); - TRACE2("Returning %s, %s\n", desc->name, desc->description); - return FALSE; // do not continue iteration - } - desc->index--; - return TRUE; -} - - -static int getMIDIDeviceDescriptionByIndex(snd_rawmidi_stream_t direction, - ALSA_MIDIDeviceDescription* desc) { - initAlsaSupport(); - TRACE1(" getMIDIDeviceDescriptionByIndex (index = %d)\n", desc->index); - iterateRawmidiDevices(direction, &deviceInfoIterator, desc); - return (desc->index == 0) ? MIDI_SUCCESS : MIDI_INVALID_DEVICEID; -} - - - -int initMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc, int index) { - int ret = MIDI_SUCCESS; - desc->index = index; - desc->strLen = 200; - desc->name = (char*) calloc(desc->strLen + 1, 1); - desc->description = (char*) calloc(desc->strLen + 1, 1); - if (! desc->name || - ! desc->description) { - ret = MIDI_OUT_OF_MEMORY; - } - return ret; -} - - -void freeMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc) { - if (desc->name) { - free(desc->name); - } - if (desc->description) { - free(desc->description); - } -} - - -int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, char *name, - UINT32 nameLength) { - ALSA_MIDIDeviceDescription desc; - int ret; - - TRACE1("getMidiDeviceName: nameLength: %d\n", (int) nameLength); - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - TRACE0("getMidiDeviceName: initMIDIDeviceDescription() SUCCESS\n"); - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); - strncpy(name, desc.name, nameLength - 1); - name[nameLength - 1] = 0; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -int getMidiDeviceVendor(int index, char *name, UINT32 nameLength) { - strncpy(name, ALSA_VENDOR, nameLength - 1); - name[nameLength - 1] = 0; - return MIDI_SUCCESS; -} - - -int getMidiDeviceDescription(snd_rawmidi_stream_t direction, - int index, char *name, UINT32 nameLength) { - ALSA_MIDIDeviceDescription desc; - int ret; - - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - strncpy(name, desc.description, nameLength - 1); - name[nameLength - 1] = 0; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -int getMidiDeviceVersion(int index, char *name, UINT32 nameLength) { - getALSAVersion(name, nameLength); - return MIDI_SUCCESS; -} - - -static int getMidiDeviceID(snd_rawmidi_stream_t direction, int index, - UINT32* deviceID) { - ALSA_MIDIDeviceDescription desc; - int ret; - - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - // TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); - *deviceID = desc.deviceID; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -/* - direction has to be either SND_RAWMIDI_STREAM_INPUT or - SND_RAWMIDI_STREAM_OUTPUT. - Returns 0 on success. Otherwise, MIDI_OUT_OF_MEMORY, MIDI_INVALID_ARGUMENT - or a negative ALSA error code is returned. -*/ -INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, - MidiDeviceHandle** handle) { - snd_rawmidi_t* native_handle; - snd_midi_event_t* event_parser = NULL; - int err; - UINT32 deviceID = 0; - char devicename[100]; -#ifdef ALSA_MIDI_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - TRACE0("> openMidiDevice()\n"); - - (*handle) = (MidiDeviceHandle*) calloc(sizeof(MidiDeviceHandle), 1); - if (!(*handle)) { - ERROR0("ERROR: openDevice: out of memory\n"); - return MIDI_OUT_OF_MEMORY; - } - - // TODO: iterate to get dev ID from index - err = getMidiDeviceID(direction, deviceIndex, &deviceID); - TRACE1(" openMidiDevice(): deviceID: %d\n", (int) deviceID); - getDeviceStringFromDeviceID(devicename, deviceID, - usePlugHw, ALSA_RAWMIDI); - TRACE1(" openMidiDevice(): deviceString: %s\n", devicename); - - // finally open the device - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_rawmidi_open(&native_handle, NULL, devicename, - SND_RAWMIDI_NONBLOCK); - } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_open(NULL, &native_handle, devicename, - SND_RAWMIDI_NONBLOCK); - } else { - ERROR0(" ERROR: openMidiDevice(): direction is neither SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); - err = MIDI_INVALID_ARGUMENT; - } - if (err < 0) { - ERROR1("< ERROR: openMidiDevice(): snd_rawmidi_open() returned %d\n", err); - free(*handle); - (*handle) = NULL; - return err; - } - /* We opened with non-blocking behaviour to not get hung if the device - is used by a different process. Writing, however, should - be blocking. So we change it here. */ - if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_nonblock(native_handle, 0); - if (err < 0) { - ERROR1(" ERROR: openMidiDevice(): snd_rawmidi_nonblock() returned %d\n", err); - snd_rawmidi_close(native_handle); - free(*handle); - (*handle) = NULL; - return err; - } - } - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_midi_event_new(EVENT_PARSER_BUFSIZE, &event_parser); - if (err < 0) { - ERROR1(" ERROR: openMidiDevice(): snd_midi_event_new() returned %d\n", err); - snd_rawmidi_close(native_handle); - free(*handle); - (*handle) = NULL; - return err; - } - } - - (*handle)->deviceHandle = (void*) native_handle; - (*handle)->startTime = getTimeInMicroseconds(); - (*handle)->platformData = event_parser; - TRACE0("< openMidiDevice(): succeeded\n"); - return err; -} - - - -INT32 closeMidiDevice(MidiDeviceHandle* handle) { - int err; - - TRACE0("> closeMidiDevice()\n"); - if (!handle) { - ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: closeMidiDevice(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - err = snd_rawmidi_close((snd_rawmidi_t*) handle->deviceHandle); - TRACE1(" snd_rawmidi_close() returns %d\n", err); - if (handle->platformData) { - snd_midi_event_free((snd_midi_event_t*) handle->platformData); - } - free(handle); - TRACE0("< closeMidiDevice: succeeded\n"); - return err; -} - - -INT64 getMidiTimestamp(MidiDeviceHandle* handle) { - if (!handle) { - ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - return getTimeInMicroseconds() - handle->startTime; -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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. - */ - -#include -#include "Utilities.h" -#include "PlatformMidi.h" - - -#ifndef PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED -#define PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED - -#define EVENT_PARSER_BUFSIZE (2048) - -// if this is defined, use plughw: devices -//#define ALSA_MIDI_USE_PLUGHW -#undef ALSA_MIDI_USE_PLUGHW - -typedef struct tag_ALSA_MIDIDeviceDescription { - int index; // in - int strLen; // in - INT32 deviceID; // out - char* name; // out - char* description; // out -} ALSA_MIDIDeviceDescription; - - -const char* getErrorStr(INT32 err); - -/* Returns the number of devices. */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceCount(snd_rawmidi_stream_t direction); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, - char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -int getMidiDeviceVendor(int index, char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceDescription(snd_rawmidi_stream_t direction, int index, - char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -int getMidiDeviceVersion(int index, char *name, UINT32 nameLength); - -// returns 0 on success, otherwise MIDI_OUT_OF_MEMORY or ALSA error code -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, - MidiDeviceHandle** handle); - -// returns 0 on success, otherwise a (negative) ALSA error code -INT32 closeMidiDevice(MidiDeviceHandle* handle); - -INT64 getMidiTimestamp(MidiDeviceHandle* handle); - -#endif // PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCM.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCM.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,941 +0,0 @@ -/* - * Copyright (c) 2002, 2012, 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_BsdOS_ALSA_PCMUtils.h" -#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h" -#include "DirectAudio.h" - -#if USE_DAUDIO == TRUE - -// GetPosition method 1: based on how many bytes are passed to the kernel driver -// + does not need much processor resources -// - not very exact, "jumps" -// GetPosition method 2: ask kernel about actual position of playback. -// - very exact -// - switch to kernel layer for each call -// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA -// quick tests on a Pentium 200MMX showed max. 1.5% processor usage -// for playing back a CD-quality file and printing 20x per second a line -// on the console with the current time. So I guess performance is not such a -// factor here. -//#define GET_POSITION_METHOD1 -#define GET_POSITION_METHOD2 - - -// The default time for a period in microseconds. -// For very small buffers, only 2 periods are used. -#define DEFAULT_PERIOD_TIME 20000 /* 20ms */ - -///// implemented functions of DirectAudio.h - -INT32 DAUDIO_GetDirectAudioDeviceCount() { - return (INT32) getAudioDeviceCount(); -} - - -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) { - ALSA_AudioDeviceDescription adesc; - - adesc.index = (int) mixerIndex; - adesc.strLen = DAUDIO_STRING_LENGTH; - - adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines)); - adesc.deviceID = &(description->deviceID); - adesc.name = description->name; - adesc.vendor = description->vendor; - adesc.description = description->description; - adesc.version = description->version; - - return getAudioDeviceDescriptionByIndex(&adesc); -} - -#define MAX_BIT_INDEX 6 -// returns -// 6: for anything above 24-bit -// 5: for 4 bytes sample size, 24-bit -// 4: for 3 bytes sample size, 24-bit -// 3: for 3 bytes sample size, 20-bit -// 2: for 2 bytes sample size, 16-bit -// 1: for 1 byte sample size, 8-bit -// 0: for anything else -int getBitIndex(int sampleSizeInBytes, int significantBits) { - if (significantBits > 24) return 6; - if (sampleSizeInBytes == 4 && significantBits == 24) return 5; - if (sampleSizeInBytes == 3) { - if (significantBits == 24) return 4; - if (significantBits == 20) return 3; - } - if (sampleSizeInBytes == 2 && significantBits == 16) return 2; - if (sampleSizeInBytes == 1 && significantBits == 8) return 1; - return 0; -} - -int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) { - switch(bitIndex) { - case 1: return 1; - case 2: return 2; - case 3: /* fall through */ - case 4: return 3; - case 5: return 4; - } - return sampleSizeInBytes; -} - -int getSignificantBits(int bitIndex, int significantBits) { - switch(bitIndex) { - case 1: return 8; - case 2: return 16; - case 3: return 20; - case 4: /* fall through */ - case 5: return 24; - } - return significantBits; -} - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { - snd_pcm_t* handle; - snd_pcm_format_mask_t* formatMask; - snd_pcm_format_t format; - snd_pcm_hw_params_t* hwParams; - int handledBits[MAX_BIT_INDEX+1]; - - int ret; - int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; - int origSampleSizeInBytes, origSignificantBits; - unsigned int channels, minChannels, maxChannels; - int rate, bitIndex; - - for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; - if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { - return; - } - ret = snd_pcm_format_mask_malloc(&formatMask); - if (ret != 0) { - ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); - } else { - ret = snd_pcm_hw_params_malloc(&hwParams); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - ret = snd_pcm_hw_params_any(handle, hwParams); - /* snd_pcm_hw_params_any can return a positive value on success too */ - if (ret < 0) { - ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); - } else { - /* for the logic following this code, set ret to 0 to indicate success */ - ret = 0; - } - } - snd_pcm_hw_params_get_format_mask(hwParams, formatMask); - if (ret == 0) { - ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); - } - } - if (ret == 0) { - ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); - } - } - - // since we queried the hw: device, for many soundcards, it will only - // report the maximum number of channels (which is the only way to talk - // to the hw: device). Since we will, however, open the plughw: device - // when opening the Source/TargetDataLine, we can safely assume that - // also the channels 1..maxChannels are available. -#ifdef ALSA_PCM_USE_PLUGHW - minChannels = 1; -#endif - if (ret == 0) { - // plughw: supports any sample rate - rate = -1; - for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { - if (snd_pcm_format_mask_test(formatMask, format)) { - // format exists - if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, - &origSignificantBits, - &isSigned, &isBigEndian, &enc)) { - // now if we use plughw:, we can use any bit size below the - // natively supported ones. Some ALSA drivers only support the maximum - // bit size, so we add any sample rates below the reported one. - // E.g. this iteration reports support for 16-bit. - // getBitIndex will return 2, so it will add entries for - // 16-bit (bitIndex=2) and in the next do-while loop iteration, - // it will decrease bitIndex and will therefore add 8-bit support. - bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); - do { - if (bitIndex == 0 - || bitIndex == MAX_BIT_INDEX - || !handledBits[bitIndex]) { - handledBits[bitIndex] = TRUE; - sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); - significantBits = getSignificantBits(bitIndex, origSignificantBits); - if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { - // avoid too many channels explicitly listed - // just add -1, min, and max - DAUDIO_AddAudioFormat(creator, significantBits, - -1, -1, rate, - enc, isSigned, isBigEndian); - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * minChannels, - minChannels, rate, - enc, isSigned, isBigEndian); - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * maxChannels, - maxChannels, rate, - enc, isSigned, isBigEndian); - } else { - for (channels = minChannels; channels <= maxChannels; channels++) { - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * channels, - channels, rate, - enc, isSigned, isBigEndian); - } - } - } -#ifndef ALSA_PCM_USE_PLUGHW - // without plugin, do not add fake formats - break; -#endif - } while (--bitIndex > 0); - } else { - TRACE1("could not get format from alsa for format %d\n", format); - } - } else { - //TRACE1("Format %d not supported\n", format); - } - } // for loop - snd_pcm_hw_params_free(hwParams); - } - snd_pcm_format_mask_free(formatMask); - } - snd_pcm_close(handle); -} - -/** Workaround for cr 7033899, 7030629: - * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty - * (just opened, underruned or already flushed). - * Sometimes it causes PCM falls to -EBADFD error, - * sometimes causes bufferSize change. - * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used. - */ -/* ******* ALSA PCM INFO ******************** */ -typedef struct tag_AlsaPcmInfo { - snd_pcm_t* handle; - snd_pcm_hw_params_t* hwParams; - snd_pcm_sw_params_t* swParams; - int bufferSizeInBytes; - int frameSize; // storage size in Bytes - unsigned int periods; - snd_pcm_uframes_t periodSize; - short int isRunning; // see comment above - short int isFlushed; // see comment above -#ifdef GET_POSITION_METHOD2 - // to be used exclusively by getBytePosition! - snd_pcm_status_t* positionStatus; -#endif -} AlsaPcmInfo; - - -int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) { - int ret; - int threshold; - - if (useThreshold) { - // start device whenever anything is written to the buffer - threshold = 1; - } else { - // never start the device automatically - threshold = 2000000000; /* near UINT_MAX */ - } - ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold); - if (ret < 0) { - ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -int setStartThreshold(AlsaPcmInfo* info, int useThreshold) { - int ret = 0; - - if (!setStartThresholdNoCommit(info, useThreshold)) { - ret = -1; - } - if (ret == 0) { - // commit it - ret = snd_pcm_sw_params(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); - } - } - return (ret == 0)?TRUE:FALSE; -} - - -// returns TRUE if successful -int setHWParams(AlsaPcmInfo* info, - float sampleRate, - int channels, - int bufferSizeInFrames, - snd_pcm_format_t format) { - unsigned int rrate, periodTime, periods; - int ret, dir; - snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; - - /* choose all parameters */ - ret = snd_pcm_hw_params_any(info->handle, info->hwParams); - if (ret < 0) { - ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the interleaved read/write format */ - ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); - if (ret < 0) { - ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the sample format */ - ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format); - if (ret < 0) { - ERROR1("Sample format not available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the count of channels */ - ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels); - if (ret < 0) { - ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret)); - return FALSE; - } - /* set the stream rate */ - rrate = (int) (sampleRate + 0.5f); - dir = 0; - ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); - if (ret < 0) { - ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); - return FALSE; - } - if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) { - ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate); - return FALSE; - } - /* set the buffer time */ - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); - if (ret < 0) { - ERROR2("Unable to set buffer size to %d frames: %s\n", - (int) alsaBufferSizeInFrames, snd_strerror(ret)); - return FALSE; - } - bufferSizeInFrames = (int) alsaBufferSizeInFrames; - /* set the period time */ - if (bufferSizeInFrames > 1024) { - dir = 0; - periodTime = DEFAULT_PERIOD_TIME; - ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); - if (ret < 0) { - ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); - return FALSE; - } - } else { - /* set the period count for very small buffer sizes to 2 */ - dir = 0; - periods = 2; - ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); - if (ret < 0) { - ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); - return FALSE; - } - } - /* write the parameters to device */ - ret = snd_pcm_hw_params(info->handle, info->hwParams); - if (ret < 0) { - ERROR1("Unable to set hw params: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -// returns 1 if successful -int setSWParams(AlsaPcmInfo* info) { - int ret; - - /* get the current swparams */ - ret = snd_pcm_sw_params_current(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret)); - return FALSE; - } - /* never start the transfer automatically */ - if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) { - return FALSE; - } - - /* allow the transfer when at least period_size samples can be processed */ - ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize); - if (ret < 0) { - ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); - return FALSE; - } - /* write the parameters to the playback device */ - ret = snd_pcm_sw_params(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -static snd_output_t* ALSA_OUTPUT = NULL; - -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) { - snd_pcm_format_mask_t* formatMask; - snd_pcm_format_t format; - int dir; - int ret = 0; - AlsaPcmInfo* info = NULL; - /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ - snd_pcm_uframes_t alsaBufferSizeInFrames = 0; - - - TRACE0("> DAUDIO_Open\n"); -#ifdef USE_TRACE - // for using ALSA debug dump methods - if (ALSA_OUTPUT == NULL) { - snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); - } -#endif - if (channels <= 0) { - ERROR1("ERROR: Invalid number of channels=%d!\n", channels); - return NULL; - } - info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); - if (!info) { - ERROR0("Out of memory\n"); - return NULL; - } - memset(info, 0, sizeof(AlsaPcmInfo)); - // initial values are: stopped, flushed - info->isRunning = 0; - info->isFlushed = 1; - - ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); - if (ret == 0) { - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - ret = snd_pcm_hw_params_malloc(&(info->hwParams)); - if (ret != 0) { - ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - ret = -1; - if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, - isSigned, isBigEndian, encoding)) { - if (setHWParams(info, - sampleRate, - channels, - bufferSizeInBytes / frameSize, - format)) { - info->frameSize = frameSize; - ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); - } - snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); - snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); - info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; - TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", - (int) info->periodSize, info->periods, info->bufferSizeInBytes); - } - } - } - if (ret == 0) { - // set software parameters - ret = snd_pcm_sw_params_malloc(&(info->swParams)); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - if (!setSWParams(info)) { - ret = -1; - } - } - } - if (ret == 0) { - // prepare device - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); - } - } - -#ifdef GET_POSITION_METHOD2 - if (ret == 0) { - ret = snd_pcm_status_malloc(&(info->positionStatus)); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); - } - } -#endif - } - if (ret != 0) { - DAUDIO_Close((void*) info, isSource); - info = NULL; - } else { - // set to non-blocking mode - snd_pcm_nonblock(info->handle, 1); - TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", - (void*) info->handle); - } - return (void*) info; -} - -#ifdef USE_TRACE -void printState(snd_pcm_state_t state) { - if (state == SND_PCM_STATE_OPEN) { - TRACE0("State: SND_PCM_STATE_OPEN\n"); - } - else if (state == SND_PCM_STATE_SETUP) { - TRACE0("State: SND_PCM_STATE_SETUP\n"); - } - else if (state == SND_PCM_STATE_PREPARED) { - TRACE0("State: SND_PCM_STATE_PREPARED\n"); - } - else if (state == SND_PCM_STATE_RUNNING) { - TRACE0("State: SND_PCM_STATE_RUNNING\n"); - } - else if (state == SND_PCM_STATE_XRUN) { - TRACE0("State: SND_PCM_STATE_XRUN\n"); - } - else if (state == SND_PCM_STATE_DRAINING) { - TRACE0("State: SND_PCM_STATE_DRAINING\n"); - } - else if (state == SND_PCM_STATE_PAUSED) { - TRACE0("State: SND_PCM_STATE_PAUSED\n"); - } - else if (state == SND_PCM_STATE_SUSPENDED) { - TRACE0("State: SND_PCM_STATE_SUSPENDED\n"); - } -} -#endif - -int DAUDIO_Start(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - snd_pcm_state_t state; - - TRACE0("> DAUDIO_Start\n"); - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - // set start mode so that it always starts as soon as data is there - setStartThreshold(info, TRUE /* use threshold */); - state = snd_pcm_state(info->handle); - if (state == SND_PCM_STATE_PAUSED) { - // in case it was stopped previously - TRACE0(" Un-pausing...\n"); - ret = snd_pcm_pause(info->handle, FALSE); - if (ret != 0) { - ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret)); - } - } - if (state == SND_PCM_STATE_SUSPENDED) { - TRACE0(" Resuming...\n"); - ret = snd_pcm_resume(info->handle); - if (ret < 0) { - if ((ret != -EAGAIN) && (ret != -ENOSYS)) { - ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret)); - } - } - } - if (state == SND_PCM_STATE_SETUP) { - TRACE0("need to call prepare again...\n"); - // prepare device - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); - } - } - // in case there is still data in the buffers - ret = snd_pcm_start(info->handle); - if (ret != 0) { - if (ret != -EPIPE) { - ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret)); - } - } - // set to non-blocking mode - ret = snd_pcm_nonblock(info->handle, 1); - if (ret != 0) { - ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret)); - } - state = snd_pcm_state(info->handle); -#ifdef USE_TRACE - printState(state); -#endif - ret = (state == SND_PCM_STATE_PREPARED) - || (state == SND_PCM_STATE_RUNNING) - || (state == SND_PCM_STATE_XRUN) - || (state == SND_PCM_STATE_SUSPENDED); - if (ret) { - info->isRunning = 1; - // source line should keep isFlushed value until Write() is called; - // for target data line reset it right now. - if (!isSource) { - info->isFlushed = 0; - } - } - TRACE1("< DAUDIO_Start %s\n", ret?"success":"error"); - return ret?TRUE:FALSE; -} - -int DAUDIO_Stop(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - - TRACE0("> DAUDIO_Stop\n"); - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun - ret = snd_pcm_pause(info->handle, 1); - // set to non-blocking mode - snd_pcm_nonblock(info->handle, 1); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret)); - return FALSE; - } - info->isRunning = 0; - TRACE0("< DAUDIO_Stop success\n"); - return TRUE; -} - -void DAUDIO_Close(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - - TRACE0("DAUDIO_Close\n"); - if (info != NULL) { - if (info->handle != NULL) { - snd_pcm_close(info->handle); - } - if (info->hwParams) { - snd_pcm_hw_params_free(info->hwParams); - } - if (info->swParams) { - snd_pcm_sw_params_free(info->swParams); - } -#ifdef GET_POSITION_METHOD2 - if (info->positionStatus) { - snd_pcm_status_free(info->positionStatus); - } -#endif - free(info); - } -} - -/* - * Underrun and suspend recovery - * returns - * 0: exit native and return 0 - * 1: try again to write/read - * -1: error - exit native with return value -1 - */ -int xrun_recovery(AlsaPcmInfo* info, int err) { - int ret; - - if (err == -EPIPE) { /* underrun / overflow */ - TRACE0("xrun_recovery: underrun/overflow.\n"); - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); - return -1; - } - return 1; - } else if (err == -ESTRPIPE) { - TRACE0("xrun_recovery: suspended.\n"); - ret = snd_pcm_resume(info->handle); - if (ret < 0) { - if (ret == -EAGAIN) { - return 0; /* wait until the suspend flag is released */ - } - return -1; - } - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); - return -1; - } - return 1; - } else if (err == -EAGAIN) { - TRACE0("xrun_recovery: EAGAIN try again flag.\n"); - return 0; - } - - TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err)); - return -1; -} - -// returns -1 on error -int DAUDIO_Write(void* id, char* data, int byteSize) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret, count; - snd_pcm_sframes_t frameSize, writtenFrames; - - TRACE1("> DAUDIO_Write %d bytes\n", byteSize); - - /* sanity */ - if (byteSize <= 0 || info->frameSize <= 0) { - ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n", - (int) byteSize, (int) info->frameSize); - TRACE0("< DAUDIO_Write returning -1\n"); - return -1; - } - - count = 2; // maximum number of trials to recover from underrun - //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); - frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); - do { - writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize); - - if (writtenFrames < 0) { - ret = xrun_recovery(info, (int) writtenFrames); - if (ret <= 0) { - TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret); - return ret; - } - if (count-- <= 0) { - ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n"); - return -1; - } - } else { - break; - } - } while (TRUE); - //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames); - - if (writtenFrames > 0) { - // reset "flushed" flag - info->isFlushed = 0; - } - - ret = (int) (writtenFrames * info->frameSize); - TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); - return ret; -} - -// returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret, count; - snd_pcm_sframes_t frameSize, readFrames; - - TRACE1("> DAUDIO_Read %d bytes\n", byteSize); - /*TRACE3(" info=%p, data=%p, byteSize=%d\n", - (void*) info, (void*) data, (int) byteSize); - TRACE2(" info->frameSize=%d, info->handle=%p\n", - (int) info->frameSize, (void*) info->handle); - */ - /* sanity */ - if (byteSize <= 0 || info->frameSize <= 0) { - ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n", - (int) byteSize, (int) info->frameSize); - TRACE0("< DAUDIO_Read returning -1\n"); - return -1; - } - if (!info->isRunning && info->isFlushed) { - // PCM has nothing to read - return 0; - } - - count = 2; // maximum number of trials to recover from error - //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); - frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); - do { - readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize); - if (readFrames < 0) { - ret = xrun_recovery(info, (int) readFrames); - if (ret <= 0) { - TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret); - return ret; - } - if (count-- <= 0) { - ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n"); - return -1; - } - } else { - break; - } - } while (TRUE); - //ret = snd_pcm_frames_to_bytes(info->handle, readFrames); - ret = (int) (readFrames * info->frameSize); - TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); - return ret; -} - - -int DAUDIO_GetBufferSize(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - - return info->bufferSizeInBytes; -} - -int DAUDIO_StillDraining(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - snd_pcm_state_t state; - - state = snd_pcm_state(info->handle); - //printState(state); - //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE"); - return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE; -} - - -int DAUDIO_Flush(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - - TRACE0("DAUDIO_Flush\n"); - - if (info->isFlushed) { - // nothing to drop - return 1; - } - - ret = snd_pcm_drop(info->handle); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret)); - return FALSE; - } - - info->isFlushed = 1; - if (info->isRunning) { - ret = DAUDIO_Start(id, isSource); - } - return ret; -} - -int DAUDIO_GetAvailable(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - snd_pcm_sframes_t availableInFrames; - snd_pcm_state_t state; - int ret; - - state = snd_pcm_state(info->handle); - if (info->isFlushed || state == SND_PCM_STATE_XRUN) { - // if in xrun state then we have the entire buffer available, - // not 0 as alsa reports - ret = info->bufferSizeInBytes; - } else { - availableInFrames = snd_pcm_avail_update(info->handle); - if (availableInFrames < 0) { - ret = 0; - } else { - //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames); - ret = (int) (availableInFrames * info->frameSize); - } - } - TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); - return ret; -} - -INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) { - // estimate the current position with the buffer size and - // the available bytes to read or write in the buffer. - // not an elegant solution - bytePos will stop on xruns, - // and in race conditions it may jump backwards - // Advantage is that it is indeed based on the samples that go through - // the system (rather than time-based methods) - if (isSource) { - // javaBytePos is the position that is reached when the current - // buffer is played completely - return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes); - } else { - // javaBytePos is the position that was when the current buffer was empty - return (INT64) (javaBytePos + availInBytes); - } -} - -INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - INT64 result = javaBytePos; - snd_pcm_state_t state; - state = snd_pcm_state(info->handle); - - if (!info->isFlushed && state != SND_PCM_STATE_XRUN) { -#ifdef GET_POSITION_METHOD2 - snd_timestamp_t* ts; - snd_pcm_uframes_t framesAvail; - - // note: slight race condition if this is called simultaneously from 2 threads - ret = snd_pcm_status(info->handle, info->positionStatus); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret)); - result = javaBytePos; - } else { - // calculate from time value, or from available bytes - framesAvail = snd_pcm_status_get_avail(info->positionStatus); - result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); - } -#endif -#ifdef GET_POSITION_METHOD3 - snd_pcm_uframes_t framesAvail; - ret = snd_pcm_avail(info->handle, &framesAvail); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret)); - result = javaBytePos; - } else { - result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); - } -#endif -#ifdef GET_POSITION_METHOD1 - result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource)); -#endif - } - //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); - return result; -} - - - -void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { - /* save to ignore, since GetBytePosition - * takes the javaBytePos param into account - */ -} - -int DAUDIO_RequiresServicing(void* id, int isSource) { - // never need servicing on Bsd - return FALSE; -} - -void DAUDIO_Service(void* id, int isSource) { - // never need servicing on Bsd -} - - -#endif // USE_DAUDIO diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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_BsdOS_ALSA_PCMUtils.h" -#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h" - - - -// callback for iteration through devices -// returns TRUE if iteration should continue -// NOTE: cardinfo may be NULL (for "default" device) -typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo, - snd_ctl_card_info_t* cardinfo, void *userData); - -// for each ALSA device, call iterator. userData is passed to the iterator -// returns total number of iterations -int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) { - int count = 0; - int subdeviceCount; - int card, dev, subDev; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_pcm_t *pcm; - snd_pcm_info_t* pcminfo; - snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL; - UINT32 deviceID; - int doContinue = TRUE; - - snd_pcm_info_malloc(&pcminfo); - snd_ctl_card_info_malloc(&cardinfo); - - // 1st try "default" device - err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - if (err < 0) { - // try with the other direction - err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - } - if (err < 0) { - ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err)); - } else { - err = snd_pcm_info(pcm, pcminfo); - snd_pcm_close(pcm); - if (err < 0) { - ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n", - snd_strerror(err)); - } else { - // try to get card info - card = snd_pcm_info_get_card(pcminfo); - if (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { - if (snd_ctl_card_info(handle, cardinfo) >= 0) { - defcardinfo = cardinfo; - } - snd_ctl_close(handle); - } - } - // call callback function for the device - if (iterator != NULL) { - doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo, - defcardinfo, userData); - } - count++; - } - } - - // iterate cards - card = -1; - while (doContinue) { - if (snd_card_next(&card) < 0) { - break; - } - if (card < 0) { - break; - } - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", - card, snd_strerror(err)); - } else { - err = snd_ctl_card_info(handle, cardinfo); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", - card, snd_strerror(err)); - } else { - dev = -1; - while (doContinue) { - if (snd_ctl_pcm_next_device(handle, &dev) < 0) { - ERROR0("snd_ctl_pcm_next_device\n"); - } - if (dev < 0) { - break; - } - snd_pcm_info_set_device(pcminfo, dev); - snd_pcm_info_set_subdevice(pcminfo, 0); - snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); - err = snd_ctl_pcm_info(handle, pcminfo); - if (err == -ENOENT) { - // try with the other direction - snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); - err = snd_ctl_pcm_info(handle, pcminfo); - } - if (err < 0) { - if (err != -ENOENT) { - ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s", - card, snd_strerror(err)); - } - } else { - subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ? - snd_pcm_info_get_subdevices_count(pcminfo) : 1; - if (iterator!=NULL) { - for (subDev = 0; subDev < subdeviceCount; subDev++) { - deviceID = encodeDeviceID(card, dev, subDev); - doContinue = (*iterator)(deviceID, pcminfo, - cardinfo, userData); - count++; - if (!doContinue) { - break; - } - } - } else { - count += subdeviceCount; - } - } - } // of while(doContinue) - } - snd_ctl_close(handle); - } - } - snd_ctl_card_info_free(cardinfo); - snd_pcm_info_free(pcminfo); - return count; -} - -int getAudioDeviceCount() { - initAlsaSupport(); - return iteratePCMDevices(NULL, NULL); -} - -int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo, - snd_ctl_card_info_t* cardinfo, void* userData) { - char buffer[300]; - ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData; -#ifdef ALSA_PCM_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - initAlsaSupport(); - if (desc->index == 0) { - // we found the device with correct index - *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ? - 1 : snd_pcm_info_get_subdevices_count(pcminfo); - *desc->deviceID = deviceID; - buffer[0]=' '; buffer[1]='['; - // buffer[300] is enough to store the actual device string w/o overrun - getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM); - strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); - strncpy(desc->name, - (cardinfo != NULL) - ? snd_ctl_card_info_get_id(cardinfo) - : snd_pcm_info_get_id(pcminfo), - desc->strLen - strlen(buffer)); - strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); - strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen); - strncpy(desc->description, - (cardinfo != NULL) - ? snd_ctl_card_info_get_name(cardinfo) - : snd_pcm_info_get_name(pcminfo), - desc->strLen); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description)); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description)); - getALSAVersion(desc->version, desc->strLen); - TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version); - return FALSE; // do not continue iteration - } - desc->index--; - return TRUE; -} - -// returns 0 if successful -int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) { - char buffer[200]; - int ret; - - initAlsaSupport(); - getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM); - - TRACE1("Opening ALSA device %s\n", buffer); - ret = snd_pcm_open(handle, buffer, - isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK); - if (ret != 0) { - ERROR1("snd_pcm_open returned error code %d \n", ret); - *handle = NULL; - } - return ret; -} - - -int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) { - initAlsaSupport(); - TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index); - iteratePCMDevices(&deviceInfoIterator, desc); - return (desc->index == 0)?TRUE:FALSE; -} - -// returns 1 if successful -// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) -int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, - int* sampleSizeInBytes, int* significantBits, - int* isSigned, int* isBigEndian, int* enc) { - - *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8; - *significantBits = snd_pcm_format_width(alsaFormat); - - // defaults - *enc = 0; // PCM - *isSigned = (snd_pcm_format_signed(alsaFormat) > 0); - *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0); - - // non-PCM formats - if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law - *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes; - } - else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law - *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes; - } - else if (snd_pcm_format_linear(alsaFormat) < 1) { - return 0; - } - return (*sampleSizeInBytes > 0); -} - -// returns 1 if successful -int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, - int sampleSizeInBytes, int significantBits, - int isSigned, int isBigEndian, int enc) { - *alsaFormat = SND_PCM_FORMAT_UNKNOWN; - - if (enc == 0) { - *alsaFormat = snd_pcm_build_linear_format(significantBits, - sampleSizeInBytes * 8, - isSigned?0:1, - isBigEndian?1:0); - } - else if ((sampleSizeInBytes == 1) && (significantBits == 8)) { - if (enc == 1) { // ULAW - *alsaFormat = SND_PCM_FORMAT_MU_LAW; - } - else if (enc == 2) { // ALAW - *alsaFormat = SND_PCM_FORMAT_A_LAW; - } - } - return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1; -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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 this with a later version of ALSA than 0.9.0rc3 -// (starting from 1.0.0 it became default behaviour) -#define ALSA_PCM_NEW_HW_PARAMS_API -#include -#include "Utilities.h" - -#ifndef PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED -#define PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED - -// if this is defined, use plughw: devices -#define ALSA_PCM_USE_PLUGHW -//#undef ALSA_PCM_USE_PLUGHW - - -// maximum number of channels that is listed in the formats. If more, than -// just -1 for channel count is used. -#define MAXIMUM_LISTED_CHANNELS 32 - -typedef struct tag_ALSA_AudioDeviceDescription { - int index; // in - int strLen; // in - INT32* deviceID; // out - int* maxSimultaneousLines; // out - char* name; // out - char* vendor; // out - char* description; // out - char* version; // out -} ALSA_AudioDeviceDescription; - - - -int getAudioDeviceCount(); -int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc); - -// returns ALSA error code, or 0 if successful -int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware); - -// returns 1 if successful -// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) -int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, - int* sampleSizeInBytes, int* significantBits, - int* isSigned, int* isBigEndian, int* enc); - -int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, - int sampleSizeInBytes, int significantBits, - int isSigned, int isBigEndian, int enc); - -#endif // PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +0,0 @@ -/* - * Copyright (c) 2003, 2016, 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 "Ports.h" -#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h" -#include - -#if USE_PORTS == TRUE - -#define MAX_ELEMS (300) -#define MAX_CONTROLS (MAX_ELEMS * 4) - -#define CHANNELS_MONO (SND_MIXER_SCHN_LAST + 1) -#define CHANNELS_STEREO (SND_MIXER_SCHN_LAST + 2) - -typedef struct { - snd_mixer_elem_t* elem; - INT32 portType; /* one of PORT_XXX_xx */ - char* controlType; /* one of CONTROL_TYPE_xx */ - /* Values: either SND_MIXER_SCHN_FRONT_xx, CHANNELS_MONO or CHANNELS_STEREO. - For SND_MIXER_SCHN_FRONT_xx, exactly this channel is set/retrieved directly. - For CHANNELS_MONO, ALSA channel SND_MIXER_SCHN_MONO is set/retrieved directly. - For CHANNELS_STEREO, ALSA channels SND_MIXER_SCHN_FRONT_LEFT and SND_MIXER_SCHN_FRONT_RIGHT - are set after a calculation that takes balance into account. Retrieved? Average of both - channels? (Using a cached value is not a good idea since the value in the HW may have been - altered.) */ - INT32 channel; -} PortControl; - - -typedef struct tag_PortMixer { - snd_mixer_t* mixer_handle; - /* Number of array elements used in elems and types. */ - int numElems; - snd_mixer_elem_t** elems; - /* Array of port types (PORT_SRC_UNKNOWN etc.). Indices are the same as in elems. */ - INT32* types; - /* Number of array elements used in controls. */ - int numControls; - PortControl* controls; -} PortMixer; - - -///// implemented functions of Ports.h - -INT32 PORT_GetPortMixerCount() { - INT32 mixerCount; - int card; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_ctl_card_info_t* info; - - TRACE0("> PORT_GetPortMixerCount\n"); - - initAlsaSupport(); - - snd_ctl_card_info_malloc(&info); - card = -1; - mixerCount = 0; - if (snd_card_next(&card) >= 0) { - while (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("PORT_GetPortMixerCount: Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, 0); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); - } else { - mixerCount++; - snd_ctl_close(handle); - } - if (snd_card_next(&card) < 0) { - break; - } - } - } - snd_ctl_card_info_free(info); - TRACE0("< PORT_GetPortMixerCount\n"); - return mixerCount; -} - - -INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { - snd_ctl_t* handle; - snd_ctl_card_info_t* card_info; - char devname[16]; - int err; - char buffer[100]; - - TRACE0("> PORT_GetPortMixerDescription\n"); - snd_ctl_card_info_malloc(&card_info); - - sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); - TRACE1("Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, 0); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); - return FALSE; - } - err = snd_ctl_card_info(handle, card_info); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); - } - strncpy(description->name, snd_ctl_card_info_get_id(card_info), PORT_STRING_LENGTH - 1); - sprintf(buffer, " [%s]", devname); - strncat(description->name, buffer, PORT_STRING_LENGTH - 1 - strlen(description->name)); - strncpy(description->vendor, "ALSA (http://www.alsa-project.org)", PORT_STRING_LENGTH - 1); - strncpy(description->description, snd_ctl_card_info_get_name(card_info), PORT_STRING_LENGTH - 1); - strncat(description->description, ", ", PORT_STRING_LENGTH - 1 - strlen(description->description)); - strncat(description->description, snd_ctl_card_info_get_mixername(card_info), PORT_STRING_LENGTH - 1 - strlen(description->description)); - getALSAVersion(description->version, PORT_STRING_LENGTH - 1); - - snd_ctl_close(handle); - snd_ctl_card_info_free(card_info); - TRACE0("< PORT_GetPortMixerDescription\n"); - return TRUE; -} - - -void* PORT_Open(INT32 mixerIndex) { - char devname[16]; - snd_mixer_t* mixer_handle; - int err; - PortMixer* handle; - - TRACE0("> PORT_Open\n"); - sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); - if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) { - ERROR2("Mixer %s open error: %s", devname, snd_strerror(err)); - return NULL; - } - if ((err = snd_mixer_attach(mixer_handle, devname)) < 0) { - ERROR2("Mixer attach %s error: %s", devname, snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0) { - ERROR1("Mixer register error: %s", snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - err = snd_mixer_load(mixer_handle); - if (err < 0) { - ERROR2("Mixer %s load error: %s", devname, snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - handle = (PortMixer*) calloc(1, sizeof(PortMixer)); - if (handle == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - return NULL; - } - handle->numElems = 0; - handle->elems = (snd_mixer_elem_t**) calloc(MAX_ELEMS, sizeof(snd_mixer_elem_t*)); - if (handle->elems == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle); - return NULL; - } - handle->types = (INT32*) calloc(MAX_ELEMS, sizeof(INT32)); - if (handle->types == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle->elems); - free(handle); - return NULL; - } - handle->controls = (PortControl*) calloc(MAX_CONTROLS, sizeof(PortControl)); - if (handle->controls == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle->elems); - free(handle->types); - free(handle); - return NULL; - } - handle->mixer_handle = mixer_handle; - // necessary to initialize data structures - PORT_GetPortCount(handle); - TRACE0("< PORT_Open\n"); - return handle; -} - - -void PORT_Close(void* id) { - TRACE0("> PORT_Close\n"); - if (id != NULL) { - PortMixer* handle = (PortMixer*) id; - if (handle->mixer_handle != NULL) { - snd_mixer_close(handle->mixer_handle); - } - if (handle->elems != NULL) { - free(handle->elems); - } - if (handle->types != NULL) { - free(handle->types); - } - if (handle->controls != NULL) { - free(handle->controls); - } - free(handle); - } - TRACE0("< PORT_Close\n"); -} - - - -INT32 PORT_GetPortCount(void* id) { - PortMixer* portMixer; - snd_mixer_elem_t *elem; - - TRACE0("> PORT_GetPortCount\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portMixer->numElems == 0) { - for (elem = snd_mixer_first_elem(portMixer->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { - if (!snd_mixer_selem_is_active(elem)) - continue; - TRACE2("Simple mixer control '%s',%i\n", - snd_mixer_selem_get_name(elem), - snd_mixer_selem_get_index(elem)); - if (snd_mixer_selem_has_playback_volume(elem)) { - portMixer->elems[portMixer->numElems] = elem; - portMixer->types[portMixer->numElems] = PORT_DST_UNKNOWN; - portMixer->numElems++; - } - // to prevent buffer overflow - if (portMixer->numElems >= MAX_ELEMS) { - break; - } - /* If an element has both playback an capture volume, it is put into the arrays - twice. */ - if (snd_mixer_selem_has_capture_volume(elem)) { - portMixer->elems[portMixer->numElems] = elem; - portMixer->types[portMixer->numElems] = PORT_SRC_UNKNOWN; - portMixer->numElems++; - } - // to prevent buffer overflow - if (portMixer->numElems >= MAX_ELEMS) { - break; - } - } - } - TRACE0("< PORT_GetPortCount\n"); - return portMixer->numElems; -} - - -INT32 PORT_GetPortType(void* id, INT32 portIndex) { - PortMixer* portMixer; - INT32 type; - TRACE0("> PORT_GetPortType\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - // $$mp: Should become a descriptive error code (index out of bounds). - return -1; - } - type = portMixer->types[portIndex]; - TRACE0("< PORT_GetPortType\n"); - return type; -} - - -INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { - PortMixer* portMixer; - const char* nam; - - TRACE0("> PORT_GetPortName\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - // $$mp: Should become a descriptive error code (index out of bounds). - return -1; - } - nam = snd_mixer_selem_get_name(portMixer->elems[portIndex]); - strncpy(name, nam, len - 1); - name[len - 1] = 0; - TRACE0("< PORT_GetPortName\n"); - return TRUE; -} - - -static int isPlaybackFunction(INT32 portType) { - return (portType & PORT_DST_MASK); -} - - -/* Sets portControl to a pointer to the next free array element in the PortControl (pointer) - array of the passed portMixer. Returns TRUE if successful. May return FALSE if there is no - free slot. In this case, portControl is not altered */ -static int getControlSlot(PortMixer* portMixer, PortControl** portControl) { - if (portMixer->numControls >= MAX_CONTROLS) { - return FALSE; - } else { - *portControl = &(portMixer->controls[portMixer->numControls]); - portMixer->numControls++; - return TRUE; - } -} - - -/* Protect against illegal min-max values, preventing divisions by zero. - */ -inline static long getRange(long min, long max) { - if (max > min) { - return max - min; - } else { - return 1; - } -} - - -/* Idea: we may specify that if unit is an empty string, the values are linear and if unit is "dB", - the values are logarithmic. -*/ -static void* createVolumeControl(PortControlCreator* creator, - PortControl* portControl, - snd_mixer_elem_t* elem, int isPlayback) { - void* control; - float precision; - long min, max; - - if (isPlayback) { - snd_mixer_selem_get_playback_volume_range(elem, &min, &max); - } else { - snd_mixer_selem_get_capture_volume_range(elem, &min, &max); - } - /* $$mp: The volume values retrieved with the ALSA API are strongly supposed to be logarithmic. - So the following calculation is wrong. However, there is no correct calculation, since - for equal-distant logarithmic steps, the precision expressed in linear varies over the - scale. */ - precision = 1.0F / getRange(min, max); - control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_VOLUME, 0.0F, +1.0F, precision, ""); - return control; -} - - -void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { - PortMixer* portMixer; - snd_mixer_elem_t* elem; - void* control; - PortControl* portControl; - void* controls[10]; - int numControls; - char* portName; - int isPlayback = 0; - int isMono; - int isStereo; - char* type; - snd_mixer_selem_channel_id_t channel; - memset(controls, 0, sizeof(controls)); - - TRACE0("> PORT_GetControls\n"); - if (id == NULL) { - ERROR0("Invalid handle!"); - // $$mp: an error code should be returned. - return; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - ERROR0("Port index out of range!"); - // $$mp: an error code should be returned. - return; - } - numControls = 0; - elem = portMixer->elems[portIndex]; - if (snd_mixer_selem_has_playback_volume(elem) || snd_mixer_selem_has_capture_volume(elem)) { - /* Since we've split/duplicated elements with both playback and capture on the recovery - of elements, we now can assume that we handle only to deal with either playback or - capture. */ - isPlayback = isPlaybackFunction(portMixer->types[portIndex]); - isMono = (isPlayback && snd_mixer_selem_is_playback_mono(elem)) || - (!isPlayback && snd_mixer_selem_is_capture_mono(elem)); - isStereo = (isPlayback && - snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && - snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)) || - (!isPlayback && - snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && - snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)); - // single volume control - if (isMono || isStereo) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_VOLUME; - if (isMono) { - portControl->channel = CHANNELS_MONO; - } else { - portControl->channel = CHANNELS_STEREO; - } - control = createVolumeControl(creator, portControl, elem, isPlayback); - if (control != NULL) { - controls[numControls++] = control; - } - } - } else { // more than two channels, each channels has its own control. - for (channel = SND_MIXER_SCHN_FRONT_LEFT; channel <= SND_MIXER_SCHN_LAST; channel++) { - if (isPlayback && snd_mixer_selem_has_playback_channel(elem, channel) || - !isPlayback && snd_mixer_selem_has_capture_channel(elem, channel)) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_VOLUME; - portControl->channel = channel; - control = createVolumeControl(creator, portControl, elem, isPlayback); - // We wrap in a compound control to provide the channel name. - if (control != NULL) { - /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the - declaration of PORT_NewCompoundControlPtr in Ports.h should be changed - to take a const char* parameter. */ - control = (creator->newCompoundControl)(creator, (char*) snd_mixer_selem_channel_name(channel), &control, 1); - } - if (control != NULL) { - controls[numControls++] = control; - } - } - } - } - } - // BALANCE control - if (isStereo) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_BALANCE; - portControl->channel = CHANNELS_STEREO; - /* $$mp: The value for precision is chosen more or less arbitrarily. */ - control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_BALANCE, -1.0F, 1.0F, 0.01F, ""); - if (control != NULL) { - controls[numControls++] = control; - } - } - } - } - if (snd_mixer_selem_has_playback_switch(elem) || snd_mixer_selem_has_capture_switch(elem)) { - if (getControlSlot(portMixer, &portControl)) { - type = isPlayback ? CONTROL_TYPE_MUTE : CONTROL_TYPE_SELECT; - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = type; - control = (creator->newBooleanControl)(creator, portControl, type); - if (control != NULL) { - controls[numControls++] = control; - } - } - } - /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the - declaration of PORT_NewCompoundControlPtr in Ports.h should be changed - to take a const char* parameter. */ - portName = (char*) snd_mixer_selem_get_name(elem); - control = (creator->newCompoundControl)(creator, portName, controls, numControls); - if (control != NULL) { - (creator->addControl)(creator, control); - } - TRACE0("< PORT_GetControls\n"); -} - - -INT32 PORT_GetIntValue(void* controlIDV) { - PortControl* portControl = (PortControl*) controlIDV; - int value = 0; - snd_mixer_selem_channel_id_t channel; - - if (portControl != NULL) { - switch (portControl->channel) { - case CHANNELS_MONO: - channel = SND_MIXER_SCHN_MONO; - break; - - case CHANNELS_STEREO: - channel = SND_MIXER_SCHN_FRONT_LEFT; - break; - - default: - channel = portControl->channel; - } - if (portControl->controlType == CONTROL_TYPE_MUTE || - portControl->controlType == CONTROL_TYPE_SELECT) { - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_switch(portControl->elem, channel, &value); - } else { - snd_mixer_selem_get_capture_switch(portControl->elem, channel, &value); - } - if (portControl->controlType == CONTROL_TYPE_MUTE) { - value = ! value; - } - } else { - ERROR1("PORT_GetIntValue(): inappropriate control type: %s\n", - portControl->controlType); - } - } - return (INT32) value; -} - - -void PORT_SetIntValue(void* controlIDV, INT32 value) { - PortControl* portControl = (PortControl*) controlIDV; - snd_mixer_selem_channel_id_t channel; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_MUTE) { - value = ! value; - } - if (portControl->controlType == CONTROL_TYPE_MUTE || - portControl->controlType == CONTROL_TYPE_SELECT) { - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_set_playback_switch_all(portControl->elem, value); - } else { - snd_mixer_selem_set_capture_switch_all(portControl->elem, value); - } - } else { - ERROR1("PORT_SetIntValue(): inappropriate control type: %s\n", - portControl->controlType); - } - } -} - - -static float scaleVolumeValueToNormalized(long value, long min, long max) { - return (float) (value - min) / getRange(min, max); -} - - -static long scaleVolumeValueToHardware(float value, long min, long max) { - return (long)(value * getRange(min, max) + min); -} - - -float getRealVolume(PortControl* portControl, - snd_mixer_selem_channel_id_t channel) { - float fValue; - long lValue = 0; - long min = 0; - long max = 0; - - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_volume_range(portControl->elem, - &min, &max); - snd_mixer_selem_get_playback_volume(portControl->elem, - channel, &lValue); - } else { - snd_mixer_selem_get_capture_volume_range(portControl->elem, - &min, &max); - snd_mixer_selem_get_capture_volume(portControl->elem, - channel, &lValue); - } - fValue = scaleVolumeValueToNormalized(lValue, min, max); - return fValue; -} - - -void setRealVolume(PortControl* portControl, - snd_mixer_selem_channel_id_t channel, float value) { - long lValue = 0; - long min = 0; - long max = 0; - - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_volume_range(portControl->elem, - &min, &max); - lValue = scaleVolumeValueToHardware(value, min, max); - snd_mixer_selem_set_playback_volume(portControl->elem, - channel, lValue); - } else { - snd_mixer_selem_get_capture_volume_range(portControl->elem, - &min, &max); - lValue = scaleVolumeValueToHardware(value, min, max); - snd_mixer_selem_set_capture_volume(portControl->elem, - channel, lValue); - } -} - - -static float getFakeBalance(PortControl* portControl) { - float volL, volR; - - // pan is the ratio of left and right - volL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); - volR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); - if (volL > volR) { - return -1.0f + (volR / volL); - } - else if (volR > volL) { - return 1.0f - (volL / volR); - } - return 0.0f; -} - - -static float getFakeVolume(PortControl* portControl) { - float valueL; - float valueR; - float value; - - valueL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); - valueR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); - // volume is the greater value of both - value = valueL > valueR ? valueL : valueR ; - return value; -} - - -/* - * sets the unsigned values for left and right volume according to - * the given volume (0...1) and balance (-1..0..+1) - */ -static void setFakeVolume(PortControl* portControl, float vol, float bal) { - float volumeLeft; - float volumeRight; - - if (bal < 0.0f) { - volumeLeft = vol; - volumeRight = vol * (bal + 1.0f); - } else { - volumeLeft = vol * (1.0f - bal); - volumeRight = vol; - } - setRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT, volumeLeft); - setRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT, volumeRight); -} - - -float PORT_GetFloatValue(void* controlIDV) { - PortControl* portControl = (PortControl*) controlIDV; - float value = 0.0F; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_VOLUME) { - switch (portControl->channel) { - case CHANNELS_MONO: - value = getRealVolume(portControl, SND_MIXER_SCHN_MONO); - break; - - case CHANNELS_STEREO: - value = getFakeVolume(portControl); - break; - - default: - value = getRealVolume(portControl, portControl->channel); - } - } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { - if (portControl->channel == CHANNELS_STEREO) { - value = getFakeBalance(portControl); - } else { - ERROR0("PORT_GetFloatValue(): Balance only allowed for stereo channels!\n"); - } - } else { - ERROR1("PORT_GetFloatValue(): inappropriate control type: %s!\n", - portControl->controlType); - } - } - return value; -} - - -void PORT_SetFloatValue(void* controlIDV, float value) { - PortControl* portControl = (PortControl*) controlIDV; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_VOLUME) { - switch (portControl->channel) { - case CHANNELS_MONO: - setRealVolume(portControl, SND_MIXER_SCHN_MONO, value); - break; - - case CHANNELS_STEREO: - setFakeVolume(portControl, value, getFakeBalance(portControl)); - break; - - default: - setRealVolume(portControl, portControl->channel, value); - } - } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { - if (portControl->channel == CHANNELS_STEREO) { - setFakeVolume(portControl, getFakeVolume(portControl), value); - } else { - ERROR0("PORT_SetFloatValue(): Balance only allowed for stereo channels!\n"); - } - } else { - ERROR1("PORT_SetFloatValue(): inappropriate control type: %s!\n", - portControl->controlType); - } - } -} - - -#endif // USE_PORTS diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2003, 2015, 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_LinuxOS_ALSA_CommonUtils.h" - -static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) { -#ifdef USE_ERROR - va_list args; - va_start(args, fmt); - printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err)); - if (strlen(fmt) > 0) { - vprintf(fmt, args); - } - va_end(args); -#endif -} - -static int alsa_inited = 0; -static int alsa_enumerate_pcm_subdevices = FALSE; // default: no -static int alsa_enumerate_midi_subdevices = FALSE; // default: no - -/* - * Declare library specific JNI_Onload entry if static build - */ -DEF_STATIC_JNI_OnLoad - -void initAlsaSupport() { - char* enumerate; - if (!alsa_inited) { - alsa_inited = TRUE; - snd_lib_error_set_handler(&alsaDebugOutput); - - enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES); - if (enumerate != NULL && strlen(enumerate) > 0 - && (enumerate[0] != 'f') // false - && (enumerate[0] != 'F') // False - && (enumerate[0] != 'n') // no - && (enumerate[0] != 'N')) { // NO - alsa_enumerate_pcm_subdevices = TRUE; - } -#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES - alsa_enumerate_midi_subdevices = TRUE; -#endif - } -} - - -/* if true (non-zero), ALSA sub devices should be listed as separate devices - */ -int needEnumerateSubdevices(int isMidi) { - initAlsaSupport(); - return isMidi ? alsa_enumerate_midi_subdevices - : alsa_enumerate_pcm_subdevices; -} - - -/* - * deviceID contains packed card, device and subdevice numbers - * each number takes 10 bits - * "default" device has id == ALSA_DEFAULT_DEVICE_ID - */ -UINT32 encodeDeviceID(int card, int device, int subdevice) { - return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10) - | (subdevice & 0x3FF)) + 1; -} - - -void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, - int isMidi) { - deviceID--; - *card = (deviceID >> 20) & 0x3FF; - *device = (deviceID >> 10) & 0x3FF; - if (needEnumerateSubdevices(isMidi)) { - *subdevice = deviceID & 0x3FF; - } else { - *subdevice = -1; // ALSA will choose any subdevices - } -} - - -void getDeviceString(char* buffer, int card, int device, int subdevice, - int usePlugHw, int isMidi) { - if (needEnumerateSubdevices(isMidi)) { - sprintf(buffer, "%s:%d,%d,%d", - usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, - card, device, subdevice); - } else { - sprintf(buffer, "%s:%d,%d", - usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE, - card, device); - } -} - - -void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, - int usePlugHw, int isMidi) { - int card, device, subdevice; - - if (deviceID == ALSA_DEFAULT_DEVICE_ID) { - strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME); - } else { - decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi); - getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi); - } -} - - -static int hasGottenALSAVersion = FALSE; -#define ALSAVersionString_LENGTH 200 -static char ALSAVersionString[ALSAVersionString_LENGTH]; - -void getALSAVersion(char* buffer, int len) { - if (!hasGottenALSAVersion) { - // get alsa version from proc interface - FILE* file; - int curr, len, totalLen, inVersionString; - file = fopen(ALSA_VERSION_PROC_FILE, "r"); - ALSAVersionString[0] = 0; - if (file) { - if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) { - // parse for version number - totalLen = strlen(ALSAVersionString); - inVersionString = FALSE; - len = 0; - curr = 0; - while (curr < totalLen) { - if (!inVersionString) { - // is this char the beginning of a version string ? - if (ALSAVersionString[curr] >= '0' - && ALSAVersionString[curr] <= '9') { - inVersionString = TRUE; - } - } - if (inVersionString) { - // the version string ends with white space - if (ALSAVersionString[curr] <= 32) { - break; - } - if (curr != len) { - // copy this char to the beginning of the string - ALSAVersionString[len] = ALSAVersionString[curr]; - } - len++; - } - curr++; - } - // remove trailing dots - while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { - len--; - } - // null terminate - ALSAVersionString[len] = 0; - } - fclose(file); - hasGottenALSAVersion = TRUE; - } - } - strncpy(buffer, ALSAVersionString, len); -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -#include -#include "Utilities.h" - -#ifndef PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED -#define PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED - -#define ALSA_VERSION_PROC_FILE "/proc/asound/version" -#define ALSA_HARDWARE "hw" -#define ALSA_HARDWARE_CARD ALSA_HARDWARE":%d" -#define ALSA_HARDWARE_DEVICE ALSA_HARDWARE_CARD",%d" -#define ALSA_HARDWARE_SUBDEVICE ALSA_HARDWARE_DEVICE",%d" - -#define ALSA_PLUGHARDWARE "plughw" -#define ALSA_DEFAULT_DEVICE_NAME "default" - -#define ALSA_DEFAULT_DEVICE_ID (0) - -#define ALSA_PCM (0) -#define ALSA_RAWMIDI (1) - -// for use in info objects -#define ALSA_VENDOR "ALSA (http://www.alsa-project.org)" - -// Environment variable for inclusion of subdevices in device listing. -// If this variable is unset or "no", then subdevices are ignored, and -// it's ALSA's choice which one to use (enables hardware mixing) -#define ENV_ENUMERATE_PCM_SUBDEVICES "ALSA_ENUMERATE_PCM_SUBDEVICES" - -// if defined, subdevices are listed. -//#undef ALSA_MIDI_ENUMERATE_SUBDEVICES -#define ALSA_MIDI_ENUMERATE_SUBDEVICES - -// must be called before any ALSA calls -void initAlsaSupport(); - -/* if true (non-zero), ALSA sub devices should be listed as separate devices - */ -int needEnumerateSubdevices(int isMidi); - - -/* - * deviceID contains packed card, device and subdevice numbers - * each number takes 10 bits - * "default" device has id == ALSA_DEFAULT_DEVICE_ID - */ -UINT32 encodeDeviceID(int card, int device, int subdevice); - -void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice, - int isMidi); - -void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID, - int usePlugHw, int isMidi); - -void getALSAVersion(char* buffer, int len); - - -#endif // PLATFORM_API_LINUXOS_ALSA_COMMONUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2003, 2010, 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 - -#if USE_PLATFORM_MIDI_IN == TRUE - - -#include -#include "PlatformMidi.h" -#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" -#if defined(i586) -#include -#endif - -/* - * Helper methods - */ - -static inline UINT32 packMessage(int status, int data1, int data2) { - return ((status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16)); -} - - -static void setShortMessage(MidiMessage* message, - int status, int data1, int data2) { - message->type = SHORT_MESSAGE; - message->data.s.packedMsg = packMessage(status, data1, data2); -} - - -static void setRealtimeMessage(MidiMessage* message, int status) { - setShortMessage(message, status, 0, 0); -} - - -static void set14bitMessage(MidiMessage* message, int status, int value) { - TRACE3("14bit value: %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); - value &= 0x3FFF; - TRACE3("14bit value (2): %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F); - setShortMessage(message, status, - value & 0x7F, - (value >> 7) & 0x7F); -} - - -/* - * implementation of the platform-dependent - * MIDI in functions declared in PlatformMidi.h - */ - -char* MIDI_IN_GetErrorStr(INT32 err) { - return (char*) getErrorStr(err); -} - -INT32 MIDI_IN_GetNumDevices() { -/* Workaround for 6842956: 32bit app on 64bit linux - * gets assertion failure trying to open midiIn ports. - * Untill the issue is fixed in ALSA - * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807) - * report no midi in devices in the configuration. - */ -#if defined(i586) - static int jre32onlinux64 = -1; - if (jre32onlinux64 < 0) { - jre32onlinux64 = 0; - /* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN" - * environment variable. - */ - if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) { - struct utsname u; - jre32onlinux64 = 0; - if (uname(&u) == 0) { - if (strstr(u.machine, "64") != NULL) { - TRACE0("jre32 on linux64 detected - report no midiIn devices\n"); - jre32onlinux64 = 1; - } - } - } - } - if (jre32onlinux64) { - return 0; - } -#endif - - TRACE0("MIDI_IN_GetNumDevices()\n"); - - return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT); -} - - -INT32 MIDI_IN_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceName(SND_RAWMIDI_STREAM_INPUT, deviceIndex, - name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceVendor(deviceIndex, name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceDescription(SND_RAWMIDI_STREAM_INPUT, deviceIndex, - name, nameLength); - return ret; -} - - -INT32 MIDI_IN_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { - int ret = getMidiDeviceVersion(deviceIndex, name, nameLength); - return ret; -} - -/*************************************************************************/ - -INT32 MIDI_IN_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { - INT32 ret; - TRACE0("> MIDI_IN_OpenDevice\n"); - ret = openMidiDevice(SND_RAWMIDI_STREAM_INPUT, deviceIndex, handle); - TRACE1("< MIDI_IN_OpenDevice: returning %d\n", (int) ret); - return ret; -} - - -INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) { - INT32 ret; - TRACE0("> MIDI_IN_CloseDevice\n"); - ret = closeMidiDevice(handle); - TRACE1("< MIDI_IN_CloseDevice: returning %d\n", (int) ret); - return ret; -} - - -INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_IN_StartDevice\n"); - return MIDI_SUCCESS; -} - - -INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_IN_StopDevice\n"); - return MIDI_SUCCESS; -} - - -INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) { - return getMidiTimestamp(handle); -} - - -/* read the next message from the queue */ -MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) { - snd_seq_event_t alsa_message; - MidiMessage* jdk_message; - int err; - char buffer[1]; - int status; - - TRACE0("> MIDI_IN_GetMessage\n"); - if (!handle) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): handle is NULL\n"); - return NULL; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): native handle is NULL\n"); - return NULL; - } - if (!handle->platformData) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): platformData is NULL\n"); - return NULL; - } - - /* For MIDI In, the device is left in non blocking mode. So if there is - no data from the device, snd_rawmidi_read() returns with -11 (EAGAIN). - This results in jumping back to the Java layer. */ - while (TRUE) { - TRACE0("before snd_rawmidi_read()\n"); - err = snd_rawmidi_read((snd_rawmidi_t*) handle->deviceHandle, buffer, 1); - TRACE0("after snd_rawmidi_read()\n"); - if (err != 1) { - ERROR2("< ERROR: MIDI_IN_GetMessage(): snd_rawmidi_read() returned %d : %s\n", err, snd_strerror(err)); - return NULL; - } - // printf("received byte: %d\n", buffer[0]); - err = snd_midi_event_encode_byte((snd_midi_event_t*) handle->platformData, - (int) buffer[0], - &alsa_message); - if (err == 1) { - break; - } else if (err < 0) { - ERROR1("< ERROR: MIDI_IN_GetMessage(): snd_midi_event_encode_byte() returned %d\n", err); - return NULL; - } - } - jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1); - if (!jdk_message) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); - return NULL; - } - // TODO: tra - switch (alsa_message.type) { - case SND_SEQ_EVENT_NOTEON: - case SND_SEQ_EVENT_NOTEOFF: - case SND_SEQ_EVENT_KEYPRESS: - status = (alsa_message.type == SND_SEQ_EVENT_KEYPRESS) ? 0xA0 : - (alsa_message.type == SND_SEQ_EVENT_NOTEON) ? 0x90 : 0x80; - status |= alsa_message.data.note.channel; - setShortMessage(jdk_message, status, - alsa_message.data.note.note, - alsa_message.data.note.velocity); - break; - - case SND_SEQ_EVENT_CONTROLLER: - status = 0xB0 | alsa_message.data.control.channel; - setShortMessage(jdk_message, status, - alsa_message.data.control.param, - alsa_message.data.control.value); - break; - - case SND_SEQ_EVENT_PGMCHANGE: - case SND_SEQ_EVENT_CHANPRESS: - status = (alsa_message.type == SND_SEQ_EVENT_PGMCHANGE) ? 0xC0 : 0xD0; - status |= alsa_message.data.control.channel; - setShortMessage(jdk_message, status, - alsa_message.data.control.value, 0); - break; - - case SND_SEQ_EVENT_PITCHBEND: - status = 0xE0 | alsa_message.data.control.channel; - // $$mp 2003-09-23: - // possible hack to work around a bug in ALSA. Necessary for - // ALSA 0.9.2. May be fixed in newer versions of ALSA. - // alsa_message.data.control.value ^= 0x2000; - // TRACE1("pitchbend value: %d\n", alsa_message.data.control.value); - set14bitMessage(jdk_message, status, - alsa_message.data.control.value); - break; - - /* System exclusive messages */ - - case SND_SEQ_EVENT_SYSEX: - jdk_message->type = LONG_MESSAGE; - jdk_message->data.l.size = alsa_message.data.ext.len; - jdk_message->data.l.data = malloc(alsa_message.data.ext.len); - if (jdk_message->data.l.data == NULL) { - ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n"); - free(jdk_message); - jdk_message = NULL; - } else { - memcpy(jdk_message->data.l.data, alsa_message.data.ext.ptr, alsa_message.data.ext.len); - } - break; - - /* System common messages */ - - case SND_SEQ_EVENT_QFRAME: - setShortMessage(jdk_message, 0xF1, - alsa_message.data.control.value & 0x7F, 0); - break; - - case SND_SEQ_EVENT_SONGPOS: - set14bitMessage(jdk_message, 0xF2, - alsa_message.data.control.value); - break; - - case SND_SEQ_EVENT_SONGSEL: - setShortMessage(jdk_message, 0xF3, - alsa_message.data.control.value & 0x7F, 0); - break; - - case SND_SEQ_EVENT_TUNE_REQUEST: - setRealtimeMessage(jdk_message, 0xF6); - break; - - /* System realtime messages */ - - case SND_SEQ_EVENT_CLOCK: - setRealtimeMessage(jdk_message, 0xF8); - break; - - case SND_SEQ_EVENT_START: - setRealtimeMessage(jdk_message, 0xFA); - break; - - case SND_SEQ_EVENT_CONTINUE: - setRealtimeMessage(jdk_message, 0xFB); - break; - - case SND_SEQ_EVENT_STOP: - setRealtimeMessage(jdk_message, 0xFC); - break; - - case SND_SEQ_EVENT_SENSING: - setRealtimeMessage(jdk_message, 0xFE); - break; - - case SND_SEQ_EVENT_RESET: - setRealtimeMessage(jdk_message, 0xFF); - break; - - default: - ERROR0("< ERROR: MIDI_IN_GetMessage(): unhandled ALSA MIDI message type\n"); - free(jdk_message); - jdk_message = NULL; - - } - - // set timestamp - if (jdk_message != NULL) { - jdk_message->timestamp = getMidiTimestamp(handle); - } - TRACE1("< MIDI_IN_GetMessage: returning %p\n", jdk_message); - return jdk_message; -} - - -void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) { - if (!msg) { - ERROR0("< ERROR: MIDI_IN_ReleaseMessage(): message is NULL\n"); - return; - } - if (msg->type == LONG_MESSAGE && msg->data.l.data) { - free(msg->data.l.data); - } - free(msg); -} - -#endif /* USE_PLATFORM_MIDI_IN */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2003, 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 - -#if USE_PLATFORM_MIDI_OUT == TRUE - -#include -#include "PlatformMidi.h" -#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" - - - -static int CHANNEL_MESSAGE_LENGTH[] = { - -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 3, 3, 2, 2, 3 }; -/* 8x 9x Ax Bx Cx Dx Ex */ - -static int SYSTEM_MESSAGE_LENGTH[] = { - -1, 2, 3, 2, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1 }; -/* F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF */ - - -// the returned length includes the status byte. -// for illegal messages, -1 is returned. -static int getShortMessageLength(int status) { - int dataLength = 0; - if (status < 0xF0) { // channel voice message - dataLength = CHANNEL_MESSAGE_LENGTH[(status >> 4) & 0xF]; - } else { - dataLength = SYSTEM_MESSAGE_LENGTH[status & 0xF]; - } - return dataLength; -} - - -/* - * implementation of the platform-dependent - * MIDI out functions declared in PlatformMidi.h - */ -char* MIDI_OUT_GetErrorStr(INT32 err) { - return (char*) getErrorStr(err); -} - - -INT32 MIDI_OUT_GetNumDevices() { - TRACE0("MIDI_OUT_GetNumDevices()\n"); - return getMidiDeviceCount(SND_RAWMIDI_STREAM_OUTPUT); -} - - -INT32 MIDI_OUT_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceName()\n"); - return getMidiDeviceName(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, - name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceVendor()\n"); - return getMidiDeviceVendor(deviceIndex, name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceDescription()\n"); - return getMidiDeviceDescription(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, - name, nameLength); -} - - -INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) { - TRACE0("MIDI_OUT_GetDeviceVersion()\n"); - return getMidiDeviceVersion(deviceIndex, name, nameLength); -} - - -/* *************************** MidiOutDevice implementation *************** */ - -INT32 MIDI_OUT_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) { - TRACE1("MIDI_OUT_OpenDevice(): deviceIndex: %d\n", (int) deviceIndex); - return openMidiDevice(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, handle); -} - - -INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { - TRACE0("MIDI_OUT_CloseDevice()\n"); - return closeMidiDevice(handle); -} - - -INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { - return getMidiTimestamp(handle); -} - - -INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, - UINT32 timestamp) { - int err; - int status; - int data1; - int data2; - char buffer[3]; - - TRACE2("> MIDI_OUT_SendShortMessage() %x, time: %u\n", packedMsg, (unsigned int) timestamp); - if (!handle) { - ERROR0("< ERROR: MIDI_OUT_SendShortMessage(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - status = (packedMsg & 0xFF); - buffer[0] = (char) status; - buffer[1] = (char) ((packedMsg >> 8) & 0xFF); - buffer[2] = (char) ((packedMsg >> 16) & 0xFF); - TRACE4("status: %d, data1: %d, data2: %d, length: %d\n", (int) buffer[0], (int) buffer[1], (int) buffer[2], getShortMessageLength(status)); - err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, buffer, getShortMessageLength(status)); - if (err < 0) { - ERROR1(" ERROR: MIDI_OUT_SendShortMessage(): snd_rawmidi_write() returned %d\n", err); - } - - TRACE0("< MIDI_OUT_SendShortMessage()\n"); - return err; -} - - -INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, - UINT32 size, UINT32 timestamp) { - int err; - - TRACE2("> MIDI_OUT_SendLongMessage() size %u, time: %u\n", (unsigned int) size, (unsigned int) timestamp); - if (!handle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!data) { - ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): data is NULL\n"); - return MIDI_INVALID_HANDLE; - } - err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, - data, size); - if (err < 0) { - ERROR1(" ERROR: MIDI_OUT_SendLongMessage(): snd_rawmidi_write() returned %d\n", err); - } - - TRACE0("< MIDI_OUT_SendLongMessage()\n"); - return err; -} - - -#endif /* USE_PLATFORM_MIDI_OUT */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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_LinuxOS_ALSA_MidiUtils.h" -#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" -#include -#include - -static INT64 getTimeInMicroseconds() { - struct timeval tv; - - gettimeofday(&tv, NULL); - return (tv.tv_sec * 1000000UL) + tv.tv_usec; -} - - -const char* getErrorStr(INT32 err) { - return snd_strerror((int) err); -} - - - -// callback for iteration through devices -// returns TRUE if iteration should continue -typedef int (*DeviceIteratorPtr)(UINT32 deviceID, - snd_rawmidi_info_t* rawmidi_info, - snd_ctl_card_info_t* cardinfo, - void *userData); - -// for each ALSA device, call iterator. userData is passed to the iterator -// returns total number of iterations -static int iterateRawmidiDevices(snd_rawmidi_stream_t direction, - DeviceIteratorPtr iterator, - void* userData) { - int count = 0; - int subdeviceCount; - int card, dev, subDev; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_rawmidi_t *rawmidi; - snd_rawmidi_info_t *rawmidi_info; - snd_ctl_card_info_t *card_info, *defcardinfo = NULL; - UINT32 deviceID; - int doContinue = TRUE; - - snd_rawmidi_info_malloc(&rawmidi_info); - snd_ctl_card_info_malloc(&card_info); - - // 1st try "default" device - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_rawmidi_open(&rawmidi, NULL, ALSA_DEFAULT_DEVICE_NAME, - SND_RAWMIDI_NONBLOCK); - } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_open(NULL, &rawmidi, ALSA_DEFAULT_DEVICE_NAME, - SND_RAWMIDI_NONBLOCK); - } else { - ERROR0("ERROR: iterateRawmidiDevices(): direction is neither" - " SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); - err = MIDI_INVALID_ARGUMENT; - } - if (err < 0) { - ERROR1("ERROR: snd_rawmidi_open (\"default\"): %s\n", - snd_strerror(err)); - } else { - err = snd_rawmidi_info(rawmidi, rawmidi_info); - - snd_rawmidi_close(rawmidi); - if (err < 0) { - ERROR1("ERROR: snd_rawmidi_info (\"default\"): %s\n", - snd_strerror(err)); - } else { - // try to get card info - card = snd_rawmidi_info_get_card(rawmidi_info); - if (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { - if (snd_ctl_card_info(handle, card_info) >= 0) { - defcardinfo = card_info; - } - snd_ctl_close(handle); - } - } - // call calback function for the device - if (iterator != NULL) { - doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, rawmidi_info, - defcardinfo, userData); - } - count++; - } - } - - // iterate cards - card = -1; - TRACE0("testing for cards...\n"); - if (snd_card_next(&card) >= 0) { - TRACE1("Found card %d\n", card); - while (doContinue && (card >= 0)) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("Opening control for alsa rawmidi device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); - } else { - TRACE0("snd_ctl_open() SUCCESS\n"); - err = snd_ctl_card_info(handle, card_info); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err)); - } else { - TRACE0("snd_ctl_card_info() SUCCESS\n"); - dev = -1; - while (doContinue) { - if (snd_ctl_rawmidi_next_device(handle, &dev) < 0) { - ERROR0("snd_ctl_rawmidi_next_device\n"); - } - TRACE0("snd_ctl_rawmidi_next_device() SUCCESS\n"); - if (dev < 0) { - break; - } - snd_rawmidi_info_set_device(rawmidi_info, dev); - snd_rawmidi_info_set_subdevice(rawmidi_info, 0); - snd_rawmidi_info_set_stream(rawmidi_info, direction); - err = snd_ctl_rawmidi_info(handle, rawmidi_info); - TRACE0("after snd_ctl_rawmidi_info()\n"); - if (err < 0) { - if (err != -ENOENT) { - ERROR2("ERROR: snd_ctl_rawmidi_info, card=%d: %s", card, snd_strerror(err)); - } - } else { - TRACE0("snd_ctl_rawmidi_info() SUCCESS\n"); - subdeviceCount = needEnumerateSubdevices(ALSA_RAWMIDI) - ? snd_rawmidi_info_get_subdevices_count(rawmidi_info) - : 1; - if (iterator!=NULL) { - for (subDev = 0; subDev < subdeviceCount; subDev++) { - TRACE3(" Iterating %d,%d,%d\n", card, dev, subDev); - deviceID = encodeDeviceID(card, dev, subDev); - doContinue = (*iterator)(deviceID, rawmidi_info, - card_info, userData); - count++; - TRACE0("returned from iterator\n"); - if (!doContinue) { - break; - } - } - } else { - count += subdeviceCount; - } - } - } // of while(doContinue) - } - snd_ctl_close(handle); - } - if (snd_card_next(&card) < 0) { - break; - } - } - } else { - ERROR0("No cards found!\n"); - } - snd_ctl_card_info_free(card_info); - snd_rawmidi_info_free(rawmidi_info); - return count; -} - - - -int getMidiDeviceCount(snd_rawmidi_stream_t direction) { - int deviceCount; - TRACE0("> getMidiDeviceCount()\n"); - initAlsaSupport(); - deviceCount = iterateRawmidiDevices(direction, NULL, NULL); - TRACE0("< getMidiDeviceCount()\n"); - return deviceCount; -} - - - -/* - userData is assumed to be a pointer to ALSA_MIDIDeviceDescription. - ALSA_MIDIDeviceDescription->index has to be set to the index of the device - we want to get information of before this method is called the first time via - iterateRawmidiDevices(). On each call of this method, - ALSA_MIDIDeviceDescription->index is decremented. If it is equal to zero, - we have reached the desired device, so action is taken. - So after successful completion of iterateRawmidiDevices(), - ALSA_MIDIDeviceDescription->index is zero. If it isn't, this is an - indication of an error. -*/ -static int deviceInfoIterator(UINT32 deviceID, snd_rawmidi_info_t *rawmidi_info, - snd_ctl_card_info_t *cardinfo, void *userData) { - char buffer[300]; - ALSA_MIDIDeviceDescription* desc = (ALSA_MIDIDeviceDescription*)userData; -#ifdef ALSA_MIDI_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - TRACE0("deviceInfoIterator\n"); - initAlsaSupport(); - if (desc->index == 0) { - // we found the device with correct index - desc->deviceID = deviceID; - - buffer[0]=' '; buffer[1]='['; - // buffer[300] is enough to store the actual device string w/o overrun - getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_RAWMIDI); - strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); - strncpy(desc->name, - (cardinfo != NULL) - ? snd_ctl_card_info_get_id(cardinfo) - : snd_rawmidi_info_get_id(rawmidi_info), - desc->strLen - strlen(buffer)); - strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); - desc->description[0] = 0; - if (cardinfo != NULL) { - strncpy(desc->description, snd_ctl_card_info_get_name(cardinfo), - desc->strLen); - strncat(desc->description, ", ", - desc->strLen - strlen(desc->description)); - } - strncat(desc->description, snd_rawmidi_info_get_id(rawmidi_info), - desc->strLen - strlen(desc->description)); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_rawmidi_info_get_name(rawmidi_info), - desc->strLen - strlen(desc->description)); - TRACE2("Returning %s, %s\n", desc->name, desc->description); - return FALSE; // do not continue iteration - } - desc->index--; - return TRUE; -} - - -static int getMIDIDeviceDescriptionByIndex(snd_rawmidi_stream_t direction, - ALSA_MIDIDeviceDescription* desc) { - initAlsaSupport(); - TRACE1(" getMIDIDeviceDescriptionByIndex (index = %d)\n", desc->index); - iterateRawmidiDevices(direction, &deviceInfoIterator, desc); - return (desc->index == 0) ? MIDI_SUCCESS : MIDI_INVALID_DEVICEID; -} - - - -int initMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc, int index) { - int ret = MIDI_SUCCESS; - desc->index = index; - desc->strLen = 200; - desc->name = (char*) calloc(desc->strLen + 1, 1); - desc->description = (char*) calloc(desc->strLen + 1, 1); - if (! desc->name || - ! desc->description) { - ret = MIDI_OUT_OF_MEMORY; - } - return ret; -} - - -void freeMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc) { - if (desc->name) { - free(desc->name); - } - if (desc->description) { - free(desc->description); - } -} - - -int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, char *name, - UINT32 nameLength) { - ALSA_MIDIDeviceDescription desc; - int ret; - - TRACE1("getMidiDeviceName: nameLength: %d\n", (int) nameLength); - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - TRACE0("getMidiDeviceName: initMIDIDeviceDescription() SUCCESS\n"); - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); - strncpy(name, desc.name, nameLength - 1); - name[nameLength - 1] = 0; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -int getMidiDeviceVendor(int index, char *name, UINT32 nameLength) { - strncpy(name, ALSA_VENDOR, nameLength - 1); - name[nameLength - 1] = 0; - return MIDI_SUCCESS; -} - - -int getMidiDeviceDescription(snd_rawmidi_stream_t direction, - int index, char *name, UINT32 nameLength) { - ALSA_MIDIDeviceDescription desc; - int ret; - - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - strncpy(name, desc.description, nameLength - 1); - name[nameLength - 1] = 0; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -int getMidiDeviceVersion(int index, char *name, UINT32 nameLength) { - getALSAVersion(name, nameLength); - return MIDI_SUCCESS; -} - - -static int getMidiDeviceID(snd_rawmidi_stream_t direction, int index, - UINT32* deviceID) { - ALSA_MIDIDeviceDescription desc; - int ret; - - ret = initMIDIDeviceDescription(&desc, index); - if (ret == MIDI_SUCCESS) { - ret = getMIDIDeviceDescriptionByIndex(direction, &desc); - if (ret == MIDI_SUCCESS) { - // TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name); - *deviceID = desc.deviceID; - } - } - freeMIDIDeviceDescription(&desc); - return ret; -} - - -/* - direction has to be either SND_RAWMIDI_STREAM_INPUT or - SND_RAWMIDI_STREAM_OUTPUT. - Returns 0 on success. Otherwise, MIDI_OUT_OF_MEMORY, MIDI_INVALID_ARGUMENT - or a negative ALSA error code is returned. -*/ -INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, - MidiDeviceHandle** handle) { - snd_rawmidi_t* native_handle; - snd_midi_event_t* event_parser = NULL; - int err; - UINT32 deviceID = 0; - char devicename[100]; -#ifdef ALSA_MIDI_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - TRACE0("> openMidiDevice()\n"); - - (*handle) = (MidiDeviceHandle*) calloc(sizeof(MidiDeviceHandle), 1); - if (!(*handle)) { - ERROR0("ERROR: openDevice: out of memory\n"); - return MIDI_OUT_OF_MEMORY; - } - - // TODO: iterate to get dev ID from index - err = getMidiDeviceID(direction, deviceIndex, &deviceID); - TRACE1(" openMidiDevice(): deviceID: %d\n", (int) deviceID); - getDeviceStringFromDeviceID(devicename, deviceID, - usePlugHw, ALSA_RAWMIDI); - TRACE1(" openMidiDevice(): deviceString: %s\n", devicename); - - // finally open the device - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_rawmidi_open(&native_handle, NULL, devicename, - SND_RAWMIDI_NONBLOCK); - } else if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_open(NULL, &native_handle, devicename, - SND_RAWMIDI_NONBLOCK); - } else { - ERROR0(" ERROR: openMidiDevice(): direction is neither SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n"); - err = MIDI_INVALID_ARGUMENT; - } - if (err < 0) { - ERROR1("< ERROR: openMidiDevice(): snd_rawmidi_open() returned %d\n", err); - free(*handle); - (*handle) = NULL; - return err; - } - /* We opened with non-blocking behaviour to not get hung if the device - is used by a different process. Writing, however, should - be blocking. So we change it here. */ - if (direction == SND_RAWMIDI_STREAM_OUTPUT) { - err = snd_rawmidi_nonblock(native_handle, 0); - if (err < 0) { - ERROR1(" ERROR: openMidiDevice(): snd_rawmidi_nonblock() returned %d\n", err); - snd_rawmidi_close(native_handle); - free(*handle); - (*handle) = NULL; - return err; - } - } - if (direction == SND_RAWMIDI_STREAM_INPUT) { - err = snd_midi_event_new(EVENT_PARSER_BUFSIZE, &event_parser); - if (err < 0) { - ERROR1(" ERROR: openMidiDevice(): snd_midi_event_new() returned %d\n", err); - snd_rawmidi_close(native_handle); - free(*handle); - (*handle) = NULL; - return err; - } - } - - (*handle)->deviceHandle = (void*) native_handle; - (*handle)->startTime = getTimeInMicroseconds(); - (*handle)->platformData = event_parser; - TRACE0("< openMidiDevice(): succeeded\n"); - return err; -} - - - -INT32 closeMidiDevice(MidiDeviceHandle* handle) { - int err; - - TRACE0("> closeMidiDevice()\n"); - if (!handle) { - ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - if (!handle->deviceHandle) { - ERROR0("< ERROR: closeMidiDevice(): native handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - err = snd_rawmidi_close((snd_rawmidi_t*) handle->deviceHandle); - TRACE1(" snd_rawmidi_close() returns %d\n", err); - if (handle->platformData) { - snd_midi_event_free((snd_midi_event_t*) handle->platformData); - } - free(handle); - TRACE0("< closeMidiDevice: succeeded\n"); - return err; -} - - -INT64 getMidiTimestamp(MidiDeviceHandle* handle) { - if (!handle) { - ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n"); - return MIDI_INVALID_HANDLE; - } - return getTimeInMicroseconds() - handle->startTime; -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -#include -#include "Utilities.h" -#include "PlatformMidi.h" - - -#ifndef PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED -#define PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED - -#define EVENT_PARSER_BUFSIZE (2048) - -// if this is defined, use plughw: devices -//#define ALSA_MIDI_USE_PLUGHW -#undef ALSA_MIDI_USE_PLUGHW - -typedef struct tag_ALSA_MIDIDeviceDescription { - int index; // in - int strLen; // in - INT32 deviceID; // out - char* name; // out - char* description; // out -} ALSA_MIDIDeviceDescription; - - -const char* getErrorStr(INT32 err); - -/* Returns the number of devices. */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceCount(snd_rawmidi_stream_t direction); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, - char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -int getMidiDeviceVendor(int index, char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -int getMidiDeviceDescription(snd_rawmidi_stream_t direction, int index, - char *name, UINT32 nameLength); - -/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */ -int getMidiDeviceVersion(int index, char *name, UINT32 nameLength); - -// returns 0 on success, otherwise MIDI_OUT_OF_MEMORY or ALSA error code -/* direction is either SND_RAWMIDI_STREAM_OUTPUT or - SND_RAWMIDI_STREAM_INPUT. */ -INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, - MidiDeviceHandle** handle); - -// returns 0 on success, otherwise a (negative) ALSA error code -INT32 closeMidiDevice(MidiDeviceHandle* handle); - -INT64 getMidiTimestamp(MidiDeviceHandle* handle); - -#endif // PLATFORM_API_LINUXOS_ALSA_MIDIUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,941 +0,0 @@ -/* - * Copyright (c) 2002, 2011, 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_LinuxOS_ALSA_PCMUtils.h" -#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" -#include "DirectAudio.h" - -#if USE_DAUDIO == TRUE - -// GetPosition method 1: based on how many bytes are passed to the kernel driver -// + does not need much processor resources -// - not very exact, "jumps" -// GetPosition method 2: ask kernel about actual position of playback. -// - very exact -// - switch to kernel layer for each call -// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA -// quick tests on a Pentium 200MMX showed max. 1.5% processor usage -// for playing back a CD-quality file and printing 20x per second a line -// on the console with the current time. So I guess performance is not such a -// factor here. -//#define GET_POSITION_METHOD1 -#define GET_POSITION_METHOD2 - - -// The default time for a period in microseconds. -// For very small buffers, only 2 periods are used. -#define DEFAULT_PERIOD_TIME 20000 /* 20ms */ - -///// implemented functions of DirectAudio.h - -INT32 DAUDIO_GetDirectAudioDeviceCount() { - return (INT32) getAudioDeviceCount(); -} - - -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) { - ALSA_AudioDeviceDescription adesc; - - adesc.index = (int) mixerIndex; - adesc.strLen = DAUDIO_STRING_LENGTH; - - adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines)); - adesc.deviceID = &(description->deviceID); - adesc.name = description->name; - adesc.vendor = description->vendor; - adesc.description = description->description; - adesc.version = description->version; - - return getAudioDeviceDescriptionByIndex(&adesc); -} - -#define MAX_BIT_INDEX 6 -// returns -// 6: for anything above 24-bit -// 5: for 4 bytes sample size, 24-bit -// 4: for 3 bytes sample size, 24-bit -// 3: for 3 bytes sample size, 20-bit -// 2: for 2 bytes sample size, 16-bit -// 1: for 1 byte sample size, 8-bit -// 0: for anything else -int getBitIndex(int sampleSizeInBytes, int significantBits) { - if (significantBits > 24) return 6; - if (sampleSizeInBytes == 4 && significantBits == 24) return 5; - if (sampleSizeInBytes == 3) { - if (significantBits == 24) return 4; - if (significantBits == 20) return 3; - } - if (sampleSizeInBytes == 2 && significantBits == 16) return 2; - if (sampleSizeInBytes == 1 && significantBits == 8) return 1; - return 0; -} - -int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) { - switch(bitIndex) { - case 1: return 1; - case 2: return 2; - case 3: /* fall through */ - case 4: return 3; - case 5: return 4; - } - return sampleSizeInBytes; -} - -int getSignificantBits(int bitIndex, int significantBits) { - switch(bitIndex) { - case 1: return 8; - case 2: return 16; - case 3: return 20; - case 4: /* fall through */ - case 5: return 24; - } - return significantBits; -} - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { - snd_pcm_t* handle; - snd_pcm_format_mask_t* formatMask; - snd_pcm_format_t format; - snd_pcm_hw_params_t* hwParams; - int handledBits[MAX_BIT_INDEX+1]; - - int ret; - int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; - int origSampleSizeInBytes, origSignificantBits; - unsigned int channels, minChannels, maxChannels; - int rate, bitIndex; - - for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; - if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { - return; - } - ret = snd_pcm_format_mask_malloc(&formatMask); - if (ret != 0) { - ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); - } else { - ret = snd_pcm_hw_params_malloc(&hwParams); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - ret = snd_pcm_hw_params_any(handle, hwParams); - /* snd_pcm_hw_params_any can return a positive value on success too */ - if (ret < 0) { - ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); - } else { - /* for the logic following this code, set ret to 0 to indicate success */ - ret = 0; - } - } - snd_pcm_hw_params_get_format_mask(hwParams, formatMask); - if (ret == 0) { - ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); - } - } - if (ret == 0) { - ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); - } - } - - // since we queried the hw: device, for many soundcards, it will only - // report the maximum number of channels (which is the only way to talk - // to the hw: device). Since we will, however, open the plughw: device - // when opening the Source/TargetDataLine, we can safely assume that - // also the channels 1..maxChannels are available. -#ifdef ALSA_PCM_USE_PLUGHW - minChannels = 1; -#endif - if (ret == 0) { - // plughw: supports any sample rate - rate = -1; - for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { - if (snd_pcm_format_mask_test(formatMask, format)) { - // format exists - if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, - &origSignificantBits, - &isSigned, &isBigEndian, &enc)) { - // now if we use plughw:, we can use any bit size below the - // natively supported ones. Some ALSA drivers only support the maximum - // bit size, so we add any sample rates below the reported one. - // E.g. this iteration reports support for 16-bit. - // getBitIndex will return 2, so it will add entries for - // 16-bit (bitIndex=2) and in the next do-while loop iteration, - // it will decrease bitIndex and will therefore add 8-bit support. - bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); - do { - if (bitIndex == 0 - || bitIndex == MAX_BIT_INDEX - || !handledBits[bitIndex]) { - handledBits[bitIndex] = TRUE; - sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); - significantBits = getSignificantBits(bitIndex, origSignificantBits); - if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { - // avoid too many channels explicitly listed - // just add -1, min, and max - DAUDIO_AddAudioFormat(creator, significantBits, - -1, -1, rate, - enc, isSigned, isBigEndian); - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * minChannels, - minChannels, rate, - enc, isSigned, isBigEndian); - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * maxChannels, - maxChannels, rate, - enc, isSigned, isBigEndian); - } else { - for (channels = minChannels; channels <= maxChannels; channels++) { - DAUDIO_AddAudioFormat(creator, significantBits, - sampleSizeInBytes * channels, - channels, rate, - enc, isSigned, isBigEndian); - } - } - } -#ifndef ALSA_PCM_USE_PLUGHW - // without plugin, do not add fake formats - break; -#endif - } while (--bitIndex > 0); - } else { - TRACE1("could not get format from alsa for format %d\n", format); - } - } else { - //TRACE1("Format %d not supported\n", format); - } - } // for loop - snd_pcm_hw_params_free(hwParams); - } - snd_pcm_format_mask_free(formatMask); - } - snd_pcm_close(handle); -} - -/** Workaround for cr 7033899, 7030629: - * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty - * (just opened, underruned or already flushed). - * Sometimes it causes PCM falls to -EBADFD error, - * sometimes causes bufferSize change. - * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used. - */ -/* ******* ALSA PCM INFO ******************** */ -typedef struct tag_AlsaPcmInfo { - snd_pcm_t* handle; - snd_pcm_hw_params_t* hwParams; - snd_pcm_sw_params_t* swParams; - int bufferSizeInBytes; - int frameSize; // storage size in Bytes - unsigned int periods; - snd_pcm_uframes_t periodSize; - short int isRunning; // see comment above - short int isFlushed; // see comment above -#ifdef GET_POSITION_METHOD2 - // to be used exclusively by getBytePosition! - snd_pcm_status_t* positionStatus; -#endif -} AlsaPcmInfo; - - -int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) { - int ret; - int threshold; - - if (useThreshold) { - // start device whenever anything is written to the buffer - threshold = 1; - } else { - // never start the device automatically - threshold = 2000000000; /* near UINT_MAX */ - } - ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold); - if (ret < 0) { - ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -int setStartThreshold(AlsaPcmInfo* info, int useThreshold) { - int ret = 0; - - if (!setStartThresholdNoCommit(info, useThreshold)) { - ret = -1; - } - if (ret == 0) { - // commit it - ret = snd_pcm_sw_params(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); - } - } - return (ret == 0)?TRUE:FALSE; -} - - -// returns TRUE if successful -int setHWParams(AlsaPcmInfo* info, - float sampleRate, - int channels, - int bufferSizeInFrames, - snd_pcm_format_t format) { - unsigned int rrate, periodTime, periods; - int ret, dir; - snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; - - /* choose all parameters */ - ret = snd_pcm_hw_params_any(info->handle, info->hwParams); - if (ret < 0) { - ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the interleaved read/write format */ - ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); - if (ret < 0) { - ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the sample format */ - ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format); - if (ret < 0) { - ERROR1("Sample format not available: %s\n", snd_strerror(ret)); - return FALSE; - } - /* set the count of channels */ - ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels); - if (ret < 0) { - ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret)); - return FALSE; - } - /* set the stream rate */ - rrate = (int) (sampleRate + 0.5f); - dir = 0; - ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); - if (ret < 0) { - ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); - return FALSE; - } - if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) { - ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate); - return FALSE; - } - /* set the buffer time */ - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); - if (ret < 0) { - ERROR2("Unable to set buffer size to %d frames: %s\n", - (int) alsaBufferSizeInFrames, snd_strerror(ret)); - return FALSE; - } - bufferSizeInFrames = (int) alsaBufferSizeInFrames; - /* set the period time */ - if (bufferSizeInFrames > 1024) { - dir = 0; - periodTime = DEFAULT_PERIOD_TIME; - ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); - if (ret < 0) { - ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); - return FALSE; - } - } else { - /* set the period count for very small buffer sizes to 2 */ - dir = 0; - periods = 2; - ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); - if (ret < 0) { - ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); - return FALSE; - } - } - /* write the parameters to device */ - ret = snd_pcm_hw_params(info->handle, info->hwParams); - if (ret < 0) { - ERROR1("Unable to set hw params: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -// returns 1 if successful -int setSWParams(AlsaPcmInfo* info) { - int ret; - - /* get the current swparams */ - ret = snd_pcm_sw_params_current(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret)); - return FALSE; - } - /* never start the transfer automatically */ - if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) { - return FALSE; - } - - /* allow the transfer when at least period_size samples can be processed */ - ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize); - if (ret < 0) { - ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); - return FALSE; - } - /* write the parameters to the playback device */ - ret = snd_pcm_sw_params(info->handle, info->swParams); - if (ret < 0) { - ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); - return FALSE; - } - return TRUE; -} - -static snd_output_t* ALSA_OUTPUT = NULL; - -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) { - snd_pcm_format_mask_t* formatMask; - snd_pcm_format_t format; - int dir; - int ret = 0; - AlsaPcmInfo* info = NULL; - /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ - snd_pcm_uframes_t alsaBufferSizeInFrames = 0; - - - TRACE0("> DAUDIO_Open\n"); -#ifdef USE_TRACE - // for using ALSA debug dump methods - if (ALSA_OUTPUT == NULL) { - snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); - } -#endif - if (channels <= 0) { - ERROR1("ERROR: Invalid number of channels=%d!\n", channels); - return NULL; - } - info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); - if (!info) { - ERROR0("Out of memory\n"); - return NULL; - } - memset(info, 0, sizeof(AlsaPcmInfo)); - // initial values are: stopped, flushed - info->isRunning = 0; - info->isFlushed = 1; - - ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); - if (ret == 0) { - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - ret = snd_pcm_hw_params_malloc(&(info->hwParams)); - if (ret != 0) { - ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - ret = -1; - if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, - isSigned, isBigEndian, encoding)) { - if (setHWParams(info, - sampleRate, - channels, - bufferSizeInBytes / frameSize, - format)) { - info->frameSize = frameSize; - ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); - } - snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); - snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); - info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; - TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", - (int) info->periodSize, info->periods, info->bufferSizeInBytes); - } - } - } - if (ret == 0) { - // set software parameters - ret = snd_pcm_sw_params_malloc(&(info->swParams)); - if (ret != 0) { - ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); - } else { - if (!setSWParams(info)) { - ret = -1; - } - } - } - if (ret == 0) { - // prepare device - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); - } - } - -#ifdef GET_POSITION_METHOD2 - if (ret == 0) { - ret = snd_pcm_status_malloc(&(info->positionStatus)); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); - } - } -#endif - } - if (ret != 0) { - DAUDIO_Close((void*) info, isSource); - info = NULL; - } else { - // set to non-blocking mode - snd_pcm_nonblock(info->handle, 1); - TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", - (void*) info->handle); - } - return (void*) info; -} - -#ifdef USE_TRACE -void printState(snd_pcm_state_t state) { - if (state == SND_PCM_STATE_OPEN) { - TRACE0("State: SND_PCM_STATE_OPEN\n"); - } - else if (state == SND_PCM_STATE_SETUP) { - TRACE0("State: SND_PCM_STATE_SETUP\n"); - } - else if (state == SND_PCM_STATE_PREPARED) { - TRACE0("State: SND_PCM_STATE_PREPARED\n"); - } - else if (state == SND_PCM_STATE_RUNNING) { - TRACE0("State: SND_PCM_STATE_RUNNING\n"); - } - else if (state == SND_PCM_STATE_XRUN) { - TRACE0("State: SND_PCM_STATE_XRUN\n"); - } - else if (state == SND_PCM_STATE_DRAINING) { - TRACE0("State: SND_PCM_STATE_DRAINING\n"); - } - else if (state == SND_PCM_STATE_PAUSED) { - TRACE0("State: SND_PCM_STATE_PAUSED\n"); - } - else if (state == SND_PCM_STATE_SUSPENDED) { - TRACE0("State: SND_PCM_STATE_SUSPENDED\n"); - } -} -#endif - -int DAUDIO_Start(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - snd_pcm_state_t state; - - TRACE0("> DAUDIO_Start\n"); - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - // set start mode so that it always starts as soon as data is there - setStartThreshold(info, TRUE /* use threshold */); - state = snd_pcm_state(info->handle); - if (state == SND_PCM_STATE_PAUSED) { - // in case it was stopped previously - TRACE0(" Un-pausing...\n"); - ret = snd_pcm_pause(info->handle, FALSE); - if (ret != 0) { - ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret)); - } - } - if (state == SND_PCM_STATE_SUSPENDED) { - TRACE0(" Resuming...\n"); - ret = snd_pcm_resume(info->handle); - if (ret < 0) { - if ((ret != -EAGAIN) && (ret != -ENOSYS)) { - ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret)); - } - } - } - if (state == SND_PCM_STATE_SETUP) { - TRACE0("need to call prepare again...\n"); - // prepare device - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); - } - } - // in case there is still data in the buffers - ret = snd_pcm_start(info->handle); - if (ret != 0) { - if (ret != -EPIPE) { - ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret)); - } - } - // set to non-blocking mode - ret = snd_pcm_nonblock(info->handle, 1); - if (ret != 0) { - ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret)); - } - state = snd_pcm_state(info->handle); -#ifdef USE_TRACE - printState(state); -#endif - ret = (state == SND_PCM_STATE_PREPARED) - || (state == SND_PCM_STATE_RUNNING) - || (state == SND_PCM_STATE_XRUN) - || (state == SND_PCM_STATE_SUSPENDED); - if (ret) { - info->isRunning = 1; - // source line should keep isFlushed value until Write() is called; - // for target data line reset it right now. - if (!isSource) { - info->isFlushed = 0; - } - } - TRACE1("< DAUDIO_Start %s\n", ret?"success":"error"); - return ret?TRUE:FALSE; -} - -int DAUDIO_Stop(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - - TRACE0("> DAUDIO_Stop\n"); - // set to blocking mode - snd_pcm_nonblock(info->handle, 0); - setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun - ret = snd_pcm_pause(info->handle, 1); - // set to non-blocking mode - snd_pcm_nonblock(info->handle, 1); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret)); - return FALSE; - } - info->isRunning = 0; - TRACE0("< DAUDIO_Stop success\n"); - return TRUE; -} - -void DAUDIO_Close(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - - TRACE0("DAUDIO_Close\n"); - if (info != NULL) { - if (info->handle != NULL) { - snd_pcm_close(info->handle); - } - if (info->hwParams) { - snd_pcm_hw_params_free(info->hwParams); - } - if (info->swParams) { - snd_pcm_sw_params_free(info->swParams); - } -#ifdef GET_POSITION_METHOD2 - if (info->positionStatus) { - snd_pcm_status_free(info->positionStatus); - } -#endif - free(info); - } -} - -/* - * Underrun and suspend recovery - * returns - * 0: exit native and return 0 - * 1: try again to write/read - * -1: error - exit native with return value -1 - */ -int xrun_recovery(AlsaPcmInfo* info, int err) { - int ret; - - if (err == -EPIPE) { /* underrun / overflow */ - TRACE0("xrun_recovery: underrun/overflow.\n"); - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); - return -1; - } - return 1; - } else if (err == -ESTRPIPE) { - TRACE0("xrun_recovery: suspended.\n"); - ret = snd_pcm_resume(info->handle); - if (ret < 0) { - if (ret == -EAGAIN) { - return 0; /* wait until the suspend flag is released */ - } - return -1; - } - ret = snd_pcm_prepare(info->handle); - if (ret < 0) { - ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); - return -1; - } - return 1; - } else if (err == -EAGAIN) { - TRACE0("xrun_recovery: EAGAIN try again flag.\n"); - return 0; - } - - TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err)); - return -1; -} - -// returns -1 on error -int DAUDIO_Write(void* id, char* data, int byteSize) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret, count; - snd_pcm_sframes_t frameSize, writtenFrames; - - TRACE1("> DAUDIO_Write %d bytes\n", byteSize); - - /* sanity */ - if (byteSize <= 0 || info->frameSize <= 0) { - ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n", - (int) byteSize, (int) info->frameSize); - TRACE0("< DAUDIO_Write returning -1\n"); - return -1; - } - - count = 2; // maximum number of trials to recover from underrun - //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); - frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); - do { - writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize); - - if (writtenFrames < 0) { - ret = xrun_recovery(info, (int) writtenFrames); - if (ret <= 0) { - TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret); - return ret; - } - if (count-- <= 0) { - ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n"); - return -1; - } - } else { - break; - } - } while (TRUE); - //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames); - - if (writtenFrames > 0) { - // reset "flushed" flag - info->isFlushed = 0; - } - - ret = (int) (writtenFrames * info->frameSize); - TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); - return ret; -} - -// returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret, count; - snd_pcm_sframes_t frameSize, readFrames; - - TRACE1("> DAUDIO_Read %d bytes\n", byteSize); - /*TRACE3(" info=%p, data=%p, byteSize=%d\n", - (void*) info, (void*) data, (int) byteSize); - TRACE2(" info->frameSize=%d, info->handle=%p\n", - (int) info->frameSize, (void*) info->handle); - */ - /* sanity */ - if (byteSize <= 0 || info->frameSize <= 0) { - ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n", - (int) byteSize, (int) info->frameSize); - TRACE0("< DAUDIO_Read returning -1\n"); - return -1; - } - if (!info->isRunning && info->isFlushed) { - // PCM has nothing to read - return 0; - } - - count = 2; // maximum number of trials to recover from error - //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); - frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); - do { - readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize); - if (readFrames < 0) { - ret = xrun_recovery(info, (int) readFrames); - if (ret <= 0) { - TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret); - return ret; - } - if (count-- <= 0) { - ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n"); - return -1; - } - } else { - break; - } - } while (TRUE); - //ret = snd_pcm_frames_to_bytes(info->handle, readFrames); - ret = (int) (readFrames * info->frameSize); - TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); - return ret; -} - - -int DAUDIO_GetBufferSize(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - - return info->bufferSizeInBytes; -} - -int DAUDIO_StillDraining(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - snd_pcm_state_t state; - - state = snd_pcm_state(info->handle); - //printState(state); - //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE"); - return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE; -} - - -int DAUDIO_Flush(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - - TRACE0("DAUDIO_Flush\n"); - - if (info->isFlushed) { - // nothing to drop - return 1; - } - - ret = snd_pcm_drop(info->handle); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret)); - return FALSE; - } - - info->isFlushed = 1; - if (info->isRunning) { - ret = DAUDIO_Start(id, isSource); - } - return ret; -} - -int DAUDIO_GetAvailable(void* id, int isSource) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - snd_pcm_sframes_t availableInFrames; - snd_pcm_state_t state; - int ret; - - state = snd_pcm_state(info->handle); - if (info->isFlushed || state == SND_PCM_STATE_XRUN) { - // if in xrun state then we have the entire buffer available, - // not 0 as alsa reports - ret = info->bufferSizeInBytes; - } else { - availableInFrames = snd_pcm_avail_update(info->handle); - if (availableInFrames < 0) { - ret = 0; - } else { - //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames); - ret = (int) (availableInFrames * info->frameSize); - } - } - TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); - return ret; -} - -INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) { - // estimate the current position with the buffer size and - // the available bytes to read or write in the buffer. - // not an elegant solution - bytePos will stop on xruns, - // and in race conditions it may jump backwards - // Advantage is that it is indeed based on the samples that go through - // the system (rather than time-based methods) - if (isSource) { - // javaBytePos is the position that is reached when the current - // buffer is played completely - return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes); - } else { - // javaBytePos is the position that was when the current buffer was empty - return (INT64) (javaBytePos + availInBytes); - } -} - -INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { - AlsaPcmInfo* info = (AlsaPcmInfo*) id; - int ret; - INT64 result = javaBytePos; - snd_pcm_state_t state; - state = snd_pcm_state(info->handle); - - if (!info->isFlushed && state != SND_PCM_STATE_XRUN) { -#ifdef GET_POSITION_METHOD2 - snd_timestamp_t* ts; - snd_pcm_uframes_t framesAvail; - - // note: slight race condition if this is called simultaneously from 2 threads - ret = snd_pcm_status(info->handle, info->positionStatus); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret)); - result = javaBytePos; - } else { - // calculate from time value, or from available bytes - framesAvail = snd_pcm_status_get_avail(info->positionStatus); - result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); - } -#endif -#ifdef GET_POSITION_METHOD3 - snd_pcm_uframes_t framesAvail; - ret = snd_pcm_avail(info->handle, &framesAvail); - if (ret != 0) { - ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret)); - result = javaBytePos; - } else { - result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); - } -#endif -#ifdef GET_POSITION_METHOD1 - result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource)); -#endif - } - //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); - return result; -} - - - -void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { - /* save to ignore, since GetBytePosition - * takes the javaBytePos param into account - */ -} - -int DAUDIO_RequiresServicing(void* id, int isSource) { - // never need servicing on Linux - return FALSE; -} - -void DAUDIO_Service(void* id, int isSource) { - // never need servicing on Linux -} - - -#endif // USE_DAUDIO diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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_LinuxOS_ALSA_PCMUtils.h" -#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" - - - -// callback for iteration through devices -// returns TRUE if iteration should continue -// NOTE: cardinfo may be NULL (for "default" device) -typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo, - snd_ctl_card_info_t* cardinfo, void *userData); - -// for each ALSA device, call iterator. userData is passed to the iterator -// returns total number of iterations -int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) { - int count = 0; - int subdeviceCount; - int card, dev, subDev; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_pcm_t *pcm; - snd_pcm_info_t* pcminfo; - snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL; - UINT32 deviceID; - int doContinue = TRUE; - - snd_pcm_info_malloc(&pcminfo); - snd_ctl_card_info_malloc(&cardinfo); - - // 1st try "default" device - err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - if (err < 0) { - // try with the other direction - err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME, - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - } - if (err < 0) { - ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err)); - } else { - err = snd_pcm_info(pcm, pcminfo); - snd_pcm_close(pcm); - if (err < 0) { - ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n", - snd_strerror(err)); - } else { - // try to get card info - card = snd_pcm_info_get_card(pcminfo); - if (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) { - if (snd_ctl_card_info(handle, cardinfo) >= 0) { - defcardinfo = cardinfo; - } - snd_ctl_close(handle); - } - } - // call callback function for the device - if (iterator != NULL) { - doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo, - defcardinfo, userData); - } - count++; - } - } - - // iterate cards - card = -1; - while (doContinue) { - if (snd_card_next(&card) < 0) { - break; - } - if (card < 0) { - break; - } - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", - card, snd_strerror(err)); - } else { - err = snd_ctl_card_info(handle, cardinfo); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", - card, snd_strerror(err)); - } else { - dev = -1; - while (doContinue) { - if (snd_ctl_pcm_next_device(handle, &dev) < 0) { - ERROR0("snd_ctl_pcm_next_device\n"); - } - if (dev < 0) { - break; - } - snd_pcm_info_set_device(pcminfo, dev); - snd_pcm_info_set_subdevice(pcminfo, 0); - snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); - err = snd_ctl_pcm_info(handle, pcminfo); - if (err == -ENOENT) { - // try with the other direction - snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); - err = snd_ctl_pcm_info(handle, pcminfo); - } - if (err < 0) { - if (err != -ENOENT) { - ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s", - card, snd_strerror(err)); - } - } else { - subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ? - snd_pcm_info_get_subdevices_count(pcminfo) : 1; - if (iterator!=NULL) { - for (subDev = 0; subDev < subdeviceCount; subDev++) { - deviceID = encodeDeviceID(card, dev, subDev); - doContinue = (*iterator)(deviceID, pcminfo, - cardinfo, userData); - count++; - if (!doContinue) { - break; - } - } - } else { - count += subdeviceCount; - } - } - } // of while(doContinue) - } - snd_ctl_close(handle); - } - } - snd_ctl_card_info_free(cardinfo); - snd_pcm_info_free(pcminfo); - return count; -} - -int getAudioDeviceCount() { - initAlsaSupport(); - return iteratePCMDevices(NULL, NULL); -} - -int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo, - snd_ctl_card_info_t* cardinfo, void* userData) { - char buffer[300]; - ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData; -#ifdef ALSA_PCM_USE_PLUGHW - int usePlugHw = 1; -#else - int usePlugHw = 0; -#endif - - initAlsaSupport(); - if (desc->index == 0) { - // we found the device with correct index - *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ? - 1 : snd_pcm_info_get_subdevices_count(pcminfo); - *desc->deviceID = deviceID; - buffer[0]=' '; buffer[1]='['; - // buffer[300] is enough to store the actual device string w/o overrun - getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM); - strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1); - strncpy(desc->name, - (cardinfo != NULL) - ? snd_ctl_card_info_get_id(cardinfo) - : snd_pcm_info_get_id(pcminfo), - desc->strLen - strlen(buffer)); - strncat(desc->name, buffer, desc->strLen - strlen(desc->name)); - strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen); - strncpy(desc->description, - (cardinfo != NULL) - ? snd_ctl_card_info_get_name(cardinfo) - : snd_pcm_info_get_name(pcminfo), - desc->strLen); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description)); - strncat(desc->description, ", ", desc->strLen - strlen(desc->description)); - strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description)); - getALSAVersion(desc->version, desc->strLen); - TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version); - return FALSE; // do not continue iteration - } - desc->index--; - return TRUE; -} - -// returns 0 if successful -int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) { - char buffer[200]; - int ret; - - initAlsaSupport(); - getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM); - - TRACE1("Opening ALSA device %s\n", buffer); - ret = snd_pcm_open(handle, buffer, - isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK); - if (ret != 0) { - ERROR1("snd_pcm_open returned error code %d \n", ret); - *handle = NULL; - } - return ret; -} - - -int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) { - initAlsaSupport(); - TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index); - iteratePCMDevices(&deviceInfoIterator, desc); - return (desc->index == 0)?TRUE:FALSE; -} - -// returns 1 if successful -// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) -int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, - int* sampleSizeInBytes, int* significantBits, - int* isSigned, int* isBigEndian, int* enc) { - - *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8; - *significantBits = snd_pcm_format_width(alsaFormat); - - // defaults - *enc = 0; // PCM - *isSigned = (snd_pcm_format_signed(alsaFormat) > 0); - *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0); - - // non-PCM formats - if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law - *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes; - } - else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law - *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes; - } - else if (snd_pcm_format_linear(alsaFormat) < 1) { - return 0; - } - return (*sampleSizeInBytes > 0); -} - -// returns 1 if successful -int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, - int sampleSizeInBytes, int significantBits, - int isSigned, int isBigEndian, int enc) { - *alsaFormat = SND_PCM_FORMAT_UNKNOWN; - - if (enc == 0) { - *alsaFormat = snd_pcm_build_linear_format(significantBits, - sampleSizeInBytes * 8, - isSigned?0:1, - isBigEndian?1:0); - } - else if ((sampleSizeInBytes == 1) && (significantBits == 8)) { - if (enc == 1) { // ULAW - *alsaFormat = SND_PCM_FORMAT_MU_LAW; - } - else if (enc == 2) { // ALAW - *alsaFormat = SND_PCM_FORMAT_A_LAW; - } - } - return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1; -} - - -/* end */ diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2003, 2010, 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 this with a later version of ALSA than 0.9.0rc3 -// (starting from 1.0.0 it became default behaviour) -#define ALSA_PCM_NEW_HW_PARAMS_API -#include -#include "Utilities.h" - -#ifndef PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED -#define PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED - -// if this is defined, use plughw: devices -#define ALSA_PCM_USE_PLUGHW -//#undef ALSA_PCM_USE_PLUGHW - - -// maximum number of channels that is listed in the formats. If more, than -// just -1 for channel count is used. -#define MAXIMUM_LISTED_CHANNELS 32 - -typedef struct tag_ALSA_AudioDeviceDescription { - int index; // in - int strLen; // in - INT32* deviceID; // out - int* maxSimultaneousLines; // out - char* name; // out - char* vendor; // out - char* description; // out - char* version; // out -} ALSA_AudioDeviceDescription; - - - -int getAudioDeviceCount(); -int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc); - -// returns ALSA error code, or 0 if successful -int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware); - -// returns 1 if successful -// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) -int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, - int* sampleSizeInBytes, int* significantBits, - int* isSigned, int* isBigEndian, int* enc); - -int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat, - int sampleSizeInBytes, int significantBits, - int isSigned, int isBigEndian, int enc); - -#endif // PLATFORM_API_LINUXOS_ALSA_PCMUTILS_H_INCLUDED diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +0,0 @@ -/* - * Copyright (c) 2003, 2016, 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 "Ports.h" -#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h" -#include - -#if USE_PORTS == TRUE - -#define MAX_ELEMS (300) -#define MAX_CONTROLS (MAX_ELEMS * 4) - -#define CHANNELS_MONO (SND_MIXER_SCHN_LAST + 1) -#define CHANNELS_STEREO (SND_MIXER_SCHN_LAST + 2) - -typedef struct { - snd_mixer_elem_t* elem; - INT32 portType; /* one of PORT_XXX_xx */ - char* controlType; /* one of CONTROL_TYPE_xx */ - /* Values: either SND_MIXER_SCHN_FRONT_xx, CHANNELS_MONO or CHANNELS_STEREO. - For SND_MIXER_SCHN_FRONT_xx, exactly this channel is set/retrieved directly. - For CHANNELS_MONO, ALSA channel SND_MIXER_SCHN_MONO is set/retrieved directly. - For CHANNELS_STEREO, ALSA channels SND_MIXER_SCHN_FRONT_LEFT and SND_MIXER_SCHN_FRONT_RIGHT - are set after a calculation that takes balance into account. Retrieved? Average of both - channels? (Using a cached value is not a good idea since the value in the HW may have been - altered.) */ - INT32 channel; -} PortControl; - - -typedef struct tag_PortMixer { - snd_mixer_t* mixer_handle; - /* Number of array elements used in elems and types. */ - int numElems; - snd_mixer_elem_t** elems; - /* Array of port types (PORT_SRC_UNKNOWN etc.). Indices are the same as in elems. */ - INT32* types; - /* Number of array elements used in controls. */ - int numControls; - PortControl* controls; -} PortMixer; - - -///// implemented functions of Ports.h - -INT32 PORT_GetPortMixerCount() { - INT32 mixerCount; - int card; - char devname[16]; - int err; - snd_ctl_t *handle; - snd_ctl_card_info_t* info; - - TRACE0("> PORT_GetPortMixerCount\n"); - - initAlsaSupport(); - - snd_ctl_card_info_malloc(&info); - card = -1; - mixerCount = 0; - if (snd_card_next(&card) >= 0) { - while (card >= 0) { - sprintf(devname, ALSA_HARDWARE_CARD, card); - TRACE1("PORT_GetPortMixerCount: Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, 0); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err)); - } else { - mixerCount++; - snd_ctl_close(handle); - } - if (snd_card_next(&card) < 0) { - break; - } - } - } - snd_ctl_card_info_free(info); - TRACE0("< PORT_GetPortMixerCount\n"); - return mixerCount; -} - - -INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { - snd_ctl_t* handle; - snd_ctl_card_info_t* card_info; - char devname[16]; - int err; - char buffer[100]; - - TRACE0("> PORT_GetPortMixerDescription\n"); - snd_ctl_card_info_malloc(&card_info); - - sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); - TRACE1("Opening alsa device \"%s\"...\n", devname); - err = snd_ctl_open(&handle, devname, 0); - if (err < 0) { - ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); - return FALSE; - } - err = snd_ctl_card_info(handle, card_info); - if (err < 0) { - ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", (int) mixerIndex, snd_strerror(err)); - } - strncpy(description->name, snd_ctl_card_info_get_id(card_info), PORT_STRING_LENGTH - 1); - sprintf(buffer, " [%s]", devname); - strncat(description->name, buffer, PORT_STRING_LENGTH - 1 - strlen(description->name)); - strncpy(description->vendor, "ALSA (http://www.alsa-project.org)", PORT_STRING_LENGTH - 1); - strncpy(description->description, snd_ctl_card_info_get_name(card_info), PORT_STRING_LENGTH - 1); - strncat(description->description, ", ", PORT_STRING_LENGTH - 1 - strlen(description->description)); - strncat(description->description, snd_ctl_card_info_get_mixername(card_info), PORT_STRING_LENGTH - 1 - strlen(description->description)); - getALSAVersion(description->version, PORT_STRING_LENGTH - 1); - - snd_ctl_close(handle); - snd_ctl_card_info_free(card_info); - TRACE0("< PORT_GetPortMixerDescription\n"); - return TRUE; -} - - -void* PORT_Open(INT32 mixerIndex) { - char devname[16]; - snd_mixer_t* mixer_handle; - int err; - PortMixer* handle; - - TRACE0("> PORT_Open\n"); - sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); - if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) { - ERROR2("Mixer %s open error: %s", devname, snd_strerror(err)); - return NULL; - } - if ((err = snd_mixer_attach(mixer_handle, devname)) < 0) { - ERROR2("Mixer attach %s error: %s", devname, snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0) { - ERROR1("Mixer register error: %s", snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - err = snd_mixer_load(mixer_handle); - if (err < 0) { - ERROR2("Mixer %s load error: %s", devname, snd_strerror(err)); - snd_mixer_close(mixer_handle); - return NULL; - } - handle = (PortMixer*) calloc(1, sizeof(PortMixer)); - if (handle == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - return NULL; - } - handle->numElems = 0; - handle->elems = (snd_mixer_elem_t**) calloc(MAX_ELEMS, sizeof(snd_mixer_elem_t*)); - if (handle->elems == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle); - return NULL; - } - handle->types = (INT32*) calloc(MAX_ELEMS, sizeof(INT32)); - if (handle->types == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle->elems); - free(handle); - return NULL; - } - handle->controls = (PortControl*) calloc(MAX_CONTROLS, sizeof(PortControl)); - if (handle->controls == NULL) { - ERROR0("malloc() failed."); - snd_mixer_close(mixer_handle); - free(handle->elems); - free(handle->types); - free(handle); - return NULL; - } - handle->mixer_handle = mixer_handle; - // necessary to initialize data structures - PORT_GetPortCount(handle); - TRACE0("< PORT_Open\n"); - return handle; -} - - -void PORT_Close(void* id) { - TRACE0("> PORT_Close\n"); - if (id != NULL) { - PortMixer* handle = (PortMixer*) id; - if (handle->mixer_handle != NULL) { - snd_mixer_close(handle->mixer_handle); - } - if (handle->elems != NULL) { - free(handle->elems); - } - if (handle->types != NULL) { - free(handle->types); - } - if (handle->controls != NULL) { - free(handle->controls); - } - free(handle); - } - TRACE0("< PORT_Close\n"); -} - - - -INT32 PORT_GetPortCount(void* id) { - PortMixer* portMixer; - snd_mixer_elem_t *elem; - - TRACE0("> PORT_GetPortCount\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portMixer->numElems == 0) { - for (elem = snd_mixer_first_elem(portMixer->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { - if (!snd_mixer_selem_is_active(elem)) - continue; - TRACE2("Simple mixer control '%s',%i\n", - snd_mixer_selem_get_name(elem), - snd_mixer_selem_get_index(elem)); - if (snd_mixer_selem_has_playback_volume(elem)) { - portMixer->elems[portMixer->numElems] = elem; - portMixer->types[portMixer->numElems] = PORT_DST_UNKNOWN; - portMixer->numElems++; - } - // to prevent buffer overflow - if (portMixer->numElems >= MAX_ELEMS) { - break; - } - /* If an element has both playback an capture volume, it is put into the arrays - twice. */ - if (snd_mixer_selem_has_capture_volume(elem)) { - portMixer->elems[portMixer->numElems] = elem; - portMixer->types[portMixer->numElems] = PORT_SRC_UNKNOWN; - portMixer->numElems++; - } - // to prevent buffer overflow - if (portMixer->numElems >= MAX_ELEMS) { - break; - } - } - } - TRACE0("< PORT_GetPortCount\n"); - return portMixer->numElems; -} - - -INT32 PORT_GetPortType(void* id, INT32 portIndex) { - PortMixer* portMixer; - INT32 type; - TRACE0("> PORT_GetPortType\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - // $$mp: Should become a descriptive error code (index out of bounds). - return -1; - } - type = portMixer->types[portIndex]; - TRACE0("< PORT_GetPortType\n"); - return type; -} - - -INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { - PortMixer* portMixer; - const char* nam; - - TRACE0("> PORT_GetPortName\n"); - if (id == NULL) { - // $$mp: Should become a descriptive error code (invalid handle). - return -1; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - // $$mp: Should become a descriptive error code (index out of bounds). - return -1; - } - nam = snd_mixer_selem_get_name(portMixer->elems[portIndex]); - strncpy(name, nam, len - 1); - name[len - 1] = 0; - TRACE0("< PORT_GetPortName\n"); - return TRUE; -} - - -static int isPlaybackFunction(INT32 portType) { - return (portType & PORT_DST_MASK); -} - - -/* Sets portControl to a pointer to the next free array element in the PortControl (pointer) - array of the passed portMixer. Returns TRUE if successful. May return FALSE if there is no - free slot. In this case, portControl is not altered */ -static int getControlSlot(PortMixer* portMixer, PortControl** portControl) { - if (portMixer->numControls >= MAX_CONTROLS) { - return FALSE; - } else { - *portControl = &(portMixer->controls[portMixer->numControls]); - portMixer->numControls++; - return TRUE; - } -} - - -/* Protect against illegal min-max values, preventing divisions by zero. - */ -inline static long getRange(long min, long max) { - if (max > min) { - return max - min; - } else { - return 1; - } -} - - -/* Idea: we may specify that if unit is an empty string, the values are linear and if unit is "dB", - the values are logarithmic. -*/ -static void* createVolumeControl(PortControlCreator* creator, - PortControl* portControl, - snd_mixer_elem_t* elem, int isPlayback) { - void* control; - float precision; - long min, max; - - if (isPlayback) { - snd_mixer_selem_get_playback_volume_range(elem, &min, &max); - } else { - snd_mixer_selem_get_capture_volume_range(elem, &min, &max); - } - /* $$mp: The volume values retrieved with the ALSA API are strongly supposed to be logarithmic. - So the following calculation is wrong. However, there is no correct calculation, since - for equal-distant logarithmic steps, the precision expressed in linear varies over the - scale. */ - precision = 1.0F / getRange(min, max); - control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_VOLUME, 0.0F, +1.0F, precision, ""); - return control; -} - - -void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { - PortMixer* portMixer; - snd_mixer_elem_t* elem; - void* control; - PortControl* portControl; - void* controls[10]; - int numControls; - char* portName; - int isPlayback = 0; - int isMono; - int isStereo; - char* type; - snd_mixer_selem_channel_id_t channel; - memset(controls, 0, sizeof(controls)); - - TRACE0("> PORT_GetControls\n"); - if (id == NULL) { - ERROR0("Invalid handle!"); - // $$mp: an error code should be returned. - return; - } - portMixer = (PortMixer*) id; - if (portIndex < 0 || portIndex >= portMixer->numElems) { - ERROR0("Port index out of range!"); - // $$mp: an error code should be returned. - return; - } - numControls = 0; - elem = portMixer->elems[portIndex]; - if (snd_mixer_selem_has_playback_volume(elem) || snd_mixer_selem_has_capture_volume(elem)) { - /* Since we've split/duplicated elements with both playback and capture on the recovery - of elements, we now can assume that we handle only to deal with either playback or - capture. */ - isPlayback = isPlaybackFunction(portMixer->types[portIndex]); - isMono = (isPlayback && snd_mixer_selem_is_playback_mono(elem)) || - (!isPlayback && snd_mixer_selem_is_capture_mono(elem)); - isStereo = (isPlayback && - snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && - snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)) || - (!isPlayback && - snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) && - snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)); - // single volume control - if (isMono || isStereo) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_VOLUME; - if (isMono) { - portControl->channel = CHANNELS_MONO; - } else { - portControl->channel = CHANNELS_STEREO; - } - control = createVolumeControl(creator, portControl, elem, isPlayback); - if (control != NULL) { - controls[numControls++] = control; - } - } - } else { // more than two channels, each channels has its own control. - for (channel = SND_MIXER_SCHN_FRONT_LEFT; channel <= SND_MIXER_SCHN_LAST; channel++) { - if ((isPlayback && snd_mixer_selem_has_playback_channel(elem, channel)) || - (!isPlayback && snd_mixer_selem_has_capture_channel(elem, channel))) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_VOLUME; - portControl->channel = channel; - control = createVolumeControl(creator, portControl, elem, isPlayback); - // We wrap in a compound control to provide the channel name. - if (control != NULL) { - /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the - declaration of PORT_NewCompoundControlPtr in Ports.h should be changed - to take a const char* parameter. */ - control = (creator->newCompoundControl)(creator, (char*) snd_mixer_selem_channel_name(channel), &control, 1); - } - if (control != NULL) { - controls[numControls++] = control; - } - } - } - } - } - // BALANCE control - if (isStereo) { - if (getControlSlot(portMixer, &portControl)) { - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = CONTROL_TYPE_BALANCE; - portControl->channel = CHANNELS_STEREO; - /* $$mp: The value for precision is chosen more or less arbitrarily. */ - control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_BALANCE, -1.0F, 1.0F, 0.01F, ""); - if (control != NULL) { - controls[numControls++] = control; - } - } - } - } - if (snd_mixer_selem_has_playback_switch(elem) || snd_mixer_selem_has_capture_switch(elem)) { - if (getControlSlot(portMixer, &portControl)) { - type = isPlayback ? CONTROL_TYPE_MUTE : CONTROL_TYPE_SELECT; - portControl->elem = elem; - portControl->portType = portMixer->types[portIndex]; - portControl->controlType = type; - control = (creator->newBooleanControl)(creator, portControl, type); - if (control != NULL) { - controls[numControls++] = control; - } - } - } - /* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the - declaration of PORT_NewCompoundControlPtr in Ports.h should be changed - to take a const char* parameter. */ - portName = (char*) snd_mixer_selem_get_name(elem); - control = (creator->newCompoundControl)(creator, portName, controls, numControls); - if (control != NULL) { - (creator->addControl)(creator, control); - } - TRACE0("< PORT_GetControls\n"); -} - - -INT32 PORT_GetIntValue(void* controlIDV) { - PortControl* portControl = (PortControl*) controlIDV; - int value = 0; - snd_mixer_selem_channel_id_t channel; - - if (portControl != NULL) { - switch (portControl->channel) { - case CHANNELS_MONO: - channel = SND_MIXER_SCHN_MONO; - break; - - case CHANNELS_STEREO: - channel = SND_MIXER_SCHN_FRONT_LEFT; - break; - - default: - channel = portControl->channel; - } - if (portControl->controlType == CONTROL_TYPE_MUTE || - portControl->controlType == CONTROL_TYPE_SELECT) { - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_switch(portControl->elem, channel, &value); - } else { - snd_mixer_selem_get_capture_switch(portControl->elem, channel, &value); - } - if (portControl->controlType == CONTROL_TYPE_MUTE) { - value = ! value; - } - } else { - ERROR1("PORT_GetIntValue(): inappropriate control type: %s\n", - portControl->controlType); - } - } - return (INT32) value; -} - - -void PORT_SetIntValue(void* controlIDV, INT32 value) { - PortControl* portControl = (PortControl*) controlIDV; - snd_mixer_selem_channel_id_t channel; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_MUTE) { - value = ! value; - } - if (portControl->controlType == CONTROL_TYPE_MUTE || - portControl->controlType == CONTROL_TYPE_SELECT) { - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_set_playback_switch_all(portControl->elem, value); - } else { - snd_mixer_selem_set_capture_switch_all(portControl->elem, value); - } - } else { - ERROR1("PORT_SetIntValue(): inappropriate control type: %s\n", - portControl->controlType); - } - } -} - - -static float scaleVolumeValueToNormalized(long value, long min, long max) { - return (float) (value - min) / getRange(min, max); -} - - -static long scaleVolumeValueToHardware(float value, long min, long max) { - return (long)(value * getRange(min, max) + min); -} - - -float getRealVolume(PortControl* portControl, - snd_mixer_selem_channel_id_t channel) { - float fValue; - long lValue = 0; - long min = 0; - long max = 0; - - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_volume_range(portControl->elem, - &min, &max); - snd_mixer_selem_get_playback_volume(portControl->elem, - channel, &lValue); - } else { - snd_mixer_selem_get_capture_volume_range(portControl->elem, - &min, &max); - snd_mixer_selem_get_capture_volume(portControl->elem, - channel, &lValue); - } - fValue = scaleVolumeValueToNormalized(lValue, min, max); - return fValue; -} - - -void setRealVolume(PortControl* portControl, - snd_mixer_selem_channel_id_t channel, float value) { - long lValue = 0; - long min = 0; - long max = 0; - - if (isPlaybackFunction(portControl->portType)) { - snd_mixer_selem_get_playback_volume_range(portControl->elem, - &min, &max); - lValue = scaleVolumeValueToHardware(value, min, max); - snd_mixer_selem_set_playback_volume(portControl->elem, - channel, lValue); - } else { - snd_mixer_selem_get_capture_volume_range(portControl->elem, - &min, &max); - lValue = scaleVolumeValueToHardware(value, min, max); - snd_mixer_selem_set_capture_volume(portControl->elem, - channel, lValue); - } -} - - -static float getFakeBalance(PortControl* portControl) { - float volL, volR; - - // pan is the ratio of left and right - volL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); - volR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); - if (volL > volR) { - return -1.0f + (volR / volL); - } - else if (volR > volL) { - return 1.0f - (volL / volR); - } - return 0.0f; -} - - -static float getFakeVolume(PortControl* portControl) { - float valueL; - float valueR; - float value; - - valueL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT); - valueR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT); - // volume is the greater value of both - value = valueL > valueR ? valueL : valueR ; - return value; -} - - -/* - * sets the unsigned values for left and right volume according to - * the given volume (0...1) and balance (-1..0..+1) - */ -static void setFakeVolume(PortControl* portControl, float vol, float bal) { - float volumeLeft; - float volumeRight; - - if (bal < 0.0f) { - volumeLeft = vol; - volumeRight = vol * (bal + 1.0f); - } else { - volumeLeft = vol * (1.0f - bal); - volumeRight = vol; - } - setRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT, volumeLeft); - setRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT, volumeRight); -} - - -float PORT_GetFloatValue(void* controlIDV) { - PortControl* portControl = (PortControl*) controlIDV; - float value = 0.0F; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_VOLUME) { - switch (portControl->channel) { - case CHANNELS_MONO: - value = getRealVolume(portControl, SND_MIXER_SCHN_MONO); - break; - - case CHANNELS_STEREO: - value = getFakeVolume(portControl); - break; - - default: - value = getRealVolume(portControl, portControl->channel); - } - } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { - if (portControl->channel == CHANNELS_STEREO) { - value = getFakeBalance(portControl); - } else { - ERROR0("PORT_GetFloatValue(): Balance only allowed for stereo channels!\n"); - } - } else { - ERROR1("PORT_GetFloatValue(): inappropriate control type: %s!\n", - portControl->controlType); - } - } - return value; -} - - -void PORT_SetFloatValue(void* controlIDV, float value) { - PortControl* portControl = (PortControl*) controlIDV; - - if (portControl != NULL) { - if (portControl->controlType == CONTROL_TYPE_VOLUME) { - switch (portControl->channel) { - case CHANNELS_MONO: - setRealVolume(portControl, SND_MIXER_SCHN_MONO, value); - break; - - case CHANNELS_STEREO: - setFakeVolume(portControl, value, getFakeBalance(portControl)); - break; - - default: - setRealVolume(portControl, portControl->channel, value); - } - } else if (portControl->controlType == CONTROL_TYPE_BALANCE) { - if (portControl->channel == CHANNELS_STEREO) { - setFakeVolume(portControl, getFakeVolume(portControl), value); - } else { - ERROR0("PORT_SetFloatValue(): Balance only allowed for stereo channels!\n"); - } - } else { - ERROR1("PORT_SetFloatValue(): inappropriate control type: %s!\n", - portControl->controlType); - } - } -} - - -#endif // USE_PORTS diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_PCM.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_PCM.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,600 +0,0 @@ -/* - * Copyright (c) 2002, 2016, 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 "Ports.h" -#include "PLATFORM_API_SolarisOS_Utils.h" - -#if USE_PORTS == TRUE - -#define MONITOR_GAIN_STRING "Monitor Gain" - -#define ALL_TARGET_PORT_COUNT 6 - -// define the following to not use audio_prinfo_t.mod_ports -#define SOLARIS7_COMPATIBLE - -// Solaris audio defines -static int targetPorts[ALL_TARGET_PORT_COUNT] = { - AUDIO_SPEAKER, - AUDIO_HEADPHONE, - AUDIO_LINE_OUT, - AUDIO_AUX1_OUT, - AUDIO_AUX2_OUT, - AUDIO_SPDIF_OUT -}; - -static char* targetPortNames[ALL_TARGET_PORT_COUNT] = { - "Speaker", - "Headphone", - "Line Out", - "AUX1 Out", - "AUX2 Out", - "SPDIF Out" -}; - -// defined in Ports.h -static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = { - PORT_DST_SPEAKER, - PORT_DST_HEADPHONE, - PORT_DST_LINE_OUT, - PORT_DST_UNKNOWN, - PORT_DST_UNKNOWN, - PORT_DST_UNKNOWN, -}; - -#define ALL_SOURCE_PORT_COUNT 7 - -// Solaris audio defines -static int sourcePorts[ALL_SOURCE_PORT_COUNT] = { - AUDIO_MICROPHONE, - AUDIO_LINE_IN, - AUDIO_CD, - AUDIO_AUX1_IN, - AUDIO_AUX2_IN, - AUDIO_SPDIF_IN, - AUDIO_CODEC_LOOPB_IN -}; - -static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = { - "Microphone In", - "Line In", - "Compact Disc In", - "AUX1 In", - "AUX2 In", - "SPDIF In", - "Internal Loopback" -}; - -// Ports.h defines -static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = { - PORT_SRC_MICROPHONE, - PORT_SRC_LINE_IN, - PORT_SRC_COMPACT_DISC, - PORT_SRC_UNKNOWN, - PORT_SRC_UNKNOWN, - PORT_SRC_UNKNOWN, - PORT_SRC_UNKNOWN -}; - -struct tag_PortControlID; - -typedef struct tag_PortInfo { - int fd; // file descriptor of the pseudo device - audio_info_t audioInfo; - // ports - int targetPortCount; - int sourcePortCount; - // indexes to sourcePorts/targetPorts - // contains first target ports, then source ports - int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT]; - // controls - int maxControlCount; // upper bound of number of controls - int usedControlIDs; // number of items already filled in controlIDs - struct tag_PortControlID* controlIDs; // the control IDs themselves -} PortInfo; - -#define PORT_CONTROL_TYPE_PLAY 0x4000000 -#define PORT_CONTROL_TYPE_RECORD 0x8000000 -#define PORT_CONTROL_TYPE_SELECT_PORT 1 -#define PORT_CONTROL_TYPE_GAIN 2 -#define PORT_CONTROL_TYPE_BALANCE 3 -#define PORT_CONTROL_TYPE_MONITOR_GAIN 10 -#define PORT_CONTROL_TYPE_OUTPUT_MUTED 11 -#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD -#define PORT_CONTROL_TYPE_MASK 0xFFFFFF - - -typedef struct tag_PortControlID { - PortInfo* portInfo; - INT32 controlType; // PORT_CONTROL_TYPE_XX - uint_t port; -} PortControlID; - - -///// implemented functions of Ports.h - -INT32 PORT_GetPortMixerCount() { - return (INT32) getAudioDeviceCount(); -} - - -INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { - AudioDeviceDescription desc; - - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { - strncpy(description->name, desc.name, PORT_STRING_LENGTH-1); - description->name[PORT_STRING_LENGTH-1] = 0; - strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1); - description->vendor[PORT_STRING_LENGTH-1] = 0; - strncpy(description->version, desc.version, PORT_STRING_LENGTH-1); - description->version[PORT_STRING_LENGTH-1] = 0; - /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/ - strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1); - description->description[PORT_STRING_LENGTH-1] = 0; - return TRUE; - } - return FALSE; -} - - -void* PORT_Open(INT32 mixerIndex) { - PortInfo* info = NULL; - int fd = -1; - AudioDeviceDescription desc; - int success = FALSE; - - TRACE0("PORT_Open\n"); - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { - fd = open(desc.pathctl, O_RDWR); - } - if (fd < 0) { - ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); - return NULL; - } - - info = (PortInfo*) malloc(sizeof(PortInfo)); - if (info != NULL) { - memset(info, 0, sizeof(PortInfo)); - info->fd = fd; - success = TRUE; - } - if (!success) { - if (fd >= 0) { - close(fd); - } - PORT_Close((void*) info); - info = NULL; - } - return info; -} - -void PORT_Close(void* id) { - TRACE0("PORT_Close\n"); - if (id != NULL) { - PortInfo* info = (PortInfo*) id; - if (info->fd >= 0) { - close(info->fd); - info->fd = -1; - } - if (info->controlIDs) { - free(info->controlIDs); - info->controlIDs = NULL; - } - free(info); - } -} - - - -INT32 PORT_GetPortCount(void* id) { - int ret = 0; - PortInfo* info = (PortInfo*) id; - if (info != NULL) { - if (!info->targetPortCount && !info->sourcePortCount) { - int i; - AUDIO_INITINFO(&info->audioInfo); - if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) { - for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) { - if (info->audioInfo.play.avail_ports & targetPorts[i]) { - info->ports[info->targetPortCount] = i; - info->targetPortCount++; - } -#ifdef SOLARIS7_COMPATIBLE - TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i], - info->audioInfo.play.avail_ports & targetPorts[i]); -#else - TRACE4("Target %d %s: avail=%d mod=%d\n", i, targetPortNames[i], - info->audioInfo.play.avail_ports & targetPorts[i], - info->audioInfo.play.mod_ports & targetPorts[i]); -#endif - } - for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) { - if (info->audioInfo.record.avail_ports & sourcePorts[i]) { - info->ports[info->targetPortCount + info->sourcePortCount] = i; - info->sourcePortCount++; - } -#ifdef SOLARIS7_COMPATIBLE - TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i], - info->audioInfo.record.avail_ports & sourcePorts[i]); -#else - TRACE4("Source %d %s: avail=%d mod=%d\n", i, sourcePortNames[i], - info->audioInfo.record.avail_ports & sourcePorts[i], - info->audioInfo.record.mod_ports & sourcePorts[i]); -#endif - } - } - } - ret = info->targetPortCount + info->sourcePortCount; - } - return ret; -} - -int isSourcePort(PortInfo* info, INT32 portIndex) { - return (portIndex >= info->targetPortCount); -} - -INT32 PORT_GetPortType(void* id, INT32 portIndex) { - PortInfo* info = (PortInfo*) id; - if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { - if (isSourcePort(info, portIndex)) { - return sourcePortJavaSoundMapping[info->ports[portIndex]]; - } else { - return targetPortJavaSoundMapping[info->ports[portIndex]]; - } - } - return 0; -} - -// pre-condition: portIndex must have been verified! -char* getPortName(PortInfo* info, INT32 portIndex) { - char* ret = NULL; - - if (isSourcePort(info, portIndex)) { - ret = sourcePortNames[info->ports[portIndex]]; - } else { - ret = targetPortNames[info->ports[portIndex]]; - } - return ret; -} - -INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { - PortInfo* info = (PortInfo*) id; - char* n; - - if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { - n = getPortName(info, portIndex); - if (n) { - strncpy(name, n, len-1); - name[len-1] = 0; - return TRUE; - } - } - return FALSE; -} - -void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex, - INT32 type, void** controlObjects, int* controlCount) { - PortControlID* controlID; - void* newControl = NULL; - int controlIndex; - char* jsType = NULL; - int isBoolean = FALSE; - - TRACE0(">createPortControl\n"); - - // fill the ControlID structure and add this control - if (info->usedControlIDs >= info->maxControlCount) { - ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount); - return; - } - controlID = &(info->controlIDs[info->usedControlIDs]); - controlID->portInfo = info; - controlID->controlType = type; - controlIndex = info->ports[portIndex]; - if (isSourcePort(info, portIndex)) { - controlID->port = sourcePorts[controlIndex]; - } else { - controlID->port = targetPorts[controlIndex]; - } - switch (type & PORT_CONTROL_TYPE_MASK) { - case PORT_CONTROL_TYPE_SELECT_PORT: - jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break; - case PORT_CONTROL_TYPE_GAIN: - jsType = CONTROL_TYPE_VOLUME; break; - case PORT_CONTROL_TYPE_BALANCE: - jsType = CONTROL_TYPE_BALANCE; break; - case PORT_CONTROL_TYPE_MONITOR_GAIN: - jsType = CONTROL_TYPE_VOLUME; break; - case PORT_CONTROL_TYPE_OUTPUT_MUTED: - jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break; - } - if (isBoolean) { - TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n"); - newControl = (creator->newBooleanControl)(creator, controlID, jsType); - } - else if (jsType == CONTROL_TYPE_BALANCE) { - TRACE0(" PORT_CONTROL_TYPE_BALANCE\n"); - newControl = (creator->newFloatControl)(creator, controlID, jsType, - -1.0f, 1.0f, 2.0f / 65.0f, ""); - } else { - TRACE0(" PORT_CONTROL_TYPE_FLOAT\n"); - newControl = (creator->newFloatControl)(creator, controlID, jsType, - 0.0f, 1.0f, 1.0f / 256.0f, ""); - } - if (newControl) { - controlObjects[*controlCount] = newControl; - (*controlCount)++; - info->usedControlIDs++; - } - TRACE0("addCompoundControl %d controls\n", *controlCount); - if (*controlCount) { - // create compound control and add it to the vector - compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount); - if (compControl) { - TRACE1(" addCompoundControl: calling addControl %p\n", compControl); - (creator->addControl)(creator, compControl); - } - *controlCount = 0; - } - TRACE0("addAllControl\n"); - // go through all controls and add them to the vector - for (i = 0; i < *controlCount; i++) { - (creator->addControl)(creator, controlObjects[i]); - } - *controlCount = 0; - TRACE0("PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", - id, portIndex, info->controlIDs, info->maxControlCount); - if ((portIndex >= 0) && (portIndex < portCount)) { - // if the memory isn't reserved for the control structures, allocate it - if (!info->controlIDs) { - int maxCount = 0; - TRACE0("getControl: allocate mem\n"); - // get a maximum number of controls: - // each port has a select, balance, and volume control. - maxCount = 3 * portCount; - // then there is monitorGain and outputMuted - maxCount += (2 * info->targetPortCount); - info->maxControlCount = maxCount; - info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount); - } - if (!isSourcePort(info, portIndex)) { - type = PORT_CONTROL_TYPE_PLAY; - // add master mute control - createPortControl(info, creator, portIndex, - type | PORT_CONTROL_TYPE_OUTPUT_MUTED, - controls, &controlCount); - addAllControls(info, creator, controls, &controlCount); -#ifdef SOLARIS7_COMPATIBLE - selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]]; -#else - selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]]; -#endif - } else { - type = PORT_CONTROL_TYPE_RECORD; -#ifdef SOLARIS7_COMPATIBLE - selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]]; -#else - selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]]; -#endif - } - // add a mixer strip with volume, ... - createPortControl(info, creator, portIndex, - type | PORT_CONTROL_TYPE_GAIN, - controls, &controlCount); - // ... balance, ... - createPortControl(info, creator, portIndex, - type | PORT_CONTROL_TYPE_BALANCE, - controls, &controlCount); - // ... and select control (if not always on)... - if (selectable) { - createPortControl(info, creator, portIndex, - type | PORT_CONTROL_TYPE_SELECT_PORT, - controls, &controlCount); - } - // ... packaged in a compound control. - addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount); - - if (type == PORT_CONTROL_TYPE_PLAY) { - // add a single strip for source ports with monitor gain - createPortControl(info, creator, portIndex, - type | PORT_CONTROL_TYPE_MONITOR_GAIN, - controls, &controlCount); - // also in a compound control - addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount); - } - } - TRACE0("< PORT_getControls\n"); -} - -INT32 PORT_GetIntValue(void* controlIDV) { - PortControlID* controlID = (PortControlID*) controlIDV; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - - AUDIO_INITINFO(&audioInfo); - if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { - if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { - case PORT_CONTROL_TYPE_SELECT_PORT: - return (prinfo->port & controlID->port)?TRUE:FALSE; - case PORT_CONTROL_TYPE_OUTPUT_MUTED: - return (audioInfo.output_muted)?TRUE:FALSE; - default: - ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); - } - } - ERROR0("PORT_GetIntValue: Could not ioctl!\n"); - return 0; -} - -void PORT_SetIntValue(void* controlIDV, INT32 value) { - PortControlID* controlID = (PortControlID*) controlIDV; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int setPort; - - if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { - case PORT_CONTROL_TYPE_SELECT_PORT: - // first try to just add this port. if that fails, set ONLY to this port. - AUDIO_INITINFO(&audioInfo); - if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { - if (value) { - setPort = (prinfo->port | controlID->port); - } else { - setPort = (prinfo->port - controlID->port); - } - AUDIO_INITINFO(&audioInfo); - prinfo->port = setPort; - if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { - // didn't work. Either this line doesn't support to select several - // ports at once (e.g. record), or a real error - if (value) { - // set to ONLY this port (and disable any other currently selected ports) - AUDIO_INITINFO(&audioInfo); - prinfo->port = controlID->port; - if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { - ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port); - } - } else { - // assume it's an error - ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort); - } - } - break; - case PORT_CONTROL_TYPE_OUTPUT_MUTED: - AUDIO_INITINFO(&audioInfo); - audioInfo.output_muted = (value?TRUE:FALSE); - if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { - ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value); - } - break; - default: - ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); - } - } -} - -float PORT_GetFloatValue(void* controlIDV) { - PortControlID* controlID = (PortControlID*) controlIDV; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - - AUDIO_INITINFO(&audioInfo); - if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { - if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { - case PORT_CONTROL_TYPE_GAIN: - return ((float) (prinfo->gain - AUDIO_MIN_GAIN)) - / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); - case PORT_CONTROL_TYPE_BALANCE: - return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1)) - / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE)); - case PORT_CONTROL_TYPE_MONITOR_GAIN: - return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN)) - / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); - default: - ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); - } - } - ERROR0("PORT_GetFloatValue: Could not ioctl!\n"); - return 0.0f; -} - -void PORT_SetFloatValue(void* controlIDV, float value) { - PortControlID* controlID = (PortControlID*) controlIDV; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - - AUDIO_INITINFO(&audioInfo); - - if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { - case PORT_CONTROL_TYPE_GAIN: - prinfo->gain = AUDIO_MIN_GAIN - + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); - break; - case PORT_CONTROL_TYPE_BALANCE: - prinfo->balance = AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE - + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f); - break; - case PORT_CONTROL_TYPE_MONITOR_GAIN: - audioInfo.monitor_gain = AUDIO_MIN_GAIN - + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); - break; - default: - ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); - return; - } - if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { - ERROR0("PORT_SetFloatValue: Could not ioctl!\n"); - } -} - -#endif // USE_PORTS diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.c --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.c Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - * 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 - 1] = 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; -} diff -r 6e2d71029781 -r 148e29df1644 src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.h --- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.h Fri Mar 23 09:26:59 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2002, 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. - */ - -#include -#include -#include -#include -/* does not work on Solaris 2.7 */ -#include -#include -#include -#ifndef __linux__ -#include -#endif -#include -#include -#include - -#ifndef PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED -#define PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED - -/* defines for Solaris 2.7 - #ifndef AUDIO_AUX1_OUT - #define AUDIO_AUX1_OUT (0x08) // output to aux1 out - #define AUDIO_AUX2_OUT (0x10) // output to aux2 out - #define AUDIO_SPDIF_OUT (0x20) // output to SPDIF port - #define AUDIO_AUX1_IN (0x08) // input from aux1 in - #define AUDIO_AUX2_IN (0x10) // input from aux2 in - #define AUDIO_SPDIF_IN (0x20) // input from SPDIF port - #endif -*/ - -/* input from Codec inter. loopback */ -#ifndef AUDIO_CODEC_LOOPB_IN -#define AUDIO_CODEC_LOOPB_IN (0x40) -#endif - - -#define MAX_NAME_LENGTH 300 - -typedef struct tag_AudioDevicePath { - char path[MAX_NAME_LENGTH]; - ino_t st_ino; // inode number to detect duplicate devices - dev_t st_dev; // device ID to detect duplicate audio devices -} AudioDevicePath; - -typedef struct tag_AudioDeviceDescription { - INT32 maxSimulLines; - char path[MAX_NAME_LENGTH+1]; - char pathctl[MAX_NAME_LENGTH+4]; - char name[MAX_NAME_LENGTH+1]; - char vendor[MAX_NAME_LENGTH+1]; - char version[MAX_NAME_LENGTH+1]; - char description[MAX_NAME_LENGTH+1]; -} AudioDeviceDescription; - -int getAudioDeviceCount(); - -/* - * adPath is an array of AudioDevicePath structures - * count contains initially the number of elements in adPath - * and will be set to the returned number of paths. - */ -void getAudioDevices(AudioDevicePath* adPath, int* count); - -/* - * fills adDesc from the audio device given in path - * returns 0 if an error occurred - * if getNames is 0, only path and pathctl are filled - */ -int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames); -int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames); - - -#endif // PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED