--- old/make/lib/SoundLibraries.gmk 2018-03-15 02:00:34.702586602 +0100 +++ new/make/lib/SoundLibraries.gmk 2018-03-15 02:00:34.486586603 +0100 @@ -23,60 +23,55 @@ # 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 \ + $(TOPDIR)/src/java.desktop/share/native/common/sound \ + $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/common/sound \ + ) + +ifeq ($(OPENJDK_TARGET_OS), windows) + LIBJSOUND_SRC_DIRS += \ + $(TOPDIR)/src/java.desktop/share/native/common/midi_port \ + # +endif # OPENJDK_TARGET_OS windows + +ifeq ($(OPENJDK_TARGET_OS), macosx) + LIBJSOUND_SRC_DIRS += \ + $(TOPDIR)/src/java.desktop/share/native/common/midi_port \ + $(TOPDIR)/src/java.desktop/share/native/common/directaudio \ + # +endif # OPENJDK_TARGET_OS macosx + +ifeq ($(OPENJDK_TARGET_OS), solaris) + LIBJSOUND_SRC_DIRS += \ + $(TOPDIR)/src/java.desktop/share/native/common/midi_port \ + $(TOPDIR)/src/java.desktop/share/native/common/directaudio \ + # +endif # OPENJDK_TARGET_OS solaris + LIBJSOUND_CFLAGS := \ -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ $(LIBJAVA_HEADER_FLAGS) \ $(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \ # -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 - 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) + -DUSE_PORTS=TRUE \ + -DEXTRA_SOUND_JNI_LIBS='"jsoundds"' endif # OPENJDK_TARGET_OS windows ifeq ($(OPENJDK_TARGET_OS), linux) - EXTRA_SOUND_JNI_LIBS += jsoundalsa - LIBJSOUND_CFLAGS += -DX_PLATFORM=X_LINUX + LIBJSOUND_CFLAGS += -DX_PLATFORM=X_LINUX \ + -DEXTRA_SOUND_JNI_LIBS='"jsoundalsa"' endif # OPENJDK_TARGET_OS linux ifeq ($(OPENJDK_TARGET_OS), aix) - LIBJSOUND_CFLAGS += -DX_PLATFORM=X_AIX + LIBJSOUND_CFLAGS += -DX_PLATFORM=X_AIX \ + -DEXTRA_SOUND_JNI_LIBS='""' endif # OPENJDK_TARGET_OS aix ifeq ($(OPENJDK_TARGET_OS), macosx) @@ -85,39 +80,20 @@ -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) + -DUSE_PLATFORM_MIDI_IN=TRUE \ + -DEXTRA_SOUND_JNI_LIBS='""' endif # OPENJDK_TARGET_OS macosx 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) + -DUSE_DAUDIO=TRUE \ + -DEXTRA_SOUND_JNI_LIBS='""' endif # OPENJDK_TARGET_OS solaris -LIBJSOUND_CFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"' - $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUND, \ NAME := jsound, \ SRC := $(LIBJSOUND_SRC_DIRS), \ - INCLUDE_FILES := $(LIBJSOUND_SRC_FILES), \ TOOLCHAIN := $(LIBJSOUND_TOOLCHAIN), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ @@ -128,8 +104,8 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -ljava -ljvm, \ LIBS_macosx := -framework CoreAudio -framework CoreFoundation \ - -framework CoreServices -framework AudioUnit $(LIBCXX) \ - -framework CoreMIDI -framework AudioToolbox, \ + -framework CoreServices -framework AudioUnit \ + -framework CoreMIDI -framework AudioToolbox $(LIBCXX), \ LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib winmm.lib, \ )) @@ -139,23 +115,30 @@ ########################################################################################## -ifneq ($(filter jsoundalsa, $(EXTRA_SOUND_JNI_LIBS)), ) +ifeq ($(OPENJDK_TARGET_OS), linux) + + BUILD_LIBJSOUNDALSA_SRC_DIRS := \ + $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libjsoundalsa \ + $(TOPDIR)/src/java.desktop/share/native/common/midi_port \ + $(TOPDIR)/src/java.desktop/share/native/common/directaudio \ + $(TOPDIR)/src/java.desktop/share/native/common/sound \ + # + + LIBJSOUNDALSA_INCLUDES := \ + -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ + $(LIBJAVA_HEADER_FLAGS) \ + $(foreach dir, $(BUILD_LIBJSOUNDALSA_SRC_DIRS), -I$(dir)) \ + # + + LIBJSOUNDALSA_CFLAGS += -DX_PLATFORM=X_LINUX \ + -DEXTRA_SOUND_JNI_LIBS='"jsoundalsa"' $(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, \ + SRC := $(BUILD_LIBJSOUNDALSA_SRC_DIRS), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \ - $(LIBJSOUND_CFLAGS) \ + $(LIBJSOUNDALSA_INCLUDES) $(LIBJSOUNDALSA_CFLAGS) \ -DUSE_DAUDIO=TRUE \ -DUSE_PORTS=TRUE \ -DUSE_PLATFORM_MIDI_OUT=TRUE \ @@ -174,17 +157,33 @@ ########################################################################################## -ifneq ($(filter jsoundds, $(EXTRA_SOUND_JNI_LIBS)), ) +ifeq ($(OPENJDK_TARGET_OS), windows) + + BUILD_LIBJSOUNDDS_SRC_DIRS := \ + $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libjsoundds \ + $(TOPDIR)/src/java.desktop/share/native/common/directaudio \ + $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/common/sound \ + $(TOPDIR)/src/java.desktop/share/native/common/sound \ + # + + LIBJSOUNDDS_INCLUDES := \ + -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ + $(LIBJAVA_HEADER_FLAGS) \ + $(foreach dir, $(BUILD_LIBJSOUNDDS_SRC_DIRS), -I$(dir)) \ + # + + LIBJSOUNDDS_CFLAGS += -DX_PLATFORM=X_WINDOWS \ + -DUSE_PLATFORM_MIDI_OUT=TRUE \ + -DUSE_PLATFORM_MIDI_IN=TRUE \ + -DUSE_PORTS=TRUE \ + -DEXTRA_SOUND_JNI_LIBS='"jsoundds"' $(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, \ + SRC := $(BUILD_LIBJSOUNDDS_SRC_DIRS), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ - $(LIBJSOUND_CFLAGS) \ + $(LIBJSOUNDDS_INCLUDES) $(LIBJSOUNDDS_CFLAGS) \ -DUSE_DAUDIO=TRUE, \ LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c 2018-03-15 02:00:35.502586596 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c 2018-03-15 02:00:35.186586598 +0100 @@ -0,0 +1,182 @@ +/* + * 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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h 2018-03-15 02:00:35.970586592 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h 2018-03-15 02:00:35.658586594 +0100 @@ -0,0 +1,82 @@ +/* + * 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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiIn.c 2018-03-15 02:00:36.446586589 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiIn.c 2018-03-15 02:00:36.150586591 +0100 @@ -0,0 +1,354 @@ +/* + * 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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiOut.c 2018-03-15 02:00:36.910586585 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiOut.c 2018-03-15 02:00:36.602586588 +0100 @@ -0,0 +1,179 @@ +/* + * 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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c 2018-03-15 02:00:37.430586581 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c 2018-03-15 02:00:37.094586584 +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_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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h 2018-03-15 02:00:37.922586578 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h 2018-03-15 02:00:37.618586580 +0100 @@ -0,0 +1,85 @@ +/* + * 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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCM.c 2018-03-15 02:00:38.386586574 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCM.c 2018-03-15 02:00:38.098586576 +0100 @@ -0,0 +1,941 @@ +/* + * 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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c 2018-03-15 02:00:38.894586571 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c 2018-03-15 02:00:38.574586573 +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_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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h 2018-03-15 02:00:39.410586567 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h 2018-03-15 02:00:39.074586569 +0100 @@ -0,0 +1,73 @@ +/* + * 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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c 2018-03-15 02:00:39.898586563 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/bsd/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c 2018-03-15 02:00:39.594586565 +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_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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c 2018-03-15 02:00:40.378586560 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c 2018-03-15 02:00:40.090586562 +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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h 2018-03-15 02:00:40.854586556 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h 2018-03-15 02:00:40.542586558 +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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c 2018-03-15 02:00:41.330586553 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_MidiIn.c 2018-03-15 02:00:41.006586555 +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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c 2018-03-15 02:00:41.798586549 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_MidiOut.c 2018-03-15 02:00:41.514586551 +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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c 2018-03-15 02:00:42.306586545 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c 2018-03-15 02:00:41.978586548 +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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h 2018-03-15 02:00:42.806586542 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h 2018-03-15 02:00:42.490586544 +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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c 2018-03-15 02:00:43.306586538 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_PCM.c 2018-03-15 02:00:42.990586540 +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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c 2018-03-15 02:00:43.818586534 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 */ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c 2018-03-15 02:00:43.494586537 +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 */ --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h 2018-03-15 02:00:44.306586531 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h 2018-03-15 02:00:43.998586533 +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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c 2018-03-15 02:00:44.802586527 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/linux/native/libjsoundalsa/PLATFORM_API_LinuxOS_ALSA_Ports.c 2018-03-15 02:00:44.486586529 +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 --- old/src/java.desktop/share/native/libjsound/DirectAudio.h 2018-03-15 02:00:45.278586524 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,102 +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. - */ - -#ifndef DIRECT_AUDIO_INCLUDED -#define DIRECT_AUDIO_INCLUDED - -// includes for types -#include "SoundDefs.h" - -// for memset -#include - -#include "Utilities.h" - -// the following defines should match the ones in AbstractMixer.java -#define DAUDIO_PCM 0 -#define DAUDIO_ULAW 1 -#define DAUDIO_ALAW 2 - -#define DAUDIO_STRING_LENGTH 200 - -typedef struct tag_DirectAudioDeviceDescription { - // optional deviceID (complementary to deviceIndex) - INT32 deviceID; - INT32 maxSimulLines; - char name[DAUDIO_STRING_LENGTH+1]; - char vendor[DAUDIO_STRING_LENGTH+1]; - char description[DAUDIO_STRING_LENGTH+1]; - char version[DAUDIO_STRING_LENGTH+1]; -} DirectAudioDeviceDescription; - - -// method definitions - -#if (USE_DAUDIO == TRUE) - -// callback from GetFormats, implemented in DirectAudioDevice.c -void DAUDIO_AddAudioFormat(void* creator, int significantBits, int frameSizeInBytes, - int channels, float sampleRate, - int encoding, int isSigned, - int bigEndian); - - -// the following methods need to be implemented by the platform dependent code - -/* returns the number of mixer devices */ -INT32 DAUDIO_GetDirectAudioDeviceCount(); - -/* returns TRUE on success, FALSE otherwise */ -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, - DirectAudioDeviceDescription* description); - -// SourceDataLine and TargetDataLine - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator); - -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 DAUDIO_Start(void* id, int isSource); -int DAUDIO_Stop(void* id, int isSource); -void DAUDIO_Close(void* id, int isSource); -int DAUDIO_Write(void* id, char* data, int byteSize); // returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize); // returns -1 on error - -int DAUDIO_GetBufferSize(void* id, int isSource); -int DAUDIO_StillDraining(void* id, int isSource); -int DAUDIO_Flush(void* id, int isSource); -/* in bytes */ -int DAUDIO_GetAvailable(void* id, int isSource); -INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos); -void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos); - -int DAUDIO_RequiresServicing(void* id, int isSource); -void DAUDIO_Service(void* id, int isSource); - -#endif // USE_DAUDIO - -#endif // DIRECT_AUDIO_INCLUDED --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/directaudio/DirectAudio.h 2018-03-15 02:00:44.966586526 +0100 @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#ifndef DIRECT_AUDIO_INCLUDED +#define DIRECT_AUDIO_INCLUDED + +// includes for types +#include "SoundDefs.h" + +// for memset +#include + +#include "Utilities.h" + +// the following defines should match the ones in AbstractMixer.java +#define DAUDIO_PCM 0 +#define DAUDIO_ULAW 1 +#define DAUDIO_ALAW 2 + +#define DAUDIO_STRING_LENGTH 200 + +typedef struct tag_DirectAudioDeviceDescription { + // optional deviceID (complementary to deviceIndex) + INT32 deviceID; + INT32 maxSimulLines; + char name[DAUDIO_STRING_LENGTH+1]; + char vendor[DAUDIO_STRING_LENGTH+1]; + char description[DAUDIO_STRING_LENGTH+1]; + char version[DAUDIO_STRING_LENGTH+1]; +} DirectAudioDeviceDescription; + + +// method definitions + +#if (USE_DAUDIO == TRUE) + +// callback from GetFormats, implemented in DirectAudioDevice.c +void DAUDIO_AddAudioFormat(void* creator, int significantBits, int frameSizeInBytes, + int channels, float sampleRate, + int encoding, int isSigned, + int bigEndian); + + +// the following methods need to be implemented by the platform dependent code + +/* returns the number of mixer devices */ +INT32 DAUDIO_GetDirectAudioDeviceCount(); + +/* returns TRUE on success, FALSE otherwise */ +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, + DirectAudioDeviceDescription* description); + +// SourceDataLine and TargetDataLine + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator); + +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 DAUDIO_Start(void* id, int isSource); +int DAUDIO_Stop(void* id, int isSource); +void DAUDIO_Close(void* id, int isSource); +int DAUDIO_Write(void* id, char* data, int byteSize); // returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize); // returns -1 on error + +int DAUDIO_GetBufferSize(void* id, int isSource); +int DAUDIO_StillDraining(void* id, int isSource); +int DAUDIO_Flush(void* id, int isSource); +/* in bytes */ +int DAUDIO_GetAvailable(void* id, int isSource); +INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos); +void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos); + +int DAUDIO_RequiresServicing(void* id, int isSource); +void DAUDIO_Service(void* id, int isSource); + +#endif // USE_DAUDIO + +#endif // DIRECT_AUDIO_INCLUDED --- old/src/java.desktop/share/native/libjsound/DirectAudioDevice.c 2018-03-15 02:00:45.786586520 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,821 +0,0 @@ -/* - * Copyright (c) 2002, 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. - */ - -/* TODO: - * - move all the conversion code into an own file - */ - -//#define USE_TRACE -//#define USE_ERROR - - -#include -#include -// for malloc -#ifdef _ALLBSD_SOURCE -#include -#else -#include -#endif -#include "SoundDefs.h" -#include "DirectAudio.h" -#include "Utilities.h" -#include "com_sun_media_sound_DirectAudioDevice.h" - - -typedef struct { - void* handle; - int encoding; - int sampleSizeInBits; - int frameSize; - int channels; - int isSigned; - int isBigEndian; - UINT8* conversionBuffer; - int conversionBufferSize; -} DAUDIO_Info; - - -//////////////////////////////////////////// MAP Conversion stuff ///////////////////////////////// - -/* 16 bit signed sample, native endianness, stored in 32-bits */ -typedef INT32 MAP_Sample; - -static INLINE UINT16 MAP_SWAP16_impl(UINT16 a) { - return (a>>8) | (a<<8); -} - -static INLINE UINT32 MAP_SWAP32_impl(UINT32 a) { - return (a>>24) - | ((a>>8) & 0xFF00) - | ((a<<8) & 0xFF0000) - | (a<<24); -} - -static INLINE UINT32 MAP_SWAP16BIT(UINT32 sh) { - return (UINT32) ((sh & 0xFF) << 8) | ((sh & 0xFF00) >> 8); -} - -static INLINE INT32 MAP_ClipAndConvertToShort(MAP_Sample sample) { - if (sample < -32768) { - return -32768; - } - else if (sample > 32767) { - return 32767; - } - return (INT32) sample; -} - - -static INLINE INT32 MAP_ClipAndConvertToShort_Swapped(MAP_Sample sample) { - if (sample < -32768) { - return 0x0080; - } - else if (sample > 32767) { - return 0xFF7F; - } - return (INT32) (INT16) MAP_SWAP16BIT(sample); -} - -static INLINE INT8 MAP_ClipAndConvertToByte(MAP_Sample sample) { - if (sample < -32768) { - return -128; - } - else if (sample > 32767) { - return 127; - } - return (INT8) (sample >> 8); -} - - -static INLINE UINT8 MAP_ClipAndConvertToUByte(MAP_Sample sample) { - if (sample < -32768) { - return 0; - } - else if (sample > 32767) { - return 255; - } - return (UINT8) ((sample >> 8) + 128); -} - -/* conversion from/to 16 bit signed little endian to native endian samples */ -#ifdef _LITTLE_ENDIAN -#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh)) -#define MAP_SAMPLE2LE_SHORT(sample) (sample) -#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample) -#else -#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh)) -#define MAP_SAMPLE2LE_SHORT(sample) (INT16) MAP_SWAP16BIT(sample) -#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample) -#endif - -/* conversion from/to 16 bit signed big endian to native endian samples */ -#ifndef _LITTLE_ENDIAN -#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh)) -#define MAP_SAMPLE2BE_SHORT(sample) (sample) -#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample) -#else -#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh)) -#define MAP_SAMPLE2BE_SHORT(sample) ((INT16) MAP_SWAP16BIT(sample)) -#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample) -#endif - -/* conversion from/to 8 bit samples */ -#define MAP_INT82SAMPLE(by) ((MAP_Sample) (((INT32) ((INT8) (by))) << 8)) -#define MAP_UINT82SAMPLE(by) ((MAP_Sample) (((INT32) ((UINT8) (by) - 128)) << 8)) -#define MAP_SAMPLE2UINT8(sample) ((UINT8) ((((MAP_Sample) (sample)) >> 8) + 128)) -#define MAP_SAMPLE2INT8(sample) ((INT8) (((MAP_Sample) (sample)) >> 8)) -#define MAP_SAMPLE2UINT8_CLIP(sample) MAP_ClipAndConvertToUByte(sample) -#define MAP_SAMPLE2INT8_CLIP(sample) MAP_ClipAndConvertToByte(sample) - -/* macros for endian conversion */ -#ifdef _LITTLE_ENDIAN -#define MAP_NATIVE2LE16(a) (a) -#define MAP_NATIVE2BE16(a) MAP_SWAP16_impl(a) -#define MAP_NATIVE2LE32(a) (a) -#define MAP_NATIVE2BE32(a) MAP_SWAP32_impl(a) -#else -#define MAP_NATIVE2LE16(a) MAP_SWAP16_impl(a) -#define MAP_NATIVE2BE16(a) (a) -#define MAP_NATIVE2LE32(a) MAP_SWAP32_impl(a) -#define MAP_NATIVE2BE32(a) (a) -#endif -#define MAP_LE2NATIVE16(a) MAP_NATIVE2LE16(a) -#define MAP_BE2NATIVE16(a) MAP_NATIVE2BE16(a) -#define MAP_LE2NATIVE32(a) MAP_NATIVE2LE32(a) -#define MAP_BE2NATIVE32(a) MAP_NATIVE2BE32(a) - - -////////////////////////////// Utility function ///////////////////////////////// - -/* - * conversion of this buffer: - * conversion size=1 -> each byte is converted from signed to unsigned or vice versa - * conversion size=2,3,4: the order of bytes in a sample is reversed (endianness) - * for sign conversion of a 24-bit sample stored in 32bits, 4 should be passed - * as conversionSize - */ -void handleSignEndianConversion(INT8* data, INT8* output, int byteSize, int conversionSize) { - TRACE1("conversion with size %d\n", conversionSize); - switch (conversionSize) { - case 1: { - while (byteSize > 0) { - *output = *data + (char) 128; // use wrap-around - byteSize--; - data++; - output++; - } - break; - } - case 2: { - INT8 h; - byteSize = byteSize / 2; - while (byteSize > 0) { - h = *data; - data++; - *output = *data; - output++; - *output = h; - byteSize--; - data++; output++; - } - break; - } - case 3: { - INT8 h; - byteSize = byteSize / 3; - while (byteSize > 0) { - h = *data; - *output = data[2]; - data++; output++; - *output = *data; - data++; output++; - *output = h; - data++; output++; - byteSize--; - } - break; - } - case 4: { - INT8 h1, h2; - byteSize = byteSize / 4; - while (byteSize > 0) { - h1 = data[0]; - h2 = data[1]; - *output = data[3]; output++; - *output = data[2]; output++; - *output = h2; output++; - *output = h1; output++; - data += 4; - byteSize--; - } - break; - } - default: - ERROR1("DirectAudioDevice.c: wrong conversionSize %d!\n", conversionSize); - } -} - -/* aply the gain to one sample */ -#define CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FACTOR) \ - /* convert to MAP_Sample native type */ \ - sample = TO_SAMPLE(*INPUT); \ - /* apply gain */ \ - sample = (MAP_Sample) (sample * FACTOR); \ - /* convert to output type */ \ - (*OUTPUT) = FROM_SAMPLE(sample); \ - INPUT++; OUTPUT++ - - -/* macro for conversion of a mono block */ -#define LOOP_M(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \ - if (leftGain > 1.0) { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE_CLIP, leftGain); \ - } \ - } else { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE, leftGain); \ - } \ - } \ - break - -/* macro for conversion of a stereo block */ -#define LOOP_S(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \ - if (leftGain > 1.0) { \ - if (rightGain > 1.0) { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE_CLIP, leftGain); \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE_CLIP, rightGain); \ - } \ - } else { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE_CLIP, leftGain); \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE, rightGain); \ - } \ - } \ - } else { \ - if (rightGain > 1.0) { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE, leftGain); \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE_CLIP, rightGain); \ - } \ - } else { \ - for ( ; len > 0; --len) { \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE, leftGain); \ - CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ - FROM_SAMPLE, rightGain); \ - } \ - } \ - } \ - break - -#define FORMAT2CODE(channels, bits, inSigned, outSigned, inBigEndian, outBigEndian) \ - (channels << 20) \ - | (bits << 4) \ - | ((inSigned & 1) << 3) \ - | ((outSigned & 1) << 2) \ - | ((inBigEndian & 1) << 1) \ - | (outBigEndian & 1) - -#define FORMAT2CODE8(channels, inSigned, outSigned) \ - FORMAT2CODE(channels, 8, inSigned, outSigned, 0, 0) - -#define FORMAT2CODE16(channels, inBigEndian, outBigEndian) \ - FORMAT2CODE(channels, 16, 1, 1, inBigEndian, outBigEndian) - - -void handleGainAndConversion(DAUDIO_Info* info, UINT8* input, UINT8* output, - int len, float leftGain, float rightGain, - int conversionSize) { - INT8* input8 = (INT8*) input; - INT8* output8 = (INT8*) output; - INT16* input16 = (INT16*) input; - INT16* output16 = (INT16*) output; - MAP_Sample sample; - - int inIsSigned = info->isSigned; - int inIsBigEndian = info->isBigEndian; - if (conversionSize == 1) { - /* 8-bit conversion: change sign */ - inIsSigned = !inIsSigned; - } - else if (conversionSize > 1) { - /* > 8-bit conversion: change endianness */ - inIsBigEndian = !inIsBigEndian; - } - if (info->frameSize <= 0) { - ERROR1("DirectAudiODevice: invalid framesize=%d\n", info->frameSize); - return; - } - len /= info->frameSize; - TRACE3("handleGainAndConversion: len=%d frames, leftGain=%f, rightGain=%f, ", - len, leftGain, rightGain); - TRACE3("channels=%d, sampleSizeInBits=%d, frameSize=%d, ", - (int) info->channels, (int) info->sampleSizeInBits, (int) info->frameSize); - TRACE4("signed:%d -> %d, endian: %d -> %d", - (int) inIsSigned, (int) info->isSigned, - (int) inIsBigEndian, (int) info->isBigEndian); - TRACE1("convSize=%d\n", conversionSize); - - switch (FORMAT2CODE(info->channels, - info->sampleSizeInBits, - inIsSigned, - info->isSigned, - inIsBigEndian, - info->isBigEndian)) { - /* 8-bit mono */ - case FORMAT2CODE8(1, 0, 0): - LOOP_M(input8, output8, MAP_UINT82SAMPLE, - MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); - case FORMAT2CODE8(1, 0, 1): - LOOP_M(input8, output8, MAP_UINT82SAMPLE, - MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); - case FORMAT2CODE8(1, 1, 0): - LOOP_M(input8, output8, MAP_INT82SAMPLE, - MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); - case FORMAT2CODE8(1, 1, 1): - LOOP_M(input8, output8, MAP_INT82SAMPLE, - MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); - - /* 8-bit stereo */ - case FORMAT2CODE8(2, 0, 0): - LOOP_S(input8, output8, MAP_UINT82SAMPLE, - MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); - case FORMAT2CODE8(2, 0, 1): - LOOP_S(input8, output8, MAP_UINT82SAMPLE, - MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); - case FORMAT2CODE8(2, 1, 0): - LOOP_S(input8, output8, MAP_INT82SAMPLE, - MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); - case FORMAT2CODE8(2, 1, 1): - LOOP_S(input8, output8, MAP_INT82SAMPLE, - MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); - - /* 16-bit mono (only signed is accepted) */ - case FORMAT2CODE16(1, 0, 0): - LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE, - MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); - case FORMAT2CODE16(1, 0, 1): - LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE, - MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); - case FORMAT2CODE16(1, 1, 0): - LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE, - MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); - case FORMAT2CODE16(1, 1, 1): - LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE, - MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); - - /* 16-bit stereo (only signed is accepted) */ - case FORMAT2CODE16(2, 0, 0): - LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE, - MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); - case FORMAT2CODE16(2, 0, 1): - LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE, - MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); - case FORMAT2CODE16(2, 1, 0): - LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE, - MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); - case FORMAT2CODE16(2, 1, 1): - LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE, - MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); - - default: - ERROR3("DirectAudioDevice: Cannot convert from native format: " - "bits=%d, inSigned=%d outSigned=%d, ", - (int) info->sampleSizeInBits, - (int) inIsSigned, (int) info->isSigned); - ERROR2("inBigEndian=%d, outBigEndian=%d\n", - (int) inIsBigEndian, (int) info->isBigEndian); - } -} - -float ABS_VALUE(float a) { - return (a < 0)?-a:a; -} - - -//////////////////////////////////////////// DirectAudioDevice //////////////////////////////////////////// - -/* ************************************** native control creation support ********************* */ - -// contains all the needed references so that the platform dependent code can call JNI wrapper functions -typedef struct tag_AddFormatCreator { - // general JNI variables - JNIEnv *env; - // the vector to be filled with the formats - jobject vector; - // the class containing the addFormat method - jclass directAudioDeviceClass; - // the method to be called to add the format - jmethodID addFormat; // signature (Ljava/util/Vector;IIFIBB)V -} AddFormatCreator; - -void DAUDIO_AddAudioFormat(void* creatorV, int significantBits, int frameSizeInBytes, - int channels, float sampleRate, - int encoding, int isSigned, - int bigEndian) { - AddFormatCreator* creator = (AddFormatCreator*) creatorV; - if (frameSizeInBytes <= 0) { - if (channels > 0) { - frameSizeInBytes = ((significantBits + 7) / 8) * channels; - } else { - frameSizeInBytes = -1; - } - } - TRACE4("AddAudioFormat with sigBits=%d bits, frameSize=%d bytes, channels=%d, sampleRate=%d ", - significantBits, frameSizeInBytes, channels, (int) sampleRate); - TRACE3("enc=%d, signed=%d, bigEndian=%d\n", encoding, isSigned, bigEndian); - (*creator->env)->CallStaticVoidMethod(creator->env, creator->directAudioDeviceClass, - creator->addFormat, creator->vector, significantBits, frameSizeInBytes, - channels, sampleRate, encoding, isSigned, bigEndian); -} - -////////////////////////////////////// JNI ///////////////////////////////////////////////////////////////////// - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nGetFormats - * Signature: (IIZLjava/util/Vector;)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetFormats -(JNIEnv *env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, jobject formats) { - -#if USE_DAUDIO == TRUE - AddFormatCreator creator; - creator.env = env; - creator.vector = formats; - creator.directAudioDeviceClass = clazz; - creator.addFormat = (*env)->GetStaticMethodID(env, clazz, "addFormat", - "(Ljava/util/Vector;IIIFIZZ)V"); - if (creator.addFormat == NULL) { - ERROR0("Could not get method ID for addFormat!\n"); - } else { - DAUDIO_GetFormats((INT32) mixerIndex, (INT32) deviceID, (int) isSource, &creator); - } -#endif -} - - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nOpen - * Signature: (IIZIFIIZZI)J - */ -JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nOpen -(JNIEnv* env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, - jint encoding, jfloat sampleRate, jint sampleSizeInBits, jint frameSize, jint channels, - jboolean isSigned, jboolean isBigendian, jint bufferSizeInBytes) { - - DAUDIO_Info* info = NULL; -#if USE_DAUDIO == TRUE - - info = (DAUDIO_Info*) malloc(sizeof(DAUDIO_Info)); - if (info == NULL) { - ERROR0("DirectAudioDevice_nOpen: Out of memory!\n"); - } else { - info->handle =DAUDIO_Open((int) mixerIndex, (INT32) deviceID, (int) isSource, - (int) encoding, (float) sampleRate, (int) sampleSizeInBits, - (int) frameSize, (int) channels, - (int) isSigned, (int) isBigendian, (int) bufferSizeInBytes); - if (!info->handle) { - free(info); - info = NULL; - } else { - info->encoding = encoding; - info->sampleSizeInBits = sampleSizeInBits; - info->frameSize = frameSize; - info->channels = channels; - info->isSigned = isSigned; - info->isBigEndian = isBigendian && (sampleSizeInBits > 8); - /* will be populated on demand */ - info->conversionBuffer = NULL; - info->conversionBufferSize = 0; - } - } -#endif - return (jlong) (UINT_PTR) info; -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nStart - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStart -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_Start(info->handle, (int) isSource); - } -#endif -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nStop - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStop -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_Stop(info->handle, (int) isSource); - } -#endif -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nClose - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nClose -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_Close(info->handle, (int) isSource); - if (info->conversionBuffer) { - free(info->conversionBuffer); - } - free(info); - } -#endif -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nWrite - * Signature: (J[BII)I - */ -JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nWrite -(JNIEnv *env, jclass clazz, jlong id, jbyteArray jData, - jint offset, jint len, jint conversionSize, jfloat leftGain, jfloat rightGain) { - int ret = -1; -#if USE_DAUDIO == TRUE - UINT8* data; - UINT8* dataOffset; - UINT8* convertedData; - jboolean didCopy; - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - - /* a little sanity */ - if (offset < 0 || len < 0) { - ERROR2("nWrite: wrong parameters: offset=%d, len=%d\n", offset, len); - return ret; - } - if (len == 0) return 0; - if (info && info->handle) { - data = (UINT8*) ((*env)->GetByteArrayElements(env, jData, &didCopy)); - CHECK_NULL_RETURN(data, ret); - dataOffset = data; - dataOffset += (int) offset; - convertedData = dataOffset; - - if (conversionSize > 0 || leftGain != 1.0f || rightGain != 1.0f) { - /* make sure we have a buffer for the intermediate data */ - if (didCopy == JNI_FALSE) { - /* let's do our own copy */ - if (info->conversionBuffer - && info->conversionBufferSize < len) { - free(info->conversionBuffer); - info->conversionBuffer = NULL; - info->conversionBufferSize = 0; - } - if (!info->conversionBuffer) { - info->conversionBuffer = (UINT8*) malloc(len); - if (!info->conversionBuffer) { - // do not commit the native array - (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT); - return -1; - } - info->conversionBufferSize = len; - } - convertedData = info->conversionBuffer; - } - if (((ABS_VALUE(leftGain - 1.0f) < 0.01) - && (ABS_VALUE(rightGain - 1.0f) < 0.01)) - || info->encoding!=DAUDIO_PCM - || ((info->channels * info->sampleSizeInBits / 8) != info->frameSize) - || (info->sampleSizeInBits != 8 && info->sampleSizeInBits != 16)) { - handleSignEndianConversion((INT8*) dataOffset, (INT8*) convertedData, (int) len, - (int) conversionSize); - } else { - handleGainAndConversion(info, dataOffset, convertedData, - (int) len, (float) leftGain, (float) rightGain, - (int) conversionSize); - } - } - - ret = DAUDIO_Write(info->handle, (INT8*) convertedData, (int) len); - - // do not commit the native array - (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT); - } -#endif - return (jint) ret; -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nRead - * Signature: (J[BII)I - */ -JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRead -(JNIEnv* env, jclass clazz, jlong id, jbyteArray jData, jint offset, jint len, jint conversionSize) { - int ret = -1; -#if USE_DAUDIO == TRUE - char* data; - char* dataOffset; - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - - /* a little sanity */ - if (offset < 0 || len < 0) { - ERROR2("nRead: wrong parameters: offset=%d, len=%d\n", offset, len); - return ret; - } - if (info && info->handle) { - data = (char*) ((*env)->GetByteArrayElements(env, jData, NULL)); - CHECK_NULL_RETURN(data, ret); - dataOffset = data; - dataOffset += (int) offset; - ret = DAUDIO_Read(info->handle, dataOffset, (int) len); - if (conversionSize > 0) { - handleSignEndianConversion(dataOffset, dataOffset, (int) len, (int) conversionSize); - } - // commit the native array - (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, 0); - } -#endif - return (jint) ret; -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nGetBufferSize - * Signature: (JZ)I - */ -JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { - int ret = -1; -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - ret = DAUDIO_GetBufferSize(info->handle, (int) isSource); - } -#endif - return (jint) ret; -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nIsStillDraining - * Signature: (JZ)Z - */ -JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { - int ret = FALSE; -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - ret = DAUDIO_StillDraining(info->handle, (int) isSource)?TRUE:FALSE; - } -#endif - return (jboolean) ret; -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nFlush - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nFlush -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_Flush(info->handle, (int) isSource); - } -#endif -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nAvailable - * Signature: (JZ)I - */ -JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nAvailable -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { - int ret = -1; -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - ret = DAUDIO_GetAvailable(info->handle, (int) isSource); - } -#endif - return (jint) ret; -} - - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nGetBytePosition - * Signature: (JZJ)J - */ -JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong javaBytePos) { - INT64 ret = (INT64) javaBytePos; -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - ret = DAUDIO_GetBytePosition(info->handle, (int) isSource, (INT64) javaBytePos); - } -#endif - return (jlong) ret; -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nSetBytePosition - * Signature: (JZJ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong pos) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_SetBytePosition(info->handle, (int) isSource, (INT64) pos); - } -#endif -} - -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nRequiresServicing - * Signature: (JZ)B - */ -JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { - int ret = FALSE; -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - ret = DAUDIO_RequiresServicing(info->handle, (int) isSource); - } -#endif - return (jboolean) ret; -} -/* - * Class: com_sun_media_sound_DirectAudioDevice - * Method: nService - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nService -(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { -#if USE_DAUDIO == TRUE - DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; - if (info && info->handle) { - DAUDIO_Service(info->handle, (int) isSource); - } -#endif -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/directaudio/DirectAudioDevice.c 2018-03-15 02:00:45.470586522 +0100 @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2002, 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. + */ + +/* TODO: + * - move all the conversion code into an own file + */ + +//#define USE_TRACE +//#define USE_ERROR + + +#include +#include +// for malloc +#ifdef _ALLBSD_SOURCE +#include +#else +#include +#endif +#include "SoundDefs.h" +#include "DirectAudio.h" +#include "Utilities.h" +#include "com_sun_media_sound_DirectAudioDevice.h" + + +typedef struct { + void* handle; + int encoding; + int sampleSizeInBits; + int frameSize; + int channels; + int isSigned; + int isBigEndian; + UINT8* conversionBuffer; + int conversionBufferSize; +} DAUDIO_Info; + + +//////////////////////////////////////////// MAP Conversion stuff ///////////////////////////////// + +/* 16 bit signed sample, native endianness, stored in 32-bits */ +typedef INT32 MAP_Sample; + +static INLINE UINT16 MAP_SWAP16_impl(UINT16 a) { + return (a>>8) | (a<<8); +} + +static INLINE UINT32 MAP_SWAP32_impl(UINT32 a) { + return (a>>24) + | ((a>>8) & 0xFF00) + | ((a<<8) & 0xFF0000) + | (a<<24); +} + +static INLINE UINT32 MAP_SWAP16BIT(UINT32 sh) { + return (UINT32) ((sh & 0xFF) << 8) | ((sh & 0xFF00) >> 8); +} + +static INLINE INT32 MAP_ClipAndConvertToShort(MAP_Sample sample) { + if (sample < -32768) { + return -32768; + } + else if (sample > 32767) { + return 32767; + } + return (INT32) sample; +} + + +static INLINE INT32 MAP_ClipAndConvertToShort_Swapped(MAP_Sample sample) { + if (sample < -32768) { + return 0x0080; + } + else if (sample > 32767) { + return 0xFF7F; + } + return (INT32) (INT16) MAP_SWAP16BIT(sample); +} + +static INLINE INT8 MAP_ClipAndConvertToByte(MAP_Sample sample) { + if (sample < -32768) { + return -128; + } + else if (sample > 32767) { + return 127; + } + return (INT8) (sample >> 8); +} + + +static INLINE UINT8 MAP_ClipAndConvertToUByte(MAP_Sample sample) { + if (sample < -32768) { + return 0; + } + else if (sample > 32767) { + return 255; + } + return (UINT8) ((sample >> 8) + 128); +} + +/* conversion from/to 16 bit signed little endian to native endian samples */ +#ifdef _LITTLE_ENDIAN +#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh)) +#define MAP_SAMPLE2LE_SHORT(sample) (sample) +#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample) +#else +#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh)) +#define MAP_SAMPLE2LE_SHORT(sample) (INT16) MAP_SWAP16BIT(sample) +#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample) +#endif + +/* conversion from/to 16 bit signed big endian to native endian samples */ +#ifndef _LITTLE_ENDIAN +#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh)) +#define MAP_SAMPLE2BE_SHORT(sample) (sample) +#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample) +#else +#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh)) +#define MAP_SAMPLE2BE_SHORT(sample) ((INT16) MAP_SWAP16BIT(sample)) +#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample) +#endif + +/* conversion from/to 8 bit samples */ +#define MAP_INT82SAMPLE(by) ((MAP_Sample) (((INT32) ((INT8) (by))) << 8)) +#define MAP_UINT82SAMPLE(by) ((MAP_Sample) (((INT32) ((UINT8) (by) - 128)) << 8)) +#define MAP_SAMPLE2UINT8(sample) ((UINT8) ((((MAP_Sample) (sample)) >> 8) + 128)) +#define MAP_SAMPLE2INT8(sample) ((INT8) (((MAP_Sample) (sample)) >> 8)) +#define MAP_SAMPLE2UINT8_CLIP(sample) MAP_ClipAndConvertToUByte(sample) +#define MAP_SAMPLE2INT8_CLIP(sample) MAP_ClipAndConvertToByte(sample) + +/* macros for endian conversion */ +#ifdef _LITTLE_ENDIAN +#define MAP_NATIVE2LE16(a) (a) +#define MAP_NATIVE2BE16(a) MAP_SWAP16_impl(a) +#define MAP_NATIVE2LE32(a) (a) +#define MAP_NATIVE2BE32(a) MAP_SWAP32_impl(a) +#else +#define MAP_NATIVE2LE16(a) MAP_SWAP16_impl(a) +#define MAP_NATIVE2BE16(a) (a) +#define MAP_NATIVE2LE32(a) MAP_SWAP32_impl(a) +#define MAP_NATIVE2BE32(a) (a) +#endif +#define MAP_LE2NATIVE16(a) MAP_NATIVE2LE16(a) +#define MAP_BE2NATIVE16(a) MAP_NATIVE2BE16(a) +#define MAP_LE2NATIVE32(a) MAP_NATIVE2LE32(a) +#define MAP_BE2NATIVE32(a) MAP_NATIVE2BE32(a) + + +////////////////////////////// Utility function ///////////////////////////////// + +/* + * conversion of this buffer: + * conversion size=1 -> each byte is converted from signed to unsigned or vice versa + * conversion size=2,3,4: the order of bytes in a sample is reversed (endianness) + * for sign conversion of a 24-bit sample stored in 32bits, 4 should be passed + * as conversionSize + */ +void handleSignEndianConversion(INT8* data, INT8* output, int byteSize, int conversionSize) { + TRACE1("conversion with size %d\n", conversionSize); + switch (conversionSize) { + case 1: { + while (byteSize > 0) { + *output = *data + (char) 128; // use wrap-around + byteSize--; + data++; + output++; + } + break; + } + case 2: { + INT8 h; + byteSize = byteSize / 2; + while (byteSize > 0) { + h = *data; + data++; + *output = *data; + output++; + *output = h; + byteSize--; + data++; output++; + } + break; + } + case 3: { + INT8 h; + byteSize = byteSize / 3; + while (byteSize > 0) { + h = *data; + *output = data[2]; + data++; output++; + *output = *data; + data++; output++; + *output = h; + data++; output++; + byteSize--; + } + break; + } + case 4: { + INT8 h1, h2; + byteSize = byteSize / 4; + while (byteSize > 0) { + h1 = data[0]; + h2 = data[1]; + *output = data[3]; output++; + *output = data[2]; output++; + *output = h2; output++; + *output = h1; output++; + data += 4; + byteSize--; + } + break; + } + default: + ERROR1("DirectAudioDevice.c: wrong conversionSize %d!\n", conversionSize); + } +} + +/* aply the gain to one sample */ +#define CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FACTOR) \ + /* convert to MAP_Sample native type */ \ + sample = TO_SAMPLE(*INPUT); \ + /* apply gain */ \ + sample = (MAP_Sample) (sample * FACTOR); \ + /* convert to output type */ \ + (*OUTPUT) = FROM_SAMPLE(sample); \ + INPUT++; OUTPUT++ + + +/* macro for conversion of a mono block */ +#define LOOP_M(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \ + if (leftGain > 1.0) { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE_CLIP, leftGain); \ + } \ + } else { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE, leftGain); \ + } \ + } \ + break + +/* macro for conversion of a stereo block */ +#define LOOP_S(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \ + if (leftGain > 1.0) { \ + if (rightGain > 1.0) { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE_CLIP, leftGain); \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE_CLIP, rightGain); \ + } \ + } else { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE_CLIP, leftGain); \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE, rightGain); \ + } \ + } \ + } else { \ + if (rightGain > 1.0) { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE, leftGain); \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE_CLIP, rightGain); \ + } \ + } else { \ + for ( ; len > 0; --len) { \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE, leftGain); \ + CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \ + FROM_SAMPLE, rightGain); \ + } \ + } \ + } \ + break + +#define FORMAT2CODE(channels, bits, inSigned, outSigned, inBigEndian, outBigEndian) \ + (channels << 20) \ + | (bits << 4) \ + | ((inSigned & 1) << 3) \ + | ((outSigned & 1) << 2) \ + | ((inBigEndian & 1) << 1) \ + | (outBigEndian & 1) + +#define FORMAT2CODE8(channels, inSigned, outSigned) \ + FORMAT2CODE(channels, 8, inSigned, outSigned, 0, 0) + +#define FORMAT2CODE16(channels, inBigEndian, outBigEndian) \ + FORMAT2CODE(channels, 16, 1, 1, inBigEndian, outBigEndian) + + +void handleGainAndConversion(DAUDIO_Info* info, UINT8* input, UINT8* output, + int len, float leftGain, float rightGain, + int conversionSize) { + INT8* input8 = (INT8*) input; + INT8* output8 = (INT8*) output; + INT16* input16 = (INT16*) input; + INT16* output16 = (INT16*) output; + MAP_Sample sample; + + int inIsSigned = info->isSigned; + int inIsBigEndian = info->isBigEndian; + if (conversionSize == 1) { + /* 8-bit conversion: change sign */ + inIsSigned = !inIsSigned; + } + else if (conversionSize > 1) { + /* > 8-bit conversion: change endianness */ + inIsBigEndian = !inIsBigEndian; + } + if (info->frameSize <= 0) { + ERROR1("DirectAudiODevice: invalid framesize=%d\n", info->frameSize); + return; + } + len /= info->frameSize; + TRACE3("handleGainAndConversion: len=%d frames, leftGain=%f, rightGain=%f, ", + len, leftGain, rightGain); + TRACE3("channels=%d, sampleSizeInBits=%d, frameSize=%d, ", + (int) info->channels, (int) info->sampleSizeInBits, (int) info->frameSize); + TRACE4("signed:%d -> %d, endian: %d -> %d", + (int) inIsSigned, (int) info->isSigned, + (int) inIsBigEndian, (int) info->isBigEndian); + TRACE1("convSize=%d\n", conversionSize); + + switch (FORMAT2CODE(info->channels, + info->sampleSizeInBits, + inIsSigned, + info->isSigned, + inIsBigEndian, + info->isBigEndian)) { + /* 8-bit mono */ + case FORMAT2CODE8(1, 0, 0): + LOOP_M(input8, output8, MAP_UINT82SAMPLE, + MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); + case FORMAT2CODE8(1, 0, 1): + LOOP_M(input8, output8, MAP_UINT82SAMPLE, + MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); + case FORMAT2CODE8(1, 1, 0): + LOOP_M(input8, output8, MAP_INT82SAMPLE, + MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); + case FORMAT2CODE8(1, 1, 1): + LOOP_M(input8, output8, MAP_INT82SAMPLE, + MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); + + /* 8-bit stereo */ + case FORMAT2CODE8(2, 0, 0): + LOOP_S(input8, output8, MAP_UINT82SAMPLE, + MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); + case FORMAT2CODE8(2, 0, 1): + LOOP_S(input8, output8, MAP_UINT82SAMPLE, + MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); + case FORMAT2CODE8(2, 1, 0): + LOOP_S(input8, output8, MAP_INT82SAMPLE, + MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP); + case FORMAT2CODE8(2, 1, 1): + LOOP_S(input8, output8, MAP_INT82SAMPLE, + MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP); + + /* 16-bit mono (only signed is accepted) */ + case FORMAT2CODE16(1, 0, 0): + LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE, + MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); + case FORMAT2CODE16(1, 0, 1): + LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE, + MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); + case FORMAT2CODE16(1, 1, 0): + LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE, + MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); + case FORMAT2CODE16(1, 1, 1): + LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE, + MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); + + /* 16-bit stereo (only signed is accepted) */ + case FORMAT2CODE16(2, 0, 0): + LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE, + MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); + case FORMAT2CODE16(2, 0, 1): + LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE, + MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); + case FORMAT2CODE16(2, 1, 0): + LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE, + MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP); + case FORMAT2CODE16(2, 1, 1): + LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE, + MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP); + + default: + ERROR3("DirectAudioDevice: Cannot convert from native format: " + "bits=%d, inSigned=%d outSigned=%d, ", + (int) info->sampleSizeInBits, + (int) inIsSigned, (int) info->isSigned); + ERROR2("inBigEndian=%d, outBigEndian=%d\n", + (int) inIsBigEndian, (int) info->isBigEndian); + } +} + +float ABS_VALUE(float a) { + return (a < 0)?-a:a; +} + + +//////////////////////////////////////////// DirectAudioDevice //////////////////////////////////////////// + +/* ************************************** native control creation support ********************* */ + +// contains all the needed references so that the platform dependent code can call JNI wrapper functions +typedef struct tag_AddFormatCreator { + // general JNI variables + JNIEnv *env; + // the vector to be filled with the formats + jobject vector; + // the class containing the addFormat method + jclass directAudioDeviceClass; + // the method to be called to add the format + jmethodID addFormat; // signature (Ljava/util/Vector;IIFIBB)V +} AddFormatCreator; + +void DAUDIO_AddAudioFormat(void* creatorV, int significantBits, int frameSizeInBytes, + int channels, float sampleRate, + int encoding, int isSigned, + int bigEndian) { + AddFormatCreator* creator = (AddFormatCreator*) creatorV; + if (frameSizeInBytes <= 0) { + if (channels > 0) { + frameSizeInBytes = ((significantBits + 7) / 8) * channels; + } else { + frameSizeInBytes = -1; + } + } + TRACE4("AddAudioFormat with sigBits=%d bits, frameSize=%d bytes, channels=%d, sampleRate=%d ", + significantBits, frameSizeInBytes, channels, (int) sampleRate); + TRACE3("enc=%d, signed=%d, bigEndian=%d\n", encoding, isSigned, bigEndian); + (*creator->env)->CallStaticVoidMethod(creator->env, creator->directAudioDeviceClass, + creator->addFormat, creator->vector, significantBits, frameSizeInBytes, + channels, sampleRate, encoding, isSigned, bigEndian); +} + +////////////////////////////////////// JNI ///////////////////////////////////////////////////////////////////// + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nGetFormats + * Signature: (IIZLjava/util/Vector;)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetFormats +(JNIEnv *env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, jobject formats) { + +#if USE_DAUDIO == TRUE + AddFormatCreator creator; + creator.env = env; + creator.vector = formats; + creator.directAudioDeviceClass = clazz; + creator.addFormat = (*env)->GetStaticMethodID(env, clazz, "addFormat", + "(Ljava/util/Vector;IIIFIZZ)V"); + if (creator.addFormat == NULL) { + ERROR0("Could not get method ID for addFormat!\n"); + } else { + DAUDIO_GetFormats((INT32) mixerIndex, (INT32) deviceID, (int) isSource, &creator); + } +#endif +} + + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nOpen + * Signature: (IIZIFIIZZI)J + */ +JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nOpen +(JNIEnv* env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, + jint encoding, jfloat sampleRate, jint sampleSizeInBits, jint frameSize, jint channels, + jboolean isSigned, jboolean isBigendian, jint bufferSizeInBytes) { + + DAUDIO_Info* info = NULL; +#if USE_DAUDIO == TRUE + + info = (DAUDIO_Info*) malloc(sizeof(DAUDIO_Info)); + if (info == NULL) { + ERROR0("DirectAudioDevice_nOpen: Out of memory!\n"); + } else { + info->handle =DAUDIO_Open((int) mixerIndex, (INT32) deviceID, (int) isSource, + (int) encoding, (float) sampleRate, (int) sampleSizeInBits, + (int) frameSize, (int) channels, + (int) isSigned, (int) isBigendian, (int) bufferSizeInBytes); + if (!info->handle) { + free(info); + info = NULL; + } else { + info->encoding = encoding; + info->sampleSizeInBits = sampleSizeInBits; + info->frameSize = frameSize; + info->channels = channels; + info->isSigned = isSigned; + info->isBigEndian = isBigendian && (sampleSizeInBits > 8); + /* will be populated on demand */ + info->conversionBuffer = NULL; + info->conversionBufferSize = 0; + } + } +#endif + return (jlong) (UINT_PTR) info; +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nStart + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStart +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_Start(info->handle, (int) isSource); + } +#endif +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nStop + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStop +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_Stop(info->handle, (int) isSource); + } +#endif +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nClose + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nClose +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_Close(info->handle, (int) isSource); + if (info->conversionBuffer) { + free(info->conversionBuffer); + } + free(info); + } +#endif +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nWrite + * Signature: (J[BII)I + */ +JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nWrite +(JNIEnv *env, jclass clazz, jlong id, jbyteArray jData, + jint offset, jint len, jint conversionSize, jfloat leftGain, jfloat rightGain) { + int ret = -1; +#if USE_DAUDIO == TRUE + UINT8* data; + UINT8* dataOffset; + UINT8* convertedData; + jboolean didCopy; + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + + /* a little sanity */ + if (offset < 0 || len < 0) { + ERROR2("nWrite: wrong parameters: offset=%d, len=%d\n", offset, len); + return ret; + } + if (len == 0) return 0; + if (info && info->handle) { + data = (UINT8*) ((*env)->GetByteArrayElements(env, jData, &didCopy)); + CHECK_NULL_RETURN(data, ret); + dataOffset = data; + dataOffset += (int) offset; + convertedData = dataOffset; + + if (conversionSize > 0 || leftGain != 1.0f || rightGain != 1.0f) { + /* make sure we have a buffer for the intermediate data */ + if (didCopy == JNI_FALSE) { + /* let's do our own copy */ + if (info->conversionBuffer + && info->conversionBufferSize < len) { + free(info->conversionBuffer); + info->conversionBuffer = NULL; + info->conversionBufferSize = 0; + } + if (!info->conversionBuffer) { + info->conversionBuffer = (UINT8*) malloc(len); + if (!info->conversionBuffer) { + // do not commit the native array + (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT); + return -1; + } + info->conversionBufferSize = len; + } + convertedData = info->conversionBuffer; + } + if (((ABS_VALUE(leftGain - 1.0f) < 0.01) + && (ABS_VALUE(rightGain - 1.0f) < 0.01)) + || info->encoding!=DAUDIO_PCM + || ((info->channels * info->sampleSizeInBits / 8) != info->frameSize) + || (info->sampleSizeInBits != 8 && info->sampleSizeInBits != 16)) { + handleSignEndianConversion((INT8*) dataOffset, (INT8*) convertedData, (int) len, + (int) conversionSize); + } else { + handleGainAndConversion(info, dataOffset, convertedData, + (int) len, (float) leftGain, (float) rightGain, + (int) conversionSize); + } + } + + ret = DAUDIO_Write(info->handle, (INT8*) convertedData, (int) len); + + // do not commit the native array + (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT); + } +#endif + return (jint) ret; +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nRead + * Signature: (J[BII)I + */ +JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRead +(JNIEnv* env, jclass clazz, jlong id, jbyteArray jData, jint offset, jint len, jint conversionSize) { + int ret = -1; +#if USE_DAUDIO == TRUE + char* data; + char* dataOffset; + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + + /* a little sanity */ + if (offset < 0 || len < 0) { + ERROR2("nRead: wrong parameters: offset=%d, len=%d\n", offset, len); + return ret; + } + if (info && info->handle) { + data = (char*) ((*env)->GetByteArrayElements(env, jData, NULL)); + CHECK_NULL_RETURN(data, ret); + dataOffset = data; + dataOffset += (int) offset; + ret = DAUDIO_Read(info->handle, dataOffset, (int) len); + if (conversionSize > 0) { + handleSignEndianConversion(dataOffset, dataOffset, (int) len, (int) conversionSize); + } + // commit the native array + (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, 0); + } +#endif + return (jint) ret; +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nGetBufferSize + * Signature: (JZ)I + */ +JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { + int ret = -1; +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + ret = DAUDIO_GetBufferSize(info->handle, (int) isSource); + } +#endif + return (jint) ret; +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nIsStillDraining + * Signature: (JZ)Z + */ +JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { + int ret = FALSE; +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + ret = DAUDIO_StillDraining(info->handle, (int) isSource)?TRUE:FALSE; + } +#endif + return (jboolean) ret; +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nFlush + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nFlush +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_Flush(info->handle, (int) isSource); + } +#endif +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nAvailable + * Signature: (JZ)I + */ +JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nAvailable +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { + int ret = -1; +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + ret = DAUDIO_GetAvailable(info->handle, (int) isSource); + } +#endif + return (jint) ret; +} + + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nGetBytePosition + * Signature: (JZJ)J + */ +JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong javaBytePos) { + INT64 ret = (INT64) javaBytePos; +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + ret = DAUDIO_GetBytePosition(info->handle, (int) isSource, (INT64) javaBytePos); + } +#endif + return (jlong) ret; +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nSetBytePosition + * Signature: (JZJ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong pos) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_SetBytePosition(info->handle, (int) isSource, (INT64) pos); + } +#endif +} + +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nRequiresServicing + * Signature: (JZ)B + */ +JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { + int ret = FALSE; +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + ret = DAUDIO_RequiresServicing(info->handle, (int) isSource); + } +#endif + return (jboolean) ret; +} +/* + * Class: com_sun_media_sound_DirectAudioDevice + * Method: nService + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nService +(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { +#if USE_DAUDIO == TRUE + DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; + if (info && info->handle) { + DAUDIO_Service(info->handle, (int) isSource); + } +#endif +} --- old/src/java.desktop/share/native/libjsound/DirectAudioDeviceProvider.c 2018-03-15 02:00:46.298586516 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2002, 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_TRACE -//#define USE_ERROR - - -#include -#include -#include "SoundDefs.h" -#include "DirectAudio.h" -#include "Utilities.h" -#include "com_sun_media_sound_DirectAudioDeviceProvider.h" - - -//////////////////////////////////////////// DirectAudioDeviceProvider //////////////////////////////////////////// - -int getDirectAudioDeviceDescription(int mixerIndex, DirectAudioDeviceDescription* desc) { - desc->deviceID = 0; - desc->maxSimulLines = 0; - strcpy(desc->name, "Unknown Name"); - strcpy(desc->vendor, "Unknown Vendor"); - strcpy(desc->description, "Unknown Description"); - strcpy(desc->version, "Unknown Version"); -#if USE_DAUDIO == TRUE - DAUDIO_GetDirectAudioDeviceDescription(mixerIndex, desc); -#endif // USE_DAUDIO - return TRUE; -} - -JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices(JNIEnv *env, jclass cls) { - INT32 numDevices = 0; - - TRACE0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices.\n"); - -#if USE_DAUDIO == TRUE - numDevices = DAUDIO_GetDirectAudioDeviceCount(); -#endif // USE_DAUDIO - - TRACE1("Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices returning %d.\n", (int) numDevices); - - return (jint)numDevices; -} - -JNIEXPORT jobject JNICALL Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo - (JNIEnv *env, jclass cls, jint mixerIndex) { - - jclass directAudioDeviceInfoClass; - jmethodID directAudioDeviceInfoConstructor; - DirectAudioDeviceDescription desc; - jobject info = NULL; - jstring name; - jstring vendor; - jstring description; - jstring version; - - TRACE1("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo(%d).\n", mixerIndex); - - // retrieve class and constructor of DirectAudioDeviceProvider.DirectAudioDeviceInfo - directAudioDeviceInfoClass = (*env)->FindClass(env, IMPLEMENTATION_PACKAGE_NAME"/DirectAudioDeviceProvider$DirectAudioDeviceInfo"); - if (directAudioDeviceInfoClass == NULL) { - ERROR0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo: directAudioDeviceInfoClass is NULL\n"); - return NULL; - } - directAudioDeviceInfoConstructor = (*env)->GetMethodID(env, directAudioDeviceInfoClass, "", - "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - if (directAudioDeviceInfoConstructor == NULL) { - ERROR0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo: directAudioDeviceInfoConstructor is NULL\n"); - return NULL; - } - - TRACE1("Get description for device %d\n", mixerIndex); - - if (getDirectAudioDeviceDescription(mixerIndex, &desc)) { - // create a new DirectAudioDeviceInfo object and return it - name = (*env)->NewStringUTF(env, desc.name); - CHECK_NULL_RETURN(name, info); - vendor = (*env)->NewStringUTF(env, desc.vendor); - CHECK_NULL_RETURN(vendor, info); - description = (*env)->NewStringUTF(env, desc.description); - CHECK_NULL_RETURN(description, info); - version = (*env)->NewStringUTF(env, desc.version); - CHECK_NULL_RETURN(version, info); - info = (*env)->NewObject(env, directAudioDeviceInfoClass, - directAudioDeviceInfoConstructor, mixerIndex, - desc.deviceID, desc.maxSimulLines, - name, vendor, description, version); - } else { - ERROR1("ERROR: getDirectAudioDeviceDescription(%d, desc) returned FALSE!\n", mixerIndex); - } - - TRACE0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo succeeded.\n"); - return info; -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/directaudio/DirectAudioDeviceProvider.c 2018-03-15 02:00:45.974586518 +0100 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002, 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_TRACE +//#define USE_ERROR + + +#include +#include +#include "SoundDefs.h" +#include "DirectAudio.h" +#include "Utilities.h" +#include "com_sun_media_sound_DirectAudioDeviceProvider.h" + + +//////////////////////////////////////////// DirectAudioDeviceProvider //////////////////////////////////////////// + +int getDirectAudioDeviceDescription(int mixerIndex, DirectAudioDeviceDescription* desc) { + desc->deviceID = 0; + desc->maxSimulLines = 0; + strcpy(desc->name, "Unknown Name"); + strcpy(desc->vendor, "Unknown Vendor"); + strcpy(desc->description, "Unknown Description"); + strcpy(desc->version, "Unknown Version"); +#if USE_DAUDIO == TRUE + DAUDIO_GetDirectAudioDeviceDescription(mixerIndex, desc); +#endif // USE_DAUDIO + return TRUE; +} + +JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices(JNIEnv *env, jclass cls) { + INT32 numDevices = 0; + + TRACE0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices.\n"); + +#if USE_DAUDIO == TRUE + numDevices = DAUDIO_GetDirectAudioDeviceCount(); +#endif // USE_DAUDIO + + TRACE1("Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices returning %d.\n", (int) numDevices); + + return (jint)numDevices; +} + +JNIEXPORT jobject JNICALL Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo + (JNIEnv *env, jclass cls, jint mixerIndex) { + + jclass directAudioDeviceInfoClass; + jmethodID directAudioDeviceInfoConstructor; + DirectAudioDeviceDescription desc; + jobject info = NULL; + jstring name; + jstring vendor; + jstring description; + jstring version; + + TRACE1("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo(%d).\n", mixerIndex); + + // retrieve class and constructor of DirectAudioDeviceProvider.DirectAudioDeviceInfo + directAudioDeviceInfoClass = (*env)->FindClass(env, IMPLEMENTATION_PACKAGE_NAME"/DirectAudioDeviceProvider$DirectAudioDeviceInfo"); + if (directAudioDeviceInfoClass == NULL) { + ERROR0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo: directAudioDeviceInfoClass is NULL\n"); + return NULL; + } + directAudioDeviceInfoConstructor = (*env)->GetMethodID(env, directAudioDeviceInfoClass, "", + "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (directAudioDeviceInfoConstructor == NULL) { + ERROR0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo: directAudioDeviceInfoConstructor is NULL\n"); + return NULL; + } + + TRACE1("Get description for device %d\n", mixerIndex); + + if (getDirectAudioDeviceDescription(mixerIndex, &desc)) { + // create a new DirectAudioDeviceInfo object and return it + name = (*env)->NewStringUTF(env, desc.name); + CHECK_NULL_RETURN(name, info); + vendor = (*env)->NewStringUTF(env, desc.vendor); + CHECK_NULL_RETURN(vendor, info); + description = (*env)->NewStringUTF(env, desc.description); + CHECK_NULL_RETURN(description, info); + version = (*env)->NewStringUTF(env, desc.version); + CHECK_NULL_RETURN(version, info); + info = (*env)->NewObject(env, directAudioDeviceInfoClass, + directAudioDeviceInfoConstructor, mixerIndex, + desc.deviceID, desc.maxSimulLines, + name, vendor, description, version); + } else { + ERROR1("ERROR: getDirectAudioDeviceDescription(%d, desc) returned FALSE!\n", mixerIndex); + } + + TRACE0("Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo succeeded.\n"); + return info; +} --- old/src/java.desktop/share/native/libjsound/MidiInDevice.c 2018-03-15 02:00:46.794586512 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,260 +0,0 @@ -/* - * Copyright (c) 1999, 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. - */ - -/*****************************************************************************/ -/* -** Native functions for interfacing Java with the native implementation -** of PlatformMidi.h's functions. -*/ -/*****************************************************************************/ - -#define USE_ERROR -#define USE_TRACE - - -#include -/* for memcpy */ -#include -#include "SoundDefs.h" -#include "PlatformMidi.h" -#include "com_sun_media_sound_MidiInDevice.h" - - -JNIEXPORT jlong JNICALL -Java_com_sun_media_sound_MidiInDevice_nOpen(JNIEnv* e, jobject thisObj, jint index) { - - MidiDeviceHandle* deviceHandle = NULL; - INT32 err = MIDI_NOT_SUPPORTED; - - TRACE1("> Java_com_sun_media_sound_MidiInDevice_nOpen: index: %d\n", index); - -#if USE_PLATFORM_MIDI_IN == TRUE - err = MIDI_IN_OpenDevice((INT32) index, &deviceHandle); -#endif - - /* $$mp 2003-08-28: - So far, the return value (err) hasn't been taken into account. - Now, it is also expected to be MIDI_SUCCESS (0). - This works for Linux, but has to be checked on other platforms. - - It would be better to settle on one method of signaling error: - either returned error codes or a NULL handle. If the latter is used, - the return value should be removed from the signature of - MIDI_IN_OpenDevice. - */ - // if we didn't get a valid handle, throw a MidiUnavailableException - if (!deviceHandle || err != MIDI_SUCCESS) { - deviceHandle = NULL; - ERROR0("Java_com_sun_media_sound_MidiInDevice_nOpen: "); - ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", - MIDI_IN_InternalGetErrorString(err)); - } else { - TRACE0("< Java_com_sun_media_sound_MidiInDevice_nOpen succeeded\n"); - } - return (jlong) (UINT_PTR) deviceHandle; -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiInDevice_nClose(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - TRACE0("> Java_com_sun_media_sound_MidiInDevice_nClose.\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - MIDI_IN_CloseDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - TRACE0("< Java_com_sun_media_sound_MidiInDevice_nClose succeeded\n"); -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiInDevice_nStart(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - INT32 err = MIDI_NOT_SUPPORTED; - - TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStart.\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - err = MIDI_IN_StartDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - if (err != MIDI_SUCCESS) { - ERROR0("Java_com_sun_media_sound_MidiInDevice_nStart: "); - ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", - MIDI_IN_InternalGetErrorString(err)); - } else { - TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStart succeeded\n"); - } -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiInDevice_nStop(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStop.\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - // stop the device and remove all queued events for this device handle - MIDI_IN_StopDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStop succeeded\n"); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - jlong ret = -1; - - TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp.\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - ret = (jlong) MIDI_IN_GetTimeStamp((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - /* Handle error codes. */ - if (ret < -1) { - ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp: MIDI_IN_GetTimeStamp returned %lld\n", ret); - ret = -1; - } - return ret; -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiInDevice_nGetMessages(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - -#if USE_PLATFORM_MIDI_IN == TRUE - MidiMessage* pMessage; - jclass javaClass = NULL; - jmethodID callbackShortMessageMethodID = NULL; - jmethodID callbackLongMessageMethodID = NULL; -#endif - - TRACE0("> Java_com_sun_media_sound_MidiInDevice_nGetMessages\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - while ((pMessage = MIDI_IN_GetMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle))) { - if ((javaClass == NULL) || (callbackShortMessageMethodID == NULL)) { - if (!thisObj) { - ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: thisObj is NULL\n"); - return; - } - - if (javaClass == NULL) { - javaClass = (*e)->GetObjectClass(e, thisObj); - if (javaClass == NULL) { - ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: javaClass is NULL\n"); - return; - } - } - - if (callbackShortMessageMethodID == NULL) { - // save the callbackShortMessage callback method id. - // this is valid as long as the class is not unloaded. - callbackShortMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackShortMessage", "(IJ)V"); - if (callbackShortMessageMethodID == 0) { - ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackShortMessageMethodID is 0\n"); - return; - } - } - if (callbackLongMessageMethodID == NULL) { - // save the callbackLongMessage callback method id. - // this is valid as long as the class is not unloaded. - callbackLongMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackLongMessage", "([BJ)V"); - if (callbackLongMessageMethodID == 0) { - ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackLongMessageMethodID is 0\n"); - return; - } - } - } - - switch ((int)pMessage->type) { - case SHORT_MESSAGE: { - jint msg = (jint)pMessage->data.s.packedMsg; - jlong ts = (jlong)pMessage->timestamp; - TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got SHORT_MESSAGE\n"); - // now we can put this message object back in the queue - MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); - // and notify Java space - (*e)->CallVoidMethod(e, thisObj, callbackShortMessageMethodID, msg, ts); - break; - } - - case LONG_MESSAGE: { - jlong ts = (jlong)pMessage->timestamp; - jbyteArray jData; - UBYTE* data; - int isSXCont = 0; - TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got LONG_MESSAGE\n"); - if ((*(pMessage->data.l.data) != 0xF0) - && (*(pMessage->data.l.data) != 0xF7)) { - // this is a continued sys ex message - // need to prepend 0xF7 - isSXCont = 1; - } - jData = (*e)->NewByteArray(e, pMessage->data.l.size + isSXCont); - if (!jData) { - ERROR0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: cannot create long byte array.\n"); - break; - } - data = (UBYTE*) ((*e)->GetByteArrayElements(e, jData, NULL)); - if (!data) { - ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: array data is NULL\n"); - break; - } - // finally copy the long message - memcpy(data + isSXCont, pMessage->data.l.data, pMessage->data.l.size); - - // now we can put this message object back in the queue - MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); - - // if this is a patched continued sys ex message, prepend 0xF7 - if (isSXCont) { - *data = 0xF7; - } - - // commit the byte array - (*e)->ReleaseByteArrayElements(e, jData, (jbyte*) data, (jint) 0); - - (*e)->CallVoidMethod(e, thisObj, callbackLongMessageMethodID, jData, ts); - // release local reference to array: not needed anymore. - (*e)->DeleteLocalRef(e, jData); - break; - } - - default: - // put this message object back in the queue - MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); - ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got unsupported message, type %d\n", pMessage->type); - break; - } // switch - } - -#endif // USE_PLATFORM_MIDI_IN - - TRACE0("< Java_com_sun_media_sound_MidiInDevice_nGetMessages returning\n"); -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/MidiInDevice.c 2018-03-15 02:00:46.482586515 +0100 @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1999, 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. + */ + +/*****************************************************************************/ +/* +** Native functions for interfacing Java with the native implementation +** of PlatformMidi.h's functions. +*/ +/*****************************************************************************/ + +#define USE_ERROR +#define USE_TRACE + + +#include +/* for memcpy */ +#include +#include "SoundDefs.h" +#include "PlatformMidi.h" +#include "com_sun_media_sound_MidiInDevice.h" + + +JNIEXPORT jlong JNICALL +Java_com_sun_media_sound_MidiInDevice_nOpen(JNIEnv* e, jobject thisObj, jint index) { + + MidiDeviceHandle* deviceHandle = NULL; + INT32 err = MIDI_NOT_SUPPORTED; + + TRACE1("> Java_com_sun_media_sound_MidiInDevice_nOpen: index: %d\n", index); + +#if USE_PLATFORM_MIDI_IN == TRUE + err = MIDI_IN_OpenDevice((INT32) index, &deviceHandle); +#endif + + /* $$mp 2003-08-28: + So far, the return value (err) hasn't been taken into account. + Now, it is also expected to be MIDI_SUCCESS (0). + This works for Linux, but has to be checked on other platforms. + + It would be better to settle on one method of signaling error: + either returned error codes or a NULL handle. If the latter is used, + the return value should be removed from the signature of + MIDI_IN_OpenDevice. + */ + // if we didn't get a valid handle, throw a MidiUnavailableException + if (!deviceHandle || err != MIDI_SUCCESS) { + deviceHandle = NULL; + ERROR0("Java_com_sun_media_sound_MidiInDevice_nOpen: "); + ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", + MIDI_IN_InternalGetErrorString(err)); + } else { + TRACE0("< Java_com_sun_media_sound_MidiInDevice_nOpen succeeded\n"); + } + return (jlong) (UINT_PTR) deviceHandle; +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiInDevice_nClose(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + TRACE0("> Java_com_sun_media_sound_MidiInDevice_nClose.\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + MIDI_IN_CloseDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + TRACE0("< Java_com_sun_media_sound_MidiInDevice_nClose succeeded\n"); +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiInDevice_nStart(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + INT32 err = MIDI_NOT_SUPPORTED; + + TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStart.\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + err = MIDI_IN_StartDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + if (err != MIDI_SUCCESS) { + ERROR0("Java_com_sun_media_sound_MidiInDevice_nStart: "); + ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", + MIDI_IN_InternalGetErrorString(err)); + } else { + TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStart succeeded\n"); + } +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiInDevice_nStop(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStop.\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + // stop the device and remove all queued events for this device handle + MIDI_IN_StopDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStop succeeded\n"); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + jlong ret = -1; + + TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp.\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + ret = (jlong) MIDI_IN_GetTimeStamp((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + /* Handle error codes. */ + if (ret < -1) { + ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp: MIDI_IN_GetTimeStamp returned %lld\n", ret); + ret = -1; + } + return ret; +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiInDevice_nGetMessages(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + +#if USE_PLATFORM_MIDI_IN == TRUE + MidiMessage* pMessage; + jclass javaClass = NULL; + jmethodID callbackShortMessageMethodID = NULL; + jmethodID callbackLongMessageMethodID = NULL; +#endif + + TRACE0("> Java_com_sun_media_sound_MidiInDevice_nGetMessages\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + while ((pMessage = MIDI_IN_GetMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle))) { + if ((javaClass == NULL) || (callbackShortMessageMethodID == NULL)) { + if (!thisObj) { + ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: thisObj is NULL\n"); + return; + } + + if (javaClass == NULL) { + javaClass = (*e)->GetObjectClass(e, thisObj); + if (javaClass == NULL) { + ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: javaClass is NULL\n"); + return; + } + } + + if (callbackShortMessageMethodID == NULL) { + // save the callbackShortMessage callback method id. + // this is valid as long as the class is not unloaded. + callbackShortMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackShortMessage", "(IJ)V"); + if (callbackShortMessageMethodID == 0) { + ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackShortMessageMethodID is 0\n"); + return; + } + } + if (callbackLongMessageMethodID == NULL) { + // save the callbackLongMessage callback method id. + // this is valid as long as the class is not unloaded. + callbackLongMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackLongMessage", "([BJ)V"); + if (callbackLongMessageMethodID == 0) { + ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackLongMessageMethodID is 0\n"); + return; + } + } + } + + switch ((int)pMessage->type) { + case SHORT_MESSAGE: { + jint msg = (jint)pMessage->data.s.packedMsg; + jlong ts = (jlong)pMessage->timestamp; + TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got SHORT_MESSAGE\n"); + // now we can put this message object back in the queue + MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); + // and notify Java space + (*e)->CallVoidMethod(e, thisObj, callbackShortMessageMethodID, msg, ts); + break; + } + + case LONG_MESSAGE: { + jlong ts = (jlong)pMessage->timestamp; + jbyteArray jData; + UBYTE* data; + int isSXCont = 0; + TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got LONG_MESSAGE\n"); + if ((*(pMessage->data.l.data) != 0xF0) + && (*(pMessage->data.l.data) != 0xF7)) { + // this is a continued sys ex message + // need to prepend 0xF7 + isSXCont = 1; + } + jData = (*e)->NewByteArray(e, pMessage->data.l.size + isSXCont); + if (!jData) { + ERROR0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: cannot create long byte array.\n"); + break; + } + data = (UBYTE*) ((*e)->GetByteArrayElements(e, jData, NULL)); + if (!data) { + ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: array data is NULL\n"); + break; + } + // finally copy the long message + memcpy(data + isSXCont, pMessage->data.l.data, pMessage->data.l.size); + + // now we can put this message object back in the queue + MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); + + // if this is a patched continued sys ex message, prepend 0xF7 + if (isSXCont) { + *data = 0xF7; + } + + // commit the byte array + (*e)->ReleaseByteArrayElements(e, jData, (jbyte*) data, (jint) 0); + + (*e)->CallVoidMethod(e, thisObj, callbackLongMessageMethodID, jData, ts); + // release local reference to array: not needed anymore. + (*e)->DeleteLocalRef(e, jData); + break; + } + + default: + // put this message object back in the queue + MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); + ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got unsupported message, type %d\n", pMessage->type); + break; + } // switch + } + +#endif // USE_PLATFORM_MIDI_IN + + TRACE0("< Java_com_sun_media_sound_MidiInDevice_nGetMessages returning\n"); +} --- old/src/java.desktop/share/native/libjsound/MidiInDeviceProvider.c 2018-03-15 02:00:47.294586509 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 1999, 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 -#include "SoundDefs.h" -#include "PlatformMidi.h" -#include "Utilities.h" -// for strcpy -#include -#include "com_sun_media_sound_MidiInDeviceProvider.h" - - -#define MAX_STRING_LENGTH 128 - - -JNIEXPORT jint JNICALL -Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices(JNIEnv* e, jobject thisObj) { - - INT32 numDevices = 0; - - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices.\n"); - -#if USE_PLATFORM_MIDI_IN == TRUE - numDevices = MIDI_IN_GetNumDevices(); -#endif - - TRACE1("Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices returning %d.\n", numDevices); - return (jint) numDevices; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiInDeviceProvider_nGetName(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetName.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_IN == TRUE - MIDI_IN_GetDeviceName((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "Unknown name"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetName completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_IN == TRUE - MIDI_IN_GetDeviceVendor((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "Unknown vendor"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_IN == TRUE - MIDI_IN_GetDeviceDescription((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "No details available"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_IN == TRUE - MIDI_IN_GetDeviceVersion((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "Unknown version"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion completed.\n"); - return jString; -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/MidiInDeviceProvider.c 2018-03-15 02:00:46.978586511 +0100 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1999, 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 +#include "SoundDefs.h" +#include "PlatformMidi.h" +#include "Utilities.h" +// for strcpy +#include +#include "com_sun_media_sound_MidiInDeviceProvider.h" + + +#define MAX_STRING_LENGTH 128 + + +JNIEXPORT jint JNICALL +Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices(JNIEnv* e, jobject thisObj) { + + INT32 numDevices = 0; + + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices.\n"); + +#if USE_PLATFORM_MIDI_IN == TRUE + numDevices = MIDI_IN_GetNumDevices(); +#endif + + TRACE1("Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices returning %d.\n", numDevices); + return (jint) numDevices; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiInDeviceProvider_nGetName(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetName.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_IN == TRUE + MIDI_IN_GetDeviceName((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "Unknown name"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetName completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_IN == TRUE + MIDI_IN_GetDeviceVendor((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "Unknown vendor"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_IN == TRUE + MIDI_IN_GetDeviceDescription((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "No details available"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_IN == TRUE + MIDI_IN_GetDeviceVersion((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "Unknown version"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion completed.\n"); + return jString; +} --- old/src/java.desktop/share/native/libjsound/MidiOutDevice.c 2018-03-15 02:00:47.774586505 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,147 +0,0 @@ -/* - * Copyright (c) 1999, 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. - */ - -/*****************************************************************************/ -/* -** Native functions for interfacing Java with the native implementation -** of PlatformMidi.h's functions. -*/ -/*****************************************************************************/ - -#define USE_ERROR -#define USE_TRACE - - -#include -#include "SoundDefs.h" -#include "PlatformMidi.h" -#include "Utilities.h" -#include "com_sun_media_sound_MidiOutDevice.h" - - -// NATIVE METHODS - - -JNIEXPORT jlong JNICALL -Java_com_sun_media_sound_MidiOutDevice_nOpen(JNIEnv* e, jobject thisObj, jint index) { - - void* deviceHandle = NULL; - INT32 err = MIDI_NOT_SUPPORTED; - - TRACE1("Java_com_sun_media_sound_MidiOutDevice_nOpen: index: %d\n", index); - -#if USE_PLATFORM_MIDI_OUT == TRUE - err = MIDI_OUT_OpenDevice((INT32) index, (MidiDeviceHandle**) (&deviceHandle)); -#endif - - // if we didn't get a valid handle, throw a MidiUnavailableException - if (!deviceHandle) { - ERROR0("Java_com_sun_media_sound_MidiOutDevice_nOpen:"); - ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", - MIDI_OUT_InternalGetErrorString(err)); - } else { - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nOpen succeeded\n"); - } - return (jlong) (INT_PTR) deviceHandle; -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiOutDevice_nClose(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nClose.\n"); - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_CloseDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nClose succeeded\n"); -} - - -JNIEXPORT jlong JNICALL -Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp(JNIEnv* e, jobject thisObj, jlong deviceHandle) { - - jlong ret = -1; - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp.\n"); - -#if USE_PLATFORM_MIDI_OUT == TRUE - ret = (jlong) MIDI_OUT_GetTimeStamp((MidiDeviceHandle*) (UINT_PTR) deviceHandle); -#endif - - /* Handle error codes. */ - if (ret < -1) { - ERROR1("Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp: MIDI_IN_GetTimeStamp returned %lld\n", ret); - ret = -1; - } - return ret; -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage(JNIEnv* e, jobject thisObj, jlong deviceHandle, - jint packedMsg, jlong timeStamp) { - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage.\n"); - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_SendShortMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, - (UINT32) packedMsg, (UINT32)timeStamp); -#endif - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage succeeded\n"); -} - - -JNIEXPORT void JNICALL -Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage(JNIEnv* e, jobject thisObj, jlong deviceHandle, - jbyteArray jData, jint size, jlong timeStamp) { -#if USE_PLATFORM_MIDI_OUT == TRUE - UBYTE* data; -#endif - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage.\n"); - -#if USE_PLATFORM_MIDI_OUT == TRUE - data = (UBYTE*) ((*e)->GetByteArrayElements(e, jData, NULL)); - if (!data) { - ERROR0("MidiOutDevice: Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage: could not get array elements\n"); - return; - } - /* "continuation" sysex messages start with F7 (instead of F0), but - are sent without the F7. */ - if (data[0] == 0xF7) { - data++; - size--; - } - MIDI_OUT_SendLongMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, data, - (UINT32) size, (UINT32)timeStamp); - // release the byte array - (*e)->ReleaseByteArrayElements(e, jData, (jbyte*) data, JNI_ABORT); -#endif - - TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage succeeded\n"); -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/MidiOutDevice.c 2018-03-15 02:00:47.450586508 +0100 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1999, 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. + */ + +/*****************************************************************************/ +/* +** Native functions for interfacing Java with the native implementation +** of PlatformMidi.h's functions. +*/ +/*****************************************************************************/ + +#define USE_ERROR +#define USE_TRACE + + +#include +#include "SoundDefs.h" +#include "PlatformMidi.h" +#include "Utilities.h" +#include "com_sun_media_sound_MidiOutDevice.h" + + +// NATIVE METHODS + + +JNIEXPORT jlong JNICALL +Java_com_sun_media_sound_MidiOutDevice_nOpen(JNIEnv* e, jobject thisObj, jint index) { + + void* deviceHandle = NULL; + INT32 err = MIDI_NOT_SUPPORTED; + + TRACE1("Java_com_sun_media_sound_MidiOutDevice_nOpen: index: %d\n", index); + +#if USE_PLATFORM_MIDI_OUT == TRUE + err = MIDI_OUT_OpenDevice((INT32) index, (MidiDeviceHandle**) (&deviceHandle)); +#endif + + // if we didn't get a valid handle, throw a MidiUnavailableException + if (!deviceHandle) { + ERROR0("Java_com_sun_media_sound_MidiOutDevice_nOpen:"); + ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", + MIDI_OUT_InternalGetErrorString(err)); + } else { + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nOpen succeeded\n"); + } + return (jlong) (INT_PTR) deviceHandle; +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiOutDevice_nClose(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nClose.\n"); + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_CloseDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nClose succeeded\n"); +} + + +JNIEXPORT jlong JNICALL +Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp(JNIEnv* e, jobject thisObj, jlong deviceHandle) { + + jlong ret = -1; + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp.\n"); + +#if USE_PLATFORM_MIDI_OUT == TRUE + ret = (jlong) MIDI_OUT_GetTimeStamp((MidiDeviceHandle*) (UINT_PTR) deviceHandle); +#endif + + /* Handle error codes. */ + if (ret < -1) { + ERROR1("Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp: MIDI_IN_GetTimeStamp returned %lld\n", ret); + ret = -1; + } + return ret; +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage(JNIEnv* e, jobject thisObj, jlong deviceHandle, + jint packedMsg, jlong timeStamp) { + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage.\n"); + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_SendShortMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, + (UINT32) packedMsg, (UINT32)timeStamp); +#endif + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage succeeded\n"); +} + + +JNIEXPORT void JNICALL +Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage(JNIEnv* e, jobject thisObj, jlong deviceHandle, + jbyteArray jData, jint size, jlong timeStamp) { +#if USE_PLATFORM_MIDI_OUT == TRUE + UBYTE* data; +#endif + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage.\n"); + +#if USE_PLATFORM_MIDI_OUT == TRUE + data = (UBYTE*) ((*e)->GetByteArrayElements(e, jData, NULL)); + if (!data) { + ERROR0("MidiOutDevice: Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage: could not get array elements\n"); + return; + } + /* "continuation" sysex messages start with F7 (instead of F0), but + are sent without the F7. */ + if (data[0] == 0xF7) { + data++; + size--; + } + MIDI_OUT_SendLongMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, data, + (UINT32) size, (UINT32)timeStamp); + // release the byte array + (*e)->ReleaseByteArrayElements(e, jData, (jbyte*) data, JNI_ABORT); +#endif + + TRACE0("Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage succeeded\n"); +} --- old/src/java.desktop/share/native/libjsound/MidiOutDeviceProvider.c 2018-03-15 02:00:48.258586502 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,144 +0,0 @@ -/* - * Copyright (c) 1999, 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 -#include "SoundDefs.h" -#include "PlatformMidi.h" -#include "Utilities.h" -// for strcpy -#include -#include "com_sun_media_sound_MidiOutDeviceProvider.h" - - -#define MAX_STRING_LENGTH 128 - - -JNIEXPORT jint JNICALL -Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices(JNIEnv* e, jobject thisObj) { - - INT32 numDevices = 0; - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices.\n"); - -#if USE_PLATFORM_MIDI_OUT == TRUE - numDevices = MIDI_OUT_GetNumDevices(); -#endif - - TRACE1("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices returning %d.\n", (int) numDevices); - return (jint) numDevices; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_GetDeviceName((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "Unknown name"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_GetDeviceVendor((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "Unknown vendor"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_GetDeviceDescription((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - - if (name[0] == 0) { - strcpy(name, "No details available"); - } - jString = (*e)->NewStringUTF(e, name); - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription completed.\n"); - return jString; -} - - -JNIEXPORT jstring JNICALL -Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion(JNIEnv* e, jobject thisObj, jint index) { - - char name[MAX_STRING_LENGTH + 1]; - jstring jString = NULL; - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion.\n"); - name[0] = 0; - -#if USE_PLATFORM_MIDI_OUT == TRUE - MIDI_OUT_GetDeviceVersion((INT32)index, name, (UINT32)MAX_STRING_LENGTH); -#endif - if (name[0] == 0) { - strcpy(name, "Unknown version"); - } - jString = (*e)->NewStringUTF(e, name); - - TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion completed.\n"); - - return jString; -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/MidiOutDeviceProvider.c 2018-03-15 02:00:47.954586504 +0100 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1999, 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 +#include "SoundDefs.h" +#include "PlatformMidi.h" +#include "Utilities.h" +// for strcpy +#include +#include "com_sun_media_sound_MidiOutDeviceProvider.h" + + +#define MAX_STRING_LENGTH 128 + + +JNIEXPORT jint JNICALL +Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices(JNIEnv* e, jobject thisObj) { + + INT32 numDevices = 0; + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices.\n"); + +#if USE_PLATFORM_MIDI_OUT == TRUE + numDevices = MIDI_OUT_GetNumDevices(); +#endif + + TRACE1("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices returning %d.\n", (int) numDevices); + return (jint) numDevices; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_GetDeviceName((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "Unknown name"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_GetDeviceVendor((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "Unknown vendor"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_GetDeviceDescription((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + + if (name[0] == 0) { + strcpy(name, "No details available"); + } + jString = (*e)->NewStringUTF(e, name); + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription completed.\n"); + return jString; +} + + +JNIEXPORT jstring JNICALL +Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion(JNIEnv* e, jobject thisObj, jint index) { + + char name[MAX_STRING_LENGTH + 1]; + jstring jString = NULL; + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion.\n"); + name[0] = 0; + +#if USE_PLATFORM_MIDI_OUT == TRUE + MIDI_OUT_GetDeviceVersion((INT32)index, name, (UINT32)MAX_STRING_LENGTH); +#endif + if (name[0] == 0) { + strcpy(name, "Unknown version"); + } + jString = (*e)->NewStringUTF(e, name); + + TRACE0("Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion completed.\n"); + + return jString; +} --- old/src/java.desktop/share/native/libjsound/PlatformMidi.c 2018-03-15 02:00:48.694586498 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2002, 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 "PlatformMidi.h" - -#include - -char* GetInternalErrorStr(INT32 err) { - switch (err) { - case MIDI_SUCCESS: return ""; - case MIDI_NOT_SUPPORTED: return "feature not supported"; - case MIDI_INVALID_DEVICEID: return "invalid device ID"; - case MIDI_INVALID_HANDLE: return "internal error: invalid handle"; - case MIDI_OUT_OF_MEMORY: return "out of memory"; - } - return NULL; -} - -/* - * internal implementation for getting error string - */ -char* MIDI_IN_InternalGetErrorString(INT32 err) { - char* result = GetInternalErrorStr(err); - -#if USE_PLATFORM_MIDI_IN == TRUE - if (!result) { - result = MIDI_IN_GetErrorStr(err); - } -#endif - if (!result) { - result = GetInternalErrorStr(MIDI_NOT_SUPPORTED); - } - return result; -} - -/* - * internal implementation for getting error string - */ -char* MIDI_OUT_InternalGetErrorString(INT32 err) { - char* result = GetInternalErrorStr(err); - -#if USE_PLATFORM_MIDI_OUT == TRUE - if (!result) { - result = MIDI_OUT_GetErrorStr(err); - } -#endif - if (!result) { - result = GetInternalErrorStr(MIDI_NOT_SUPPORTED); - } - return result; -} - - -#if USE_MIDI_QUEUE == TRUE - -// MessageQueue implementation - -MidiMessageQueue* MIDI_CreateQueue(int capacity) { - MidiMessageQueue* queue = (MidiMessageQueue*) malloc(sizeof(MidiMessageQueue) + ((capacity-1) * sizeof(MidiMessage))); - if (queue) { - TRACE0("MIDI_CreateQueue\n"); - queue->lock = MIDI_CreateLock(); - queue->capacity = capacity; - queue->size = 0; - queue->readIndex = 0; - queue->writeIndex = 0; - } - return queue; -} - -void MIDI_DestroyQueue(MidiMessageQueue* queue) { - if (queue) { - void* lock = queue->lock; - MIDI_Lock(lock); - free(queue); - MIDI_Unlock(lock); - MIDI_DestroyLock(lock); - TRACE0("MIDI_DestroyQueue\n"); - } -} - -// if overwrite is true, oldest messages will be overwritten when the queue is full -// returns true, if message has been added -int MIDI_QueueAddShort(MidiMessageQueue* queue, UINT32 packedMsg, INT64 timestamp, int overwrite) { - if (queue) { - MIDI_Lock(queue->lock); - if (queue->size == queue->capacity) { - TRACE0("MIDI_QueueAddShort: overflow\n"); - if (!overwrite || queue->queue[queue->writeIndex].locked) { - return FALSE; // failed - } - // adjust overwritten readIndex - queue->readIndex = (queue->readIndex+1) % queue->capacity; - } else { - queue->size++; - } - TRACE2("MIDI_QueueAddShort. index=%d, size=%d\n", queue->writeIndex, queue->size); - queue->queue[queue->writeIndex].type = SHORT_MESSAGE; - queue->queue[queue->writeIndex].data.s.packedMsg = packedMsg; - queue->queue[queue->writeIndex].timestamp = timestamp; - queue->writeIndex = (queue->writeIndex+1) % queue->capacity; - MIDI_Unlock(queue->lock); - return TRUE; - } - return FALSE; -} - -int MIDI_QueueAddLong(MidiMessageQueue* queue, UBYTE* data, UINT32 size, - INT32 sysexIndex, INT64 timestamp, int overwrite) { - if (queue) { - MIDI_Lock(queue->lock); - if (queue->size == queue->capacity) { - TRACE0("MIDI_QueueAddLong: overflow\n"); - if (!overwrite || queue->queue[queue->writeIndex].locked) { - return FALSE; // failed - } - // adjust overwritten readIndex - queue->readIndex = (queue->readIndex+1) % queue->capacity; - } else { - queue->size++; - } - TRACE2("MIDI_QueueAddLong. index=%d, size=%d\n", queue->writeIndex, queue->size); - //fprintf(stdout, "MIDI_QueueAddLong sysex-index %d\n", sysexIndex); fflush(stdout); - queue->queue[queue->writeIndex].type = LONG_MESSAGE; - queue->queue[queue->writeIndex].data.l.size = size; - queue->queue[queue->writeIndex].data.l.data = data; - queue->queue[queue->writeIndex].data.l.index = sysexIndex; - queue->queue[queue->writeIndex].timestamp = timestamp; - queue->writeIndex = (queue->writeIndex+1) % queue->capacity; - MIDI_Unlock(queue->lock); - return TRUE; - } - return FALSE; -} - -// returns NULL if no messages in queue. -MidiMessage* MIDI_QueueRead(MidiMessageQueue* queue) { - MidiMessage* msg = NULL; - if (queue) { - MIDI_Lock(queue->lock); - if (queue->size > 0) { - msg = &(queue->queue[queue->readIndex]); - TRACE2("MIDI_QueueRead. index=%d, size=%d\n", queue->readIndex, queue->size); - msg->locked = TRUE; - } - MIDI_Unlock(queue->lock); - } - return msg; -} - -void MIDI_QueueRemove(MidiMessageQueue* queue, INT32 onlyLocked) { - if (queue) { - MIDI_Lock(queue->lock); - if (queue->size > 0) { - MidiMessage* msg = &(queue->queue[queue->readIndex]); - if (!onlyLocked || msg->locked) { - TRACE2("MIDI_QueueRemove. index=%d, size=%d\n", queue->readIndex, queue->size); - queue->readIndex = (queue->readIndex+1) % queue->capacity; - queue->size--; - } - msg->locked = FALSE; - } - MIDI_Unlock(queue->lock); - } -} - -void MIDI_QueueClear(MidiMessageQueue* queue) { - if (queue) { - MIDI_Lock(queue->lock); - queue->size = 0; - queue->readIndex = 0; - queue->writeIndex = 0; - MIDI_Unlock(queue->lock); - } -} - -#endif --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/PlatformMidi.c 2018-03-15 02:00:48.410586500 +0100 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2002, 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 "PlatformMidi.h" + +#include + +char* GetInternalErrorStr(INT32 err) { + switch (err) { + case MIDI_SUCCESS: return ""; + case MIDI_NOT_SUPPORTED: return "feature not supported"; + case MIDI_INVALID_DEVICEID: return "invalid device ID"; + case MIDI_INVALID_HANDLE: return "internal error: invalid handle"; + case MIDI_OUT_OF_MEMORY: return "out of memory"; + } + return NULL; +} + +/* + * internal implementation for getting error string + */ +char* MIDI_IN_InternalGetErrorString(INT32 err) { + char* result = GetInternalErrorStr(err); + +#if USE_PLATFORM_MIDI_IN == TRUE + if (!result) { + result = MIDI_IN_GetErrorStr(err); + } +#endif + if (!result) { + result = GetInternalErrorStr(MIDI_NOT_SUPPORTED); + } + return result; +} + +/* + * internal implementation for getting error string + */ +char* MIDI_OUT_InternalGetErrorString(INT32 err) { + char* result = GetInternalErrorStr(err); + +#if USE_PLATFORM_MIDI_OUT == TRUE + if (!result) { + result = MIDI_OUT_GetErrorStr(err); + } +#endif + if (!result) { + result = GetInternalErrorStr(MIDI_NOT_SUPPORTED); + } + return result; +} + + +#if USE_MIDI_QUEUE == TRUE + +// MessageQueue implementation + +MidiMessageQueue* MIDI_CreateQueue(int capacity) { + MidiMessageQueue* queue = (MidiMessageQueue*) malloc(sizeof(MidiMessageQueue) + ((capacity-1) * sizeof(MidiMessage))); + if (queue) { + TRACE0("MIDI_CreateQueue\n"); + queue->lock = MIDI_CreateLock(); + queue->capacity = capacity; + queue->size = 0; + queue->readIndex = 0; + queue->writeIndex = 0; + } + return queue; +} + +void MIDI_DestroyQueue(MidiMessageQueue* queue) { + if (queue) { + void* lock = queue->lock; + MIDI_Lock(lock); + free(queue); + MIDI_Unlock(lock); + MIDI_DestroyLock(lock); + TRACE0("MIDI_DestroyQueue\n"); + } +} + +// if overwrite is true, oldest messages will be overwritten when the queue is full +// returns true, if message has been added +int MIDI_QueueAddShort(MidiMessageQueue* queue, UINT32 packedMsg, INT64 timestamp, int overwrite) { + if (queue) { + MIDI_Lock(queue->lock); + if (queue->size == queue->capacity) { + TRACE0("MIDI_QueueAddShort: overflow\n"); + if (!overwrite || queue->queue[queue->writeIndex].locked) { + return FALSE; // failed + } + // adjust overwritten readIndex + queue->readIndex = (queue->readIndex+1) % queue->capacity; + } else { + queue->size++; + } + TRACE2("MIDI_QueueAddShort. index=%d, size=%d\n", queue->writeIndex, queue->size); + queue->queue[queue->writeIndex].type = SHORT_MESSAGE; + queue->queue[queue->writeIndex].data.s.packedMsg = packedMsg; + queue->queue[queue->writeIndex].timestamp = timestamp; + queue->writeIndex = (queue->writeIndex+1) % queue->capacity; + MIDI_Unlock(queue->lock); + return TRUE; + } + return FALSE; +} + +int MIDI_QueueAddLong(MidiMessageQueue* queue, UBYTE* data, UINT32 size, + INT32 sysexIndex, INT64 timestamp, int overwrite) { + if (queue) { + MIDI_Lock(queue->lock); + if (queue->size == queue->capacity) { + TRACE0("MIDI_QueueAddLong: overflow\n"); + if (!overwrite || queue->queue[queue->writeIndex].locked) { + return FALSE; // failed + } + // adjust overwritten readIndex + queue->readIndex = (queue->readIndex+1) % queue->capacity; + } else { + queue->size++; + } + TRACE2("MIDI_QueueAddLong. index=%d, size=%d\n", queue->writeIndex, queue->size); + //fprintf(stdout, "MIDI_QueueAddLong sysex-index %d\n", sysexIndex); fflush(stdout); + queue->queue[queue->writeIndex].type = LONG_MESSAGE; + queue->queue[queue->writeIndex].data.l.size = size; + queue->queue[queue->writeIndex].data.l.data = data; + queue->queue[queue->writeIndex].data.l.index = sysexIndex; + queue->queue[queue->writeIndex].timestamp = timestamp; + queue->writeIndex = (queue->writeIndex+1) % queue->capacity; + MIDI_Unlock(queue->lock); + return TRUE; + } + return FALSE; +} + +// returns NULL if no messages in queue. +MidiMessage* MIDI_QueueRead(MidiMessageQueue* queue) { + MidiMessage* msg = NULL; + if (queue) { + MIDI_Lock(queue->lock); + if (queue->size > 0) { + msg = &(queue->queue[queue->readIndex]); + TRACE2("MIDI_QueueRead. index=%d, size=%d\n", queue->readIndex, queue->size); + msg->locked = TRUE; + } + MIDI_Unlock(queue->lock); + } + return msg; +} + +void MIDI_QueueRemove(MidiMessageQueue* queue, INT32 onlyLocked) { + if (queue) { + MIDI_Lock(queue->lock); + if (queue->size > 0) { + MidiMessage* msg = &(queue->queue[queue->readIndex]); + if (!onlyLocked || msg->locked) { + TRACE2("MIDI_QueueRemove. index=%d, size=%d\n", queue->readIndex, queue->size); + queue->readIndex = (queue->readIndex+1) % queue->capacity; + queue->size--; + } + msg->locked = FALSE; + } + MIDI_Unlock(queue->lock); + } +} + +void MIDI_QueueClear(MidiMessageQueue* queue) { + if (queue) { + MIDI_Lock(queue->lock); + queue->size = 0; + queue->readIndex = 0; + queue->writeIndex = 0; + MIDI_Unlock(queue->lock); + } +} + +#endif --- old/src/java.desktop/share/native/libjsound/PlatformMidi.h 2018-03-15 02:00:49.174586495 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,335 +0,0 @@ -/* - * Copyright (c) 1999, 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. - */ - -#ifndef PLATFORM_MIDI_INCLUDED -#define PLATFORM_MIDI_INCLUDED - - -#include "SoundDefs.h" -#include "Configure.h" // put flags for debug msgs etc. here -#include "Utilities.h" - - -/* do we need the queue ? */ -#if (USE_PLATFORM_MIDI_IN == TRUE) || (USE_PLATFORM_MIDI_OUT == TRUE) - #if X_PLATFORM == X_WINDOWS || X_PLATFORM == X_MACOSX - #define USE_MIDI_QUEUE TRUE - #endif -#endif - -/* *********************** MIDI TYPES (for all platforms) ******************************* */ - -/* return value for functions to denote successful completion */ -#define MIDI_SUCCESS 0 -/* code if function is not supported */ -#define MIDI_NOT_SUPPORTED -11111 -/* return code for invalid handle */ -#define MIDI_INVALID_DEVICEID -11112 -/* return code for invalid handle */ -#define MIDI_INVALID_HANDLE -11113 -/* return code for invalid argument */ -#define MIDI_INVALID_ARGUMENT -11114 -/* return code for out of memory */ -#define MIDI_OUT_OF_MEMORY -11115 - -// MIDI message types -typedef enum { - SHORT_MESSAGE = 0, - LONG_MESSAGE = 1 -} MidiMessageType; - -// MIDI message object -typedef struct tag_MidiMessage { - INT64 timestamp; // in microseconds - INT32 locked; // TRUE when event is currently being read - MidiMessageType type; - union { - struct { - // platform-endianness packed message: - // status | data1<<8 | data2<<16 - UINT32 packedMsg; - } s; // short message - struct { - UINT32 size; - // this buffer is read only. It must not be freed. - UBYTE* data; - INT32 index; // sysex buffer number - } l; // long message - } data; -} MidiMessage; - -/* error handling. Implemented in PlatformMidi.c */ -char* MIDI_IN_InternalGetErrorString(INT32 err); -char* MIDI_OUT_InternalGetErrorString(INT32 err); - - -#if USE_MIDI_QUEUE == TRUE -/* - * Native MIDI message circular buffer - */ -typedef struct tag_MidiQueue { - void* lock; - INT32 size; - INT32 capacity; - INT32 readIndex; - INT32 writeIndex; - MidiMessage queue[1]; -} MidiMessageQueue; -#endif - -// device handle, to be created and filled in MIDI_IN_OpenDevice() and MIDI_OUT_OpenDevice() -typedef struct tag_MidiDeviceHandle { - void* deviceHandle; // handle to the device - void* longBuffers; // contains platform-specific data for long buffers, e.g. list of MIDIHDR - void* platformData; // contains platform specific data, e.g. an Event object - INT32 isWaiting; // if TRUE, then waiting for new events - INT64 startTime; // start time -#if USE_MIDI_QUEUE == TRUE - MidiMessageQueue* queue; // may be NULL if no queue is used -#endif -} MidiDeviceHandle; - - -#if USE_MIDI_QUEUE == TRUE - -/* - * Native Locking support - */ -void* MIDI_CreateLock(); -void MIDI_DestroyLock(void* lock); - -/* Blocks until this lock can be gotten. - * Nop if lock is NULL */ -void MIDI_Lock(void* lock); - -/* Releases this lock */ -void MIDI_Unlock(void* lock); - -MidiMessageQueue* MIDI_CreateQueue(int capacity); -void MIDI_DestroyQueue(MidiMessageQueue* queue); -// if overwrite is true, oldest messages will be overwritten when the queue is full -// returns true, if message has been added -int MIDI_QueueAddShort(MidiMessageQueue* queue, UINT32 packedMsg, INT64 timestamp, int overwrite); -int MIDI_QueueAddLong(MidiMessageQueue* queue, UBYTE* data, UINT32 size, - INT32 sysexIndex, INT64 timestamp, int overwrite); - -// returns NULL if no messages in queue. -MidiMessage* MIDI_QueueRead(MidiMessageQueue* queue); -// message will be removed from queue. -void MIDI_QueueRemove(MidiMessageQueue* queue, INT32 onlyLocked); -void MIDI_QueueClear(MidiMessageQueue* queue); - -#endif /* USE_MIDI_QUEUE */ - - -/* - * Platform MIDI IN support. - * deviceId: device-by-number - * deviceHandle: native device handle - */ - -#if USE_PLATFORM_MIDI_IN == TRUE - -// number of messages to be buffered -#define MIDI_IN_MESSAGE_QUEUE_SIZE 64 -// number of sysex to be buffered -#define MIDI_IN_LONG_QUEUE_SIZE 20 -// maximum number of bytes in one sys ex message -#define MIDI_IN_LONG_MESSAGE_SIZE 1024 - - -/* - * Return an error message for the error code - */ -char* MIDI_IN_GetErrorStr(INT32 err); - - -/* - * Get the number of MIDI IN devices on the system. - */ -INT32 MIDI_IN_GetNumDevices(); - -/* - * Get the name of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the vendor of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the description of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the version of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Open the device with this id. - * Returns a device handle in handle*. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle); - -/* - * Close the device handle. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle); - -/* - * Start the device with this handle. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle); - -/* - * Stop the device with this handle. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle); - -/* - * Return the current time stamp in microseconds. - * If not supported, or problem occurred, returns -1 - */ -INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle); - -/* - * Get the next message from the queue. - * This call blocks until the device is stopped - * or a message is received. - * The returned message is READ ONLY. - * The message will be returned into the message - * queue by calling MIDI_IN_ReleaseMessage. - */ -MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle); - -/* - * Put a message, which was taken - * out of the queue, back into the queue. - */ -void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg); - -#endif // USE_PLATFORM_MIDI_IN - - -/* - * Platform MIDI OUT support. - * deviceId: device-by-number - * deviceHandle: native device handle - */ - -#if USE_PLATFORM_MIDI_OUT == TRUE - -// number of messages to be buffered -#define MIDI_OUT_MESSAGE_QUEUE_SIZE 32 -// number of sysex to be buffered -#define MIDI_OUT_LONG_QUEUE_SIZE 16 -// maximum number of bytes in one sys ex message -#define MIDI_OUT_LONG_MESSAGE_SIZE 1024 - -/* - * Return an error message for the error code - */ -char* MIDI_OUT_GetErrorStr(INT32 err); - - -/* - * Get the number of MIDI OUT devices on the system. - */ -INT32 MIDI_OUT_GetNumDevices(); - -/* - * Get the name of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the vendor of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the description of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Get the version of the device with this id - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength); - -/* - * Open the device with this id. - * Returns a device handle in handle*. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle); - -/* - * Close the device handle. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle); - -/* - * Return the current time stamp in microseconds (the time since the device - * was opened). - * If not supported, or problem occurred, returns -1 - */ -INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle); - -/* - * Send a short message to the hardware. - * packedMsg: (status | data1<<8 | data2<<16) in platform-endianness - * Timestamp is in microseconds. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp); - -/* - * Send a long message to the hardware. Timestamp is in microseconds. - * This blocks until a slot to send a message is free. - * Returns MIDI_SUCCESS or an error code - */ -INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp); - -#endif // USE_PLATFORM_MIDI_OUT - -#endif // PLATFORM_MIDI_INCLUDED --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/PlatformMidi.h 2018-03-15 02:00:48.854586497 +0100 @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1999, 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. + */ + +#ifndef PLATFORM_MIDI_INCLUDED +#define PLATFORM_MIDI_INCLUDED + + +#include "SoundDefs.h" +#include "Configure.h" // put flags for debug msgs etc. here +#include "Utilities.h" + + +/* do we need the queue ? */ +#if (USE_PLATFORM_MIDI_IN == TRUE) || (USE_PLATFORM_MIDI_OUT == TRUE) + #if X_PLATFORM == X_WINDOWS || X_PLATFORM == X_MACOSX + #define USE_MIDI_QUEUE TRUE + #endif +#endif + +/* *********************** MIDI TYPES (for all platforms) ******************************* */ + +/* return value for functions to denote successful completion */ +#define MIDI_SUCCESS 0 +/* code if function is not supported */ +#define MIDI_NOT_SUPPORTED -11111 +/* return code for invalid handle */ +#define MIDI_INVALID_DEVICEID -11112 +/* return code for invalid handle */ +#define MIDI_INVALID_HANDLE -11113 +/* return code for invalid argument */ +#define MIDI_INVALID_ARGUMENT -11114 +/* return code for out of memory */ +#define MIDI_OUT_OF_MEMORY -11115 + +// MIDI message types +typedef enum { + SHORT_MESSAGE = 0, + LONG_MESSAGE = 1 +} MidiMessageType; + +// MIDI message object +typedef struct tag_MidiMessage { + INT64 timestamp; // in microseconds + INT32 locked; // TRUE when event is currently being read + MidiMessageType type; + union { + struct { + // platform-endianness packed message: + // status | data1<<8 | data2<<16 + UINT32 packedMsg; + } s; // short message + struct { + UINT32 size; + // this buffer is read only. It must not be freed. + UBYTE* data; + INT32 index; // sysex buffer number + } l; // long message + } data; +} MidiMessage; + +/* error handling. Implemented in PlatformMidi.c */ +char* MIDI_IN_InternalGetErrorString(INT32 err); +char* MIDI_OUT_InternalGetErrorString(INT32 err); + + +#if USE_MIDI_QUEUE == TRUE +/* + * Native MIDI message circular buffer + */ +typedef struct tag_MidiQueue { + void* lock; + INT32 size; + INT32 capacity; + INT32 readIndex; + INT32 writeIndex; + MidiMessage queue[1]; +} MidiMessageQueue; +#endif + +// device handle, to be created and filled in MIDI_IN_OpenDevice() and MIDI_OUT_OpenDevice() +typedef struct tag_MidiDeviceHandle { + void* deviceHandle; // handle to the device + void* longBuffers; // contains platform-specific data for long buffers, e.g. list of MIDIHDR + void* platformData; // contains platform specific data, e.g. an Event object + INT32 isWaiting; // if TRUE, then waiting for new events + INT64 startTime; // start time +#if USE_MIDI_QUEUE == TRUE + MidiMessageQueue* queue; // may be NULL if no queue is used +#endif +} MidiDeviceHandle; + + +#if USE_MIDI_QUEUE == TRUE + +/* + * Native Locking support + */ +void* MIDI_CreateLock(); +void MIDI_DestroyLock(void* lock); + +/* Blocks until this lock can be gotten. + * Nop if lock is NULL */ +void MIDI_Lock(void* lock); + +/* Releases this lock */ +void MIDI_Unlock(void* lock); + +MidiMessageQueue* MIDI_CreateQueue(int capacity); +void MIDI_DestroyQueue(MidiMessageQueue* queue); +// if overwrite is true, oldest messages will be overwritten when the queue is full +// returns true, if message has been added +int MIDI_QueueAddShort(MidiMessageQueue* queue, UINT32 packedMsg, INT64 timestamp, int overwrite); +int MIDI_QueueAddLong(MidiMessageQueue* queue, UBYTE* data, UINT32 size, + INT32 sysexIndex, INT64 timestamp, int overwrite); + +// returns NULL if no messages in queue. +MidiMessage* MIDI_QueueRead(MidiMessageQueue* queue); +// message will be removed from queue. +void MIDI_QueueRemove(MidiMessageQueue* queue, INT32 onlyLocked); +void MIDI_QueueClear(MidiMessageQueue* queue); + +#endif /* USE_MIDI_QUEUE */ + + +/* + * Platform MIDI IN support. + * deviceId: device-by-number + * deviceHandle: native device handle + */ + +#if USE_PLATFORM_MIDI_IN == TRUE + +// number of messages to be buffered +#define MIDI_IN_MESSAGE_QUEUE_SIZE 64 +// number of sysex to be buffered +#define MIDI_IN_LONG_QUEUE_SIZE 20 +// maximum number of bytes in one sys ex message +#define MIDI_IN_LONG_MESSAGE_SIZE 1024 + + +/* + * Return an error message for the error code + */ +char* MIDI_IN_GetErrorStr(INT32 err); + + +/* + * Get the number of MIDI IN devices on the system. + */ +INT32 MIDI_IN_GetNumDevices(); + +/* + * Get the name of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the vendor of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the description of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the version of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Open the device with this id. + * Returns a device handle in handle*. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle); + +/* + * Close the device handle. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle); + +/* + * Start the device with this handle. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle); + +/* + * Stop the device with this handle. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle); + +/* + * Return the current time stamp in microseconds. + * If not supported, or problem occurred, returns -1 + */ +INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle); + +/* + * Get the next message from the queue. + * This call blocks until the device is stopped + * or a message is received. + * The returned message is READ ONLY. + * The message will be returned into the message + * queue by calling MIDI_IN_ReleaseMessage. + */ +MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle); + +/* + * Put a message, which was taken + * out of the queue, back into the queue. + */ +void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg); + +#endif // USE_PLATFORM_MIDI_IN + + +/* + * Platform MIDI OUT support. + * deviceId: device-by-number + * deviceHandle: native device handle + */ + +#if USE_PLATFORM_MIDI_OUT == TRUE + +// number of messages to be buffered +#define MIDI_OUT_MESSAGE_QUEUE_SIZE 32 +// number of sysex to be buffered +#define MIDI_OUT_LONG_QUEUE_SIZE 16 +// maximum number of bytes in one sys ex message +#define MIDI_OUT_LONG_MESSAGE_SIZE 1024 + +/* + * Return an error message for the error code + */ +char* MIDI_OUT_GetErrorStr(INT32 err); + + +/* + * Get the number of MIDI OUT devices on the system. + */ +INT32 MIDI_OUT_GetNumDevices(); + +/* + * Get the name of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the vendor of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the description of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Get the version of the device with this id + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength); + +/* + * Open the device with this id. + * Returns a device handle in handle*. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle); + +/* + * Close the device handle. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle); + +/* + * Return the current time stamp in microseconds (the time since the device + * was opened). + * If not supported, or problem occurred, returns -1 + */ +INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle); + +/* + * Send a short message to the hardware. + * packedMsg: (status | data1<<8 | data2<<16) in platform-endianness + * Timestamp is in microseconds. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp); + +/* + * Send a long message to the hardware. Timestamp is in microseconds. + * This blocks until a slot to send a message is free. + * Returns MIDI_SUCCESS or an error code + */ +INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp); + +#endif // USE_PLATFORM_MIDI_OUT + +#endif // PLATFORM_MIDI_INCLUDED --- old/src/java.desktop/share/native/libjsound/PortMixer.c 2018-03-15 02:00:49.674586491 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,377 +0,0 @@ -/* - * Copyright (c) 2002, 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_TRACE -#define USE_ERROR - - -#include -#include -#include "SoundDefs.h" -#include "Ports.h" -#include "Utilities.h" -#include "com_sun_media_sound_PortMixer.h" - - -//////////////////////////////////////////// PortMixer //////////////////////////////////////////// - -JNIEXPORT jlong JNICALL Java_com_sun_media_sound_PortMixer_nOpen - (JNIEnv *env, jclass cls, jint mixerIndex) { - - jlong ret = 0; -#if USE_PORTS == TRUE - ret = (jlong) (INT_PTR) PORT_Open(mixerIndex); -#endif - return ret; -} - -JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nClose - (JNIEnv *env, jclass cls, jlong id) { - -#if USE_PORTS == TRUE - if (id != 0) { - PORT_Close((void*) (INT_PTR) id); - } -#endif -} - -JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortCount - (JNIEnv *env, jclass cls, jlong id) { - - jint ret = 0; -#if USE_PORTS == TRUE - if (id != 0) { - ret = (jint) PORT_GetPortCount((void*) (INT_PTR) id); - } -#endif - return ret; -} - - -JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortType - (JNIEnv *env, jclass cls, jlong id, jint portIndex) { - - jint ret = 0; - TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortType(%d).\n", portIndex); - -#if USE_PORTS == TRUE - if (id != 0) { - ret = (jint) PORT_GetPortType((void*) (INT_PTR) id, portIndex); - } -#endif - - TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetPortType returning %d.\n", ret); - return ret; -} - -JNIEXPORT jstring JNICALL Java_com_sun_media_sound_PortMixer_nGetPortName - (JNIEnv *env, jclass cls, jlong id, jint portIndex) { - - char str[PORT_STRING_LENGTH]; - jstring jString = NULL; - TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortName(%d).\n", portIndex); - - str[0] = 0; -#if USE_PORTS == TRUE - if (id != 0) { - PORT_GetPortName((void*) (INT_PTR) id, portIndex, str, PORT_STRING_LENGTH); - } -#endif - jString = (*env)->NewStringUTF(env, str); - - TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetName returning \"%s\".\n", str); - return jString; -} - -JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetIntValue - (JNIEnv *env, jclass cls, jlong controlID, jint value) { -#if USE_PORTS == TRUE - if (controlID != 0) { - PORT_SetIntValue((void*) (UINT_PTR) controlID, (INT32) value); - } -#endif -} - -JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nControlGetIntValue - (JNIEnv *env, jclass cls, jlong controlID) { - INT32 ret = 0; -#if USE_PORTS == TRUE - if (controlID != 0) { - ret = PORT_GetIntValue((void*) (UINT_PTR) controlID); - } -#endif - return (jint) ret; -} - -JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetFloatValue - (JNIEnv *env, jclass cls, jlong controlID, jfloat value) { -#if USE_PORTS == TRUE - if (controlID != 0) { - PORT_SetFloatValue((void*) (UINT_PTR) controlID, (float) value); - } -#endif -} - -JNIEXPORT jfloat JNICALL Java_com_sun_media_sound_PortMixer_nControlGetFloatValue - (JNIEnv *env, jclass cls, jlong controlID) { - float ret = 0; -#if USE_PORTS == TRUE - if (controlID != 0) { - ret = PORT_GetFloatValue((void*) (UINT_PTR) controlID); - } -#endif - return (jfloat) ret; -} - -/* ************************************** native control creation support ********************* */ - -// contains all the needed references so that the platform dependent code can call JNI wrapper functions -typedef struct tag_ControlCreatorJNI { - // this member is seen by the platform dependent code - PortControlCreator creator; - // general JNI variables - JNIEnv *env; - // the vector to be filled with controls (initialized before usage) - jobject vector; - jmethodID vectorAddElement; - // control specific constructors (initialized on demand) - jclass boolCtrlClass; - jmethodID boolCtrlConstructor; // signature (JLjava/lang/String;)V - jclass controlClass; // class of javax.sound.sampled.Control - jclass compCtrlClass; - jmethodID compCtrlConstructor; // signature (Ljava/lang/String;[Ljavax/sound/sampled/Control;)V - jclass floatCtrlClass; - jmethodID floatCtrlConstructor1; // signature (JLjava/lang/String;FFFLjava/lang/String;)V - jmethodID floatCtrlConstructor2; // signature (JIFFFLjava/lang/String;)V -} ControlCreatorJNI; - - -void* PORT_NewBooleanControl(void* creatorV, void* controlID, char* type) { - ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; - jobject ctrl = NULL; - jstring typeString; - -#ifdef USE_TRACE - if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { - TRACE1("PORT_NewBooleanControl: creating '%d'\n", (int) (UINT_PTR) type); - } else { - TRACE1("PORT_NewBooleanControl: creating '%s'\n", type); - } -#endif - if (!creator->boolCtrlClass) { - // retrieve class and constructor of PortMixer.BoolCtrl - creator->boolCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$BoolCtrl"); - if (!creator->boolCtrlClass) { - ERROR0("PORT_NewBooleanControl: boolCtrlClass is NULL\n"); - return NULL; - } - creator->boolCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->boolCtrlClass, - "", "(JLjava/lang/String;)V"); - if (!creator->boolCtrlConstructor) { - ERROR0("PORT_NewBooleanControl: boolCtrlConstructor is NULL\n"); - return NULL; - } - } - if (type == CONTROL_TYPE_MUTE) { - type = "Mute"; - } - else if (type == CONTROL_TYPE_SELECT) { - type = "Select"; - } - - typeString = (*creator->env)->NewStringUTF(creator->env, type); - CHECK_NULL_RETURN(typeString, (void*) ctrl); - ctrl = (*creator->env)->NewObject(creator->env, creator->boolCtrlClass, - creator->boolCtrlConstructor, - (jlong) (UINT_PTR) controlID, typeString); - if (!ctrl) { - ERROR0("PORT_NewBooleanControl: ctrl is NULL\n"); - } - if ((*creator->env)->ExceptionOccurred(creator->env)) { - ERROR0("PORT_NewBooleanControl: ExceptionOccurred!\n"); - } - TRACE0("PORT_NewBooleanControl succeeded\n"); - return (void*) ctrl; -} - -void* PORT_NewCompoundControl(void* creatorV, char* type, void** controls, int controlCount) { - ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; - jobject ctrl = NULL; - jobjectArray controlArray; - int i; - jstring typeString; - - TRACE2("PORT_NewCompoundControl: creating '%s' with %d controls\n", type, controlCount); - if (!creator->compCtrlClass) { - TRACE0("PORT_NewCompoundControl: retrieve method ids\n"); - // retrieve class and constructor of PortMixer.BoolCtrl - creator->compCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$CompCtrl"); - if (!creator->compCtrlClass) { - ERROR0("PORT_NewCompoundControl: compCtrlClass is NULL\n"); - return NULL; - } - creator->compCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->compCtrlClass, - "", "(Ljava/lang/String;[Ljavax/sound/sampled/Control;)V"); - if (!creator->compCtrlConstructor) { - ERROR0("PORT_NewCompoundControl: compCtrlConstructor is NULL\n"); - return NULL; - } - creator->controlClass = (*creator->env)->FindClass(creator->env, JAVA_SAMPLED_PACKAGE_NAME"/Control"); - if (!creator->controlClass) { - ERROR0("PORT_NewCompoundControl: controlClass is NULL\n"); - return NULL; - } - } - TRACE0("PORT_NewCompoundControl: creating array\n"); - // create new array for the controls - controlArray = (*creator->env)->NewObjectArray(creator->env, controlCount, creator->controlClass, (jobject) NULL); - if (!controlArray) { - ERROR0("PORT_NewCompoundControl: controlArray is NULL\n"); - return NULL; - } - TRACE0("PORT_NewCompoundControl: setting array values\n"); - for (i = 0; i < controlCount; i++) { - (*creator->env)->SetObjectArrayElement(creator->env, controlArray, i, (jobject) controls[i]); - } - TRACE0("PORT_NewCompoundControl: creating compound control\n"); - typeString = (*creator->env)->NewStringUTF(creator->env, type); - CHECK_NULL_RETURN(typeString, (void*) ctrl); - ctrl = (*creator->env)->NewObject(creator->env, creator->compCtrlClass, - creator->compCtrlConstructor, - typeString, controlArray); - if (!ctrl) { - ERROR0("PORT_NewCompoundControl: ctrl is NULL\n"); - } - if ((*creator->env)->ExceptionOccurred(creator->env)) { - ERROR0("PORT_NewCompoundControl: ExceptionOccurred!\n"); - } - TRACE0("PORT_NewCompoundControl succeeded\n"); - return (void*) ctrl; -} - -void* PORT_NewFloatControl(void* creatorV, void* controlID, char* type, - float min, float max, float precision, const char* units) { - ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; - jobject ctrl = NULL; - jstring unitsString; - jstring typeString; - -#ifdef USE_TRACE - if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { - TRACE1("PORT_NewFloatControl: creating '%d'\n", (int) (UINT_PTR) type); - } else { - TRACE1("PORT_NewFloatControl: creating '%s'\n", type); - } -#endif - if (!creator->floatCtrlClass) { - // retrieve class and constructor of PortMixer.BoolCtrl - creator->floatCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$FloatCtrl"); - if (!creator->floatCtrlClass) { - ERROR0("PORT_NewFloatControl: floatCtrlClass is NULL\n"); - return NULL; - } - creator->floatCtrlConstructor1 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass, - "", "(JLjava/lang/String;FFFLjava/lang/String;)V"); - if (!creator->floatCtrlConstructor1) { - ERROR0("PORT_NewFloatControl: floatCtrlConstructor1 is NULL\n"); - return NULL; - } - creator->floatCtrlConstructor2 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass, - "", "(JIFFFLjava/lang/String;)V"); - if (!creator->floatCtrlConstructor2) { - ERROR0("PORT_NewFloatControl: floatCtrlConstructor2 is NULL\n"); - return NULL; - } - } - unitsString = (*creator->env)->NewStringUTF(creator->env, units); - CHECK_NULL_RETURN(unitsString, (void*) ctrl); - if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { - // constructor with int parameter - TRACE1("PORT_NewFloatControl: calling constructor2 with type %d\n", (int) (UINT_PTR) type); - ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass, - creator->floatCtrlConstructor2, - (jlong) (UINT_PTR) controlID, (jint) (UINT_PTR) type, - min, max, precision, unitsString); - } else { - TRACE0("PORT_NewFloatControl: calling constructor1\n"); - // constructor with string parameter - typeString = (*creator->env)->NewStringUTF(creator->env, type); - CHECK_NULL_RETURN(typeString, (void*) ctrl); - ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass, - creator->floatCtrlConstructor1, - (jlong) (UINT_PTR) controlID, typeString, - min, max, precision, unitsString); - } - if (!ctrl) { - ERROR0("PORT_NewFloatControl: ctrl is NULL!\n"); - } - if ((*creator->env)->ExceptionOccurred(creator->env)) { - ERROR0("PORT_NewFloatControl: ExceptionOccurred!\n"); - } - TRACE1("PORT_NewFloatControl succeeded %p\n", (void*) ctrl); - return (void*) ctrl; -} - -int PORT_AddControl(void* creatorV, void* control) { - ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; - - TRACE1("PORT_AddControl %p\n", (void*) control); - (*creator->env)->CallVoidMethod(creator->env, creator->vector, creator->vectorAddElement, (jobject) control); - if ((*creator->env)->ExceptionOccurred(creator->env)) { - ERROR0("PORT_AddControl: ExceptionOccurred!\n"); - } - TRACE0("PORT_AddControl succeeded\n"); - return TRUE; -} - -JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nGetControls - (JNIEnv *env, jclass cls, jlong id, jint portIndex, jobject vector) { - - ControlCreatorJNI creator; - jclass vectorClass; - -#if USE_PORTS == TRUE - if (id != 0) { - memset(&creator, 0, sizeof(ControlCreatorJNI)); - creator.creator.newBooleanControl = &PORT_NewBooleanControl; - creator.creator.newCompoundControl = &PORT_NewCompoundControl; - creator.creator.newFloatControl = &PORT_NewFloatControl; - creator.creator.addControl = &PORT_AddControl; - creator.env = env; - vectorClass = (*env)->GetObjectClass(env, vector); - if (vectorClass == NULL) { - ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: vectorClass is NULL\n"); - return; - } - creator.vector = vector; - creator.vectorAddElement = (*env)->GetMethodID(env, vectorClass, "addElement", "(Ljava/lang/Object;)V"); - if (creator.vectorAddElement == NULL) { - ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: addElementMethodID is NULL\n"); - return; - } - PORT_GetControls((void*) (UINT_PTR) id, (INT32) portIndex, (PortControlCreator*) &creator); - } -#endif -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/PortMixer.c 2018-03-15 02:00:49.354586493 +0100 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2002, 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_TRACE +#define USE_ERROR + + +#include +#include +#include "SoundDefs.h" +#include "Ports.h" +#include "Utilities.h" +#include "com_sun_media_sound_PortMixer.h" + + +//////////////////////////////////////////// PortMixer //////////////////////////////////////////// + +JNIEXPORT jlong JNICALL Java_com_sun_media_sound_PortMixer_nOpen + (JNIEnv *env, jclass cls, jint mixerIndex) { + + jlong ret = 0; +#if USE_PORTS == TRUE + ret = (jlong) (INT_PTR) PORT_Open(mixerIndex); +#endif + return ret; +} + +JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nClose + (JNIEnv *env, jclass cls, jlong id) { + +#if USE_PORTS == TRUE + if (id != 0) { + PORT_Close((void*) (INT_PTR) id); + } +#endif +} + +JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortCount + (JNIEnv *env, jclass cls, jlong id) { + + jint ret = 0; +#if USE_PORTS == TRUE + if (id != 0) { + ret = (jint) PORT_GetPortCount((void*) (INT_PTR) id); + } +#endif + return ret; +} + + +JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nGetPortType + (JNIEnv *env, jclass cls, jlong id, jint portIndex) { + + jint ret = 0; + TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortType(%d).\n", portIndex); + +#if USE_PORTS == TRUE + if (id != 0) { + ret = (jint) PORT_GetPortType((void*) (INT_PTR) id, portIndex); + } +#endif + + TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetPortType returning %d.\n", ret); + return ret; +} + +JNIEXPORT jstring JNICALL Java_com_sun_media_sound_PortMixer_nGetPortName + (JNIEnv *env, jclass cls, jlong id, jint portIndex) { + + char str[PORT_STRING_LENGTH]; + jstring jString = NULL; + TRACE1("Java_com_sun_media_sound_PortMixer_nGetPortName(%d).\n", portIndex); + + str[0] = 0; +#if USE_PORTS == TRUE + if (id != 0) { + PORT_GetPortName((void*) (INT_PTR) id, portIndex, str, PORT_STRING_LENGTH); + } +#endif + jString = (*env)->NewStringUTF(env, str); + + TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetName returning \"%s\".\n", str); + return jString; +} + +JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetIntValue + (JNIEnv *env, jclass cls, jlong controlID, jint value) { +#if USE_PORTS == TRUE + if (controlID != 0) { + PORT_SetIntValue((void*) (UINT_PTR) controlID, (INT32) value); + } +#endif +} + +JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixer_nControlGetIntValue + (JNIEnv *env, jclass cls, jlong controlID) { + INT32 ret = 0; +#if USE_PORTS == TRUE + if (controlID != 0) { + ret = PORT_GetIntValue((void*) (UINT_PTR) controlID); + } +#endif + return (jint) ret; +} + +JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nControlSetFloatValue + (JNIEnv *env, jclass cls, jlong controlID, jfloat value) { +#if USE_PORTS == TRUE + if (controlID != 0) { + PORT_SetFloatValue((void*) (UINT_PTR) controlID, (float) value); + } +#endif +} + +JNIEXPORT jfloat JNICALL Java_com_sun_media_sound_PortMixer_nControlGetFloatValue + (JNIEnv *env, jclass cls, jlong controlID) { + float ret = 0; +#if USE_PORTS == TRUE + if (controlID != 0) { + ret = PORT_GetFloatValue((void*) (UINT_PTR) controlID); + } +#endif + return (jfloat) ret; +} + +/* ************************************** native control creation support ********************* */ + +// contains all the needed references so that the platform dependent code can call JNI wrapper functions +typedef struct tag_ControlCreatorJNI { + // this member is seen by the platform dependent code + PortControlCreator creator; + // general JNI variables + JNIEnv *env; + // the vector to be filled with controls (initialized before usage) + jobject vector; + jmethodID vectorAddElement; + // control specific constructors (initialized on demand) + jclass boolCtrlClass; + jmethodID boolCtrlConstructor; // signature (JLjava/lang/String;)V + jclass controlClass; // class of javax.sound.sampled.Control + jclass compCtrlClass; + jmethodID compCtrlConstructor; // signature (Ljava/lang/String;[Ljavax/sound/sampled/Control;)V + jclass floatCtrlClass; + jmethodID floatCtrlConstructor1; // signature (JLjava/lang/String;FFFLjava/lang/String;)V + jmethodID floatCtrlConstructor2; // signature (JIFFFLjava/lang/String;)V +} ControlCreatorJNI; + + +void* PORT_NewBooleanControl(void* creatorV, void* controlID, char* type) { + ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; + jobject ctrl = NULL; + jstring typeString; + +#ifdef USE_TRACE + if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { + TRACE1("PORT_NewBooleanControl: creating '%d'\n", (int) (UINT_PTR) type); + } else { + TRACE1("PORT_NewBooleanControl: creating '%s'\n", type); + } +#endif + if (!creator->boolCtrlClass) { + // retrieve class and constructor of PortMixer.BoolCtrl + creator->boolCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$BoolCtrl"); + if (!creator->boolCtrlClass) { + ERROR0("PORT_NewBooleanControl: boolCtrlClass is NULL\n"); + return NULL; + } + creator->boolCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->boolCtrlClass, + "", "(JLjava/lang/String;)V"); + if (!creator->boolCtrlConstructor) { + ERROR0("PORT_NewBooleanControl: boolCtrlConstructor is NULL\n"); + return NULL; + } + } + if (type == CONTROL_TYPE_MUTE) { + type = "Mute"; + } + else if (type == CONTROL_TYPE_SELECT) { + type = "Select"; + } + + typeString = (*creator->env)->NewStringUTF(creator->env, type); + CHECK_NULL_RETURN(typeString, (void*) ctrl); + ctrl = (*creator->env)->NewObject(creator->env, creator->boolCtrlClass, + creator->boolCtrlConstructor, + (jlong) (UINT_PTR) controlID, typeString); + if (!ctrl) { + ERROR0("PORT_NewBooleanControl: ctrl is NULL\n"); + } + if ((*creator->env)->ExceptionOccurred(creator->env)) { + ERROR0("PORT_NewBooleanControl: ExceptionOccurred!\n"); + } + TRACE0("PORT_NewBooleanControl succeeded\n"); + return (void*) ctrl; +} + +void* PORT_NewCompoundControl(void* creatorV, char* type, void** controls, int controlCount) { + ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; + jobject ctrl = NULL; + jobjectArray controlArray; + int i; + jstring typeString; + + TRACE2("PORT_NewCompoundControl: creating '%s' with %d controls\n", type, controlCount); + if (!creator->compCtrlClass) { + TRACE0("PORT_NewCompoundControl: retrieve method ids\n"); + // retrieve class and constructor of PortMixer.BoolCtrl + creator->compCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$CompCtrl"); + if (!creator->compCtrlClass) { + ERROR0("PORT_NewCompoundControl: compCtrlClass is NULL\n"); + return NULL; + } + creator->compCtrlConstructor = (*creator->env)->GetMethodID(creator->env, creator->compCtrlClass, + "", "(Ljava/lang/String;[Ljavax/sound/sampled/Control;)V"); + if (!creator->compCtrlConstructor) { + ERROR0("PORT_NewCompoundControl: compCtrlConstructor is NULL\n"); + return NULL; + } + creator->controlClass = (*creator->env)->FindClass(creator->env, JAVA_SAMPLED_PACKAGE_NAME"/Control"); + if (!creator->controlClass) { + ERROR0("PORT_NewCompoundControl: controlClass is NULL\n"); + return NULL; + } + } + TRACE0("PORT_NewCompoundControl: creating array\n"); + // create new array for the controls + controlArray = (*creator->env)->NewObjectArray(creator->env, controlCount, creator->controlClass, (jobject) NULL); + if (!controlArray) { + ERROR0("PORT_NewCompoundControl: controlArray is NULL\n"); + return NULL; + } + TRACE0("PORT_NewCompoundControl: setting array values\n"); + for (i = 0; i < controlCount; i++) { + (*creator->env)->SetObjectArrayElement(creator->env, controlArray, i, (jobject) controls[i]); + } + TRACE0("PORT_NewCompoundControl: creating compound control\n"); + typeString = (*creator->env)->NewStringUTF(creator->env, type); + CHECK_NULL_RETURN(typeString, (void*) ctrl); + ctrl = (*creator->env)->NewObject(creator->env, creator->compCtrlClass, + creator->compCtrlConstructor, + typeString, controlArray); + if (!ctrl) { + ERROR0("PORT_NewCompoundControl: ctrl is NULL\n"); + } + if ((*creator->env)->ExceptionOccurred(creator->env)) { + ERROR0("PORT_NewCompoundControl: ExceptionOccurred!\n"); + } + TRACE0("PORT_NewCompoundControl succeeded\n"); + return (void*) ctrl; +} + +void* PORT_NewFloatControl(void* creatorV, void* controlID, char* type, + float min, float max, float precision, const char* units) { + ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; + jobject ctrl = NULL; + jstring unitsString; + jstring typeString; + +#ifdef USE_TRACE + if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { + TRACE1("PORT_NewFloatControl: creating '%d'\n", (int) (UINT_PTR) type); + } else { + TRACE1("PORT_NewFloatControl: creating '%s'\n", type); + } +#endif + if (!creator->floatCtrlClass) { + // retrieve class and constructor of PortMixer.BoolCtrl + creator->floatCtrlClass = (*creator->env)->FindClass(creator->env, IMPLEMENTATION_PACKAGE_NAME"/PortMixer$FloatCtrl"); + if (!creator->floatCtrlClass) { + ERROR0("PORT_NewFloatControl: floatCtrlClass is NULL\n"); + return NULL; + } + creator->floatCtrlConstructor1 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass, + "", "(JLjava/lang/String;FFFLjava/lang/String;)V"); + if (!creator->floatCtrlConstructor1) { + ERROR0("PORT_NewFloatControl: floatCtrlConstructor1 is NULL\n"); + return NULL; + } + creator->floatCtrlConstructor2 = (*creator->env)->GetMethodID(creator->env, creator->floatCtrlClass, + "", "(JIFFFLjava/lang/String;)V"); + if (!creator->floatCtrlConstructor2) { + ERROR0("PORT_NewFloatControl: floatCtrlConstructor2 is NULL\n"); + return NULL; + } + } + unitsString = (*creator->env)->NewStringUTF(creator->env, units); + CHECK_NULL_RETURN(unitsString, (void*) ctrl); + if (((UINT_PTR) type) <= CONTROL_TYPE_MAX) { + // constructor with int parameter + TRACE1("PORT_NewFloatControl: calling constructor2 with type %d\n", (int) (UINT_PTR) type); + ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass, + creator->floatCtrlConstructor2, + (jlong) (UINT_PTR) controlID, (jint) (UINT_PTR) type, + min, max, precision, unitsString); + } else { + TRACE0("PORT_NewFloatControl: calling constructor1\n"); + // constructor with string parameter + typeString = (*creator->env)->NewStringUTF(creator->env, type); + CHECK_NULL_RETURN(typeString, (void*) ctrl); + ctrl = (*creator->env)->NewObject(creator->env, creator->floatCtrlClass, + creator->floatCtrlConstructor1, + (jlong) (UINT_PTR) controlID, typeString, + min, max, precision, unitsString); + } + if (!ctrl) { + ERROR0("PORT_NewFloatControl: ctrl is NULL!\n"); + } + if ((*creator->env)->ExceptionOccurred(creator->env)) { + ERROR0("PORT_NewFloatControl: ExceptionOccurred!\n"); + } + TRACE1("PORT_NewFloatControl succeeded %p\n", (void*) ctrl); + return (void*) ctrl; +} + +int PORT_AddControl(void* creatorV, void* control) { + ControlCreatorJNI* creator = (ControlCreatorJNI*) creatorV; + + TRACE1("PORT_AddControl %p\n", (void*) control); + (*creator->env)->CallVoidMethod(creator->env, creator->vector, creator->vectorAddElement, (jobject) control); + if ((*creator->env)->ExceptionOccurred(creator->env)) { + ERROR0("PORT_AddControl: ExceptionOccurred!\n"); + } + TRACE0("PORT_AddControl succeeded\n"); + return TRUE; +} + +JNIEXPORT void JNICALL Java_com_sun_media_sound_PortMixer_nGetControls + (JNIEnv *env, jclass cls, jlong id, jint portIndex, jobject vector) { + + ControlCreatorJNI creator; + jclass vectorClass; + +#if USE_PORTS == TRUE + if (id != 0) { + memset(&creator, 0, sizeof(ControlCreatorJNI)); + creator.creator.newBooleanControl = &PORT_NewBooleanControl; + creator.creator.newCompoundControl = &PORT_NewCompoundControl; + creator.creator.newFloatControl = &PORT_NewFloatControl; + creator.creator.addControl = &PORT_AddControl; + creator.env = env; + vectorClass = (*env)->GetObjectClass(env, vector); + if (vectorClass == NULL) { + ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: vectorClass is NULL\n"); + return; + } + creator.vector = vector; + creator.vectorAddElement = (*env)->GetMethodID(env, vectorClass, "addElement", "(Ljava/lang/Object;)V"); + if (creator.vectorAddElement == NULL) { + ERROR0("Java_com_sun_media_sound_PortMixer_nGetControls: addElementMethodID is NULL\n"); + return; + } + PORT_GetControls((void*) (UINT_PTR) id, (INT32) portIndex, (PortControlCreator*) &creator); + } +#endif +} --- old/src/java.desktop/share/native/libjsound/PortMixerProvider.c 2018-03-15 02:00:50.142586488 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2002, 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_TRACE - - -#include -#include -#include "SoundDefs.h" -#include "Ports.h" -#include "Utilities.h" -#include "com_sun_media_sound_PortMixerProvider.h" - - -//////////////////////////////////////////// PortMixerProvider //////////////////////////////////////////// - -int getPortMixerDescription(int mixerIndex, PortMixerDescription* desc) { - strcpy(desc->name, "Unknown Name"); - strcpy(desc->vendor, "Unknown Vendor"); - strcpy(desc->description, "Port Mixer"); - strcpy(desc->version, "Unknown Version"); -#if USE_PORTS == TRUE - PORT_GetPortMixerDescription(mixerIndex, desc); -#endif // USE_PORTS - return TRUE; -} - -JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices(JNIEnv *env, jclass cls) { - INT32 numDevices = 0; - - TRACE0("Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices.\n"); - -#if USE_PORTS == TRUE - numDevices = PORT_GetPortMixerCount(); -#endif // USE_PORTS - - TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices returning %d.\n", (int) numDevices); - - return (jint)numDevices; -} - -JNIEXPORT jobject JNICALL Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo(JNIEnv *env, jclass cls, jint mixerIndex) { - jclass portMixerInfoClass; - jmethodID portMixerInfoConstructor; - PortMixerDescription desc; - jobject info = NULL; - jstring name; - jstring vendor; - jstring description; - jstring version; - - TRACE1("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo(%d).\n", mixerIndex); - - // retrieve class and constructor of PortMixerProvider.PortMixerInfo - portMixerInfoClass = (*env)->FindClass(env, IMPLEMENTATION_PACKAGE_NAME"/PortMixerProvider$PortMixerInfo"); - if (portMixerInfoClass == NULL) { - ERROR0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo: portMixerInfoClass is NULL\n"); - return NULL; - } - portMixerInfoConstructor = (*env)->GetMethodID(env, portMixerInfoClass, "", - "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - if (portMixerInfoConstructor == NULL) { - ERROR0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo: portMixerInfoConstructor is NULL\n"); - return NULL; - } - - if (getPortMixerDescription(mixerIndex, &desc)) { - // create a new PortMixerInfo object and return it - name = (*env)->NewStringUTF(env, desc.name); - CHECK_NULL_RETURN(name, info); - vendor = (*env)->NewStringUTF(env, desc.vendor); - CHECK_NULL_RETURN(vendor, info); - description = (*env)->NewStringUTF(env, desc.description); - CHECK_NULL_RETURN(description, info); - version = (*env)->NewStringUTF(env, desc.version); - CHECK_NULL_RETURN(version, info); - info = (*env)->NewObject(env, portMixerInfoClass, - portMixerInfoConstructor, mixerIndex, - name, vendor, description, version); - } - - TRACE0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo succeeded.\n"); - return info; -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/PortMixerProvider.c 2018-03-15 02:00:49.850586490 +0100 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002, 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_TRACE + + +#include +#include +#include "SoundDefs.h" +#include "Ports.h" +#include "Utilities.h" +#include "com_sun_media_sound_PortMixerProvider.h" + + +//////////////////////////////////////////// PortMixerProvider //////////////////////////////////////////// + +int getPortMixerDescription(int mixerIndex, PortMixerDescription* desc) { + strcpy(desc->name, "Unknown Name"); + strcpy(desc->vendor, "Unknown Vendor"); + strcpy(desc->description, "Port Mixer"); + strcpy(desc->version, "Unknown Version"); +#if USE_PORTS == TRUE + PORT_GetPortMixerDescription(mixerIndex, desc); +#endif // USE_PORTS + return TRUE; +} + +JNIEXPORT jint JNICALL Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices(JNIEnv *env, jclass cls) { + INT32 numDevices = 0; + + TRACE0("Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices.\n"); + +#if USE_PORTS == TRUE + numDevices = PORT_GetPortMixerCount(); +#endif // USE_PORTS + + TRACE1("Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices returning %d.\n", (int) numDevices); + + return (jint)numDevices; +} + +JNIEXPORT jobject JNICALL Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo(JNIEnv *env, jclass cls, jint mixerIndex) { + jclass portMixerInfoClass; + jmethodID portMixerInfoConstructor; + PortMixerDescription desc; + jobject info = NULL; + jstring name; + jstring vendor; + jstring description; + jstring version; + + TRACE1("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo(%d).\n", mixerIndex); + + // retrieve class and constructor of PortMixerProvider.PortMixerInfo + portMixerInfoClass = (*env)->FindClass(env, IMPLEMENTATION_PACKAGE_NAME"/PortMixerProvider$PortMixerInfo"); + if (portMixerInfoClass == NULL) { + ERROR0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo: portMixerInfoClass is NULL\n"); + return NULL; + } + portMixerInfoConstructor = (*env)->GetMethodID(env, portMixerInfoClass, "", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (portMixerInfoConstructor == NULL) { + ERROR0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo: portMixerInfoConstructor is NULL\n"); + return NULL; + } + + if (getPortMixerDescription(mixerIndex, &desc)) { + // create a new PortMixerInfo object and return it + name = (*env)->NewStringUTF(env, desc.name); + CHECK_NULL_RETURN(name, info); + vendor = (*env)->NewStringUTF(env, desc.vendor); + CHECK_NULL_RETURN(vendor, info); + description = (*env)->NewStringUTF(env, desc.description); + CHECK_NULL_RETURN(description, info); + version = (*env)->NewStringUTF(env, desc.version); + CHECK_NULL_RETURN(version, info); + info = (*env)->NewObject(env, portMixerInfoClass, + portMixerInfoConstructor, mixerIndex, + name, vendor, description, version); + } + + TRACE0("Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo succeeded.\n"); + return info; +} --- old/src/java.desktop/share/native/libjsound/Ports.h 2018-03-15 02:00:50.610586484 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,133 +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. - */ - -#ifndef PORTS_INCLUDED -#define PORTS_INCLUDED - - -#include "SoundDefs.h" -// for memset -#include -#include "Configure.h" // put flags for debug msgs etc. here -#include "Utilities.h" -#include - - -/* *********************** PORT TYPES (for all platforms) ******************************* */ - -#define PORT_SRC_UNKNOWN (com_sun_media_sound_PortMixer_SRC_UNKNOWN) -#define PORT_SRC_MICROPHONE (com_sun_media_sound_PortMixer_SRC_MICROPHONE) -#define PORT_SRC_LINE_IN (com_sun_media_sound_PortMixer_SRC_LINE_IN) -#define PORT_SRC_COMPACT_DISC (com_sun_media_sound_PortMixer_SRC_COMPACT_DISC) -#define PORT_SRC_MASK (com_sun_media_sound_PortMixer_SRC_MASK) -#define PORT_DST_UNKNOWN (com_sun_media_sound_PortMixer_DST_UNKNOWN) -#define PORT_DST_SPEAKER (com_sun_media_sound_PortMixer_DST_SPEAKER) -#define PORT_DST_HEADPHONE (com_sun_media_sound_PortMixer_DST_HEADPHONE) -#define PORT_DST_LINE_OUT (com_sun_media_sound_PortMixer_DST_LINE_OUT) -#define PORT_DST_MASK (com_sun_media_sound_PortMixer_DST_MASK) - -#define PORT_STRING_LENGTH 200 - -typedef struct tag_PortMixerDescription { - char name[PORT_STRING_LENGTH]; - char vendor[PORT_STRING_LENGTH]; - char description[PORT_STRING_LENGTH]; - char version[PORT_STRING_LENGTH]; -} PortMixerDescription; - - -// for BooleanControl.Type -#define CONTROL_TYPE_MUTE ((char*) 1) -#define CONTROL_TYPE_SELECT ((char*) 2) - -// for FloatControl.Type -#define CONTROL_TYPE_BALANCE ((char*) 1) -#define CONTROL_TYPE_MASTER_GAIN ((char*) 2) -#define CONTROL_TYPE_PAN ((char*) 3) -#define CONTROL_TYPE_VOLUME ((char*) 4) -#define CONTROL_TYPE_MAX 4 - -// method definitions - -/* controlID: unique ID for this control - * type: string that is used to construct the BooleanControl.Type, or CONTROL_TYPE_MUTE - * creator: pointer to the creator struct provided by PORT_GetControls - * returns an opaque pointer to the created control - */ -typedef void* (*PORT_NewBooleanControlPtr)(void* creator, void* controlID, char* type); - -/* type: string that is used to construct the CompoundControl.Type - * controls: an array of opaque controls returned by the CreateXXXControlPtr functions - * controlCount: number of elements in controls - * creator: pointer to the creator struct provided by PORT_GetControls - * returns an opaque pointer to the created control - */ -typedef void* (*PORT_NewCompoundControlPtr)(void* creator, char* type, void** controls, int controlCount); - -/* controlID: unique ID for this control - * type: string that is used to construct the FloatControl.Type, or one of - * CONTROL_TYPE_BALANCE, CONTROL_TYPE_MASTER_GAIN, CONTROL_TYPE_PAN, CONTROL_TYPE_VOLUME - * creator: pointer to the creator struct provided by PORT_GetControls - * returns an opaque pointer to the created control - */ -typedef void* (*PORT_NewFloatControlPtr)(void* creator, void* controlID, char* type, - float min, float max, float precision, const char* units); - -/* control: The control to add to current port - * creator: pointer to the creator struct provided by PORT_GetControls - * returns TRUE or FALSE - */ -typedef int (*PORT_AddControlPtr)(void* creator, void* control); - -// struct for dynamically instantiating the controls from platform dependent code -// without creating a dependency from the platform code to JNI - -typedef struct tag_PortControlCreator { - PORT_NewBooleanControlPtr newBooleanControl; - PORT_NewCompoundControlPtr newCompoundControl; - PORT_NewFloatControlPtr newFloatControl; - PORT_AddControlPtr addControl; -} PortControlCreator; - -#if (USE_PORTS == TRUE) - -// the following methods need to be implemented by the platform dependent code -INT32 PORT_GetPortMixerCount(); -INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description); -void* PORT_Open(INT32 mixerIndex); -void PORT_Close(void* id); - -INT32 PORT_GetPortCount(void* id); -INT32 PORT_GetPortType(void* id, INT32 portIndex); -INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len); -void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator); -float PORT_GetFloatValue(void* controlID); -INT32 PORT_GetIntValue(void* controlIDV); -void PORT_SetFloatValue(void* controlID, float value); -void PORT_SetIntValue(void* controlIDV, INT32 value); - -#endif // USE_PORTS - -#endif // PORTS_INCLUDED --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/midi_port/Ports.h 2018-03-15 02:00:50.318586486 +0100 @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#ifndef PORTS_INCLUDED +#define PORTS_INCLUDED + + +#include "SoundDefs.h" +// for memset +#include +#include "Configure.h" // put flags for debug msgs etc. here +#include "Utilities.h" +#include + + +/* *********************** PORT TYPES (for all platforms) ******************************* */ + +#define PORT_SRC_UNKNOWN (com_sun_media_sound_PortMixer_SRC_UNKNOWN) +#define PORT_SRC_MICROPHONE (com_sun_media_sound_PortMixer_SRC_MICROPHONE) +#define PORT_SRC_LINE_IN (com_sun_media_sound_PortMixer_SRC_LINE_IN) +#define PORT_SRC_COMPACT_DISC (com_sun_media_sound_PortMixer_SRC_COMPACT_DISC) +#define PORT_SRC_MASK (com_sun_media_sound_PortMixer_SRC_MASK) +#define PORT_DST_UNKNOWN (com_sun_media_sound_PortMixer_DST_UNKNOWN) +#define PORT_DST_SPEAKER (com_sun_media_sound_PortMixer_DST_SPEAKER) +#define PORT_DST_HEADPHONE (com_sun_media_sound_PortMixer_DST_HEADPHONE) +#define PORT_DST_LINE_OUT (com_sun_media_sound_PortMixer_DST_LINE_OUT) +#define PORT_DST_MASK (com_sun_media_sound_PortMixer_DST_MASK) + +#define PORT_STRING_LENGTH 200 + +typedef struct tag_PortMixerDescription { + char name[PORT_STRING_LENGTH]; + char vendor[PORT_STRING_LENGTH]; + char description[PORT_STRING_LENGTH]; + char version[PORT_STRING_LENGTH]; +} PortMixerDescription; + + +// for BooleanControl.Type +#define CONTROL_TYPE_MUTE ((char*) 1) +#define CONTROL_TYPE_SELECT ((char*) 2) + +// for FloatControl.Type +#define CONTROL_TYPE_BALANCE ((char*) 1) +#define CONTROL_TYPE_MASTER_GAIN ((char*) 2) +#define CONTROL_TYPE_PAN ((char*) 3) +#define CONTROL_TYPE_VOLUME ((char*) 4) +#define CONTROL_TYPE_MAX 4 + +// method definitions + +/* controlID: unique ID for this control + * type: string that is used to construct the BooleanControl.Type, or CONTROL_TYPE_MUTE + * creator: pointer to the creator struct provided by PORT_GetControls + * returns an opaque pointer to the created control + */ +typedef void* (*PORT_NewBooleanControlPtr)(void* creator, void* controlID, char* type); + +/* type: string that is used to construct the CompoundControl.Type + * controls: an array of opaque controls returned by the CreateXXXControlPtr functions + * controlCount: number of elements in controls + * creator: pointer to the creator struct provided by PORT_GetControls + * returns an opaque pointer to the created control + */ +typedef void* (*PORT_NewCompoundControlPtr)(void* creator, char* type, void** controls, int controlCount); + +/* controlID: unique ID for this control + * type: string that is used to construct the FloatControl.Type, or one of + * CONTROL_TYPE_BALANCE, CONTROL_TYPE_MASTER_GAIN, CONTROL_TYPE_PAN, CONTROL_TYPE_VOLUME + * creator: pointer to the creator struct provided by PORT_GetControls + * returns an opaque pointer to the created control + */ +typedef void* (*PORT_NewFloatControlPtr)(void* creator, void* controlID, char* type, + float min, float max, float precision, const char* units); + +/* control: The control to add to current port + * creator: pointer to the creator struct provided by PORT_GetControls + * returns TRUE or FALSE + */ +typedef int (*PORT_AddControlPtr)(void* creator, void* control); + +// struct for dynamically instantiating the controls from platform dependent code +// without creating a dependency from the platform code to JNI + +typedef struct tag_PortControlCreator { + PORT_NewBooleanControlPtr newBooleanControl; + PORT_NewCompoundControlPtr newCompoundControl; + PORT_NewFloatControlPtr newFloatControl; + PORT_AddControlPtr addControl; +} PortControlCreator; + +#if (USE_PORTS == TRUE) + +// the following methods need to be implemented by the platform dependent code +INT32 PORT_GetPortMixerCount(); +INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description); +void* PORT_Open(INT32 mixerIndex); +void PORT_Close(void* id); + +INT32 PORT_GetPortCount(void* id); +INT32 PORT_GetPortType(void* id, INT32 portIndex); +INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len); +void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator); +float PORT_GetFloatValue(void* controlID); +INT32 PORT_GetIntValue(void* controlIDV); +void PORT_SetFloatValue(void* controlID, float value); +void PORT_SetIntValue(void* controlIDV, INT32 value); + +#endif // USE_PORTS + +#endif // PORTS_INCLUDED --- old/src/java.desktop/share/native/libjsound/Configure.h 2018-03-15 02:00:51.062586481 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1998, 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. - */ - -// USE THIS FILE TO SET UP PARAMS FOR DEBUG ETC - - -// USE ERROR PRINTS -#undef USE_ERROR -//#ifndef USE_ERROR -//#define USE_ERROR -//#endif - - -// USE TRACE PRINTS -#undef USE_TRACE -//#ifndef USE_TRACE -//#define USE_TRACE -//#endif - -// USE VERBOSE TRACE PRINTS -#undef USE_VERBOSE_TRACE -//#ifndef USE_VERBOSE_TRACE -//#define USE_VERBOSE_TRACE -//#endif - -#define IMPLEMENTATION_PACKAGE_NAME "com/sun/media/sound" -#define JAVA_PACKAGE_BASE "javax/sound" -#define JAVA_SAMPLED_PACKAGE_NAME JAVA_PACKAGE_BASE"/sampled" -#define JAVA_MIDI_PACKAGE_NAME JAVA_PACKAGE_BASE"/midi" --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/sound/Configure.h 2018-03-15 02:00:50.762586483 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998, 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. + */ + +// USE THIS FILE TO SET UP PARAMS FOR DEBUG ETC + + +// USE ERROR PRINTS +#undef USE_ERROR +//#ifndef USE_ERROR +//#define USE_ERROR +//#endif + + +// USE TRACE PRINTS +#undef USE_TRACE +//#ifndef USE_TRACE +//#define USE_TRACE +//#endif + +// USE VERBOSE TRACE PRINTS +#undef USE_VERBOSE_TRACE +//#ifndef USE_VERBOSE_TRACE +//#define USE_VERBOSE_TRACE +//#endif + +#define IMPLEMENTATION_PACKAGE_NAME "com/sun/media/sound" +#define JAVA_PACKAGE_BASE "javax/sound" +#define JAVA_SAMPLED_PACKAGE_NAME JAVA_PACKAGE_BASE"/sampled" +#define JAVA_MIDI_PACKAGE_NAME JAVA_PACKAGE_BASE"/midi" --- old/src/java.desktop/share/native/libjsound/SoundDefs.h 2018-03-15 02:00:51.534586477 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2007, 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. - */ - -#ifndef __SOUNDDEFS_INCLUDED__ -#define __SOUNDDEFS_INCLUDED__ - - -// types for X_PLATFORM -#define X_WINDOWS 1 -#define X_SOLARIS 2 -#define X_LINUX 3 -#define X_BSD 4 -#define X_MACOSX 5 - -// ********************************** -// Make sure you set X_PLATFORM defines correctly. -// Everything depends upon this flag being setup correctly. -// ********************************** - -#if (!defined(X_PLATFORM)) -#error "You need to define X_PLATFORM outside of the source. Use the types above." -#endif - - -// following is needed for _LP64 -#if ((X_PLATFORM == X_SOLARIS) || (X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX)) -#include -#endif - -#if X_PLATFORM == X_WINDOWS -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#endif /* X_PLATFORM == X_WINDOWS */ - - -/* -* These types are defined elsewhere for newer 32/64-bit Windows -* header files, but not on Solaris/Linux (X_PLATFORM != X_WINDOWS) -*/ -#if (X_PLATFORM != X_WINDOWS) - -typedef unsigned char UINT8; -typedef char INT8; -typedef short INT16; -typedef unsigned short UINT16; -#ifdef _LP64 -typedef int INT32; -typedef unsigned int UINT32; -typedef unsigned long UINT64; -typedef long INT64; -#else /* _LP64 */ -typedef long INT32; -typedef unsigned long UINT32; -/* generic 64 bit ? */ -typedef unsigned long long UINT64; -typedef long long INT64; -#endif /* _LP64 */ - -typedef unsigned long UINT_PTR; -typedef long INT_PTR; - -#endif /* X_PLATFORM != X_WINDOWS */ - - -typedef unsigned char UBYTE; -typedef char SBYTE; - - -#undef TRUE -#undef FALSE - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#undef NULL -#ifndef NULL -#define NULL 0L -#endif - - - - -#if X_PLATFORM == X_WINDOWS -#include -#define INLINE _inline -#endif - - -#if X_PLATFORM == X_SOLARIS -#define INLINE -#endif - - -#if X_PLATFORM == X_LINUX -#define INLINE inline -#endif - - -#if (X_PLATFORM == X_BSD) || (X_PLATFORM == X_MACOSX) -#define INLINE inline -#endif - - -#endif // __SOUNDDEFS_INCLUDED__ --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/sound/SoundDefs.h 2018-03-15 02:00:51.222586480 +0100 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2007, 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. + */ + +#ifndef __SOUNDDEFS_INCLUDED__ +#define __SOUNDDEFS_INCLUDED__ + + +// types for X_PLATFORM +#define X_WINDOWS 1 +#define X_SOLARIS 2 +#define X_LINUX 3 +#define X_BSD 4 +#define X_MACOSX 5 + +// ********************************** +// Make sure you set X_PLATFORM defines correctly. +// Everything depends upon this flag being setup correctly. +// ********************************** + +#if (!defined(X_PLATFORM)) +#error "You need to define X_PLATFORM outside of the source. Use the types above." +#endif + + +// following is needed for _LP64 +#if ((X_PLATFORM == X_SOLARIS) || (X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX)) +#include +#endif + +#if X_PLATFORM == X_WINDOWS +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif /* X_PLATFORM == X_WINDOWS */ + + +/* +* These types are defined elsewhere for newer 32/64-bit Windows +* header files, but not on Solaris/Linux (X_PLATFORM != X_WINDOWS) +*/ +#if (X_PLATFORM != X_WINDOWS) + +typedef unsigned char UINT8; +typedef char INT8; +typedef short INT16; +typedef unsigned short UINT16; +#ifdef _LP64 +typedef int INT32; +typedef unsigned int UINT32; +typedef unsigned long UINT64; +typedef long INT64; +#else /* _LP64 */ +typedef long INT32; +typedef unsigned long UINT32; +/* generic 64 bit ? */ +typedef unsigned long long UINT64; +typedef long long INT64; +#endif /* _LP64 */ + +typedef unsigned long UINT_PTR; +typedef long INT_PTR; + +#endif /* X_PLATFORM != X_WINDOWS */ + + +typedef unsigned char UBYTE; +typedef char SBYTE; + + +#undef TRUE +#undef FALSE + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#undef NULL +#ifndef NULL +#define NULL 0L +#endif + + + + +#if X_PLATFORM == X_WINDOWS +#include +#define INLINE _inline +#endif + + +#if X_PLATFORM == X_SOLARIS +#define INLINE +#endif + + +#if X_PLATFORM == X_LINUX +#define INLINE inline +#endif + + +#if (X_PLATFORM == X_BSD) || (X_PLATFORM == X_MACOSX) +#define INLINE inline +#endif + + +#endif // __SOUNDDEFS_INCLUDED__ --- old/src/java.desktop/share/native/libjsound/Utilities.c 2018-03-15 02:00:52.030586474 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1998, 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 "Utilities.h" - - -int UTIL_IsBigEndianPlatform() { -#ifdef _LITTLE_ENDIAN - return 0; -#else - return 1; -#endif -} - -void ThrowJavaMessageException(JNIEnv *e, const char *exClass, const char *msg) { - jclass newExcCls; - - ERROR1("throw exception: %s\n", msg); - newExcCls = (*e)->FindClass(e, exClass); - if (newExcCls == 0) { - /* Unable to find the new exception class, give up. */ - ERROR0("ThrowJavaMessageException unable to find class!\n"); - return; - } - (*e)->ThrowNew(e, newExcCls, msg); -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/sound/Utilities.c 2018-03-15 02:00:51.706586476 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1998, 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 "Utilities.h" + + +int UTIL_IsBigEndianPlatform() { +#ifdef _LITTLE_ENDIAN + return 0; +#else + return 1; +#endif +} + +void ThrowJavaMessageException(JNIEnv *e, const char *exClass, const char *msg) { + jclass newExcCls; + + ERROR1("throw exception: %s\n", msg); + newExcCls = (*e)->FindClass(e, exClass); + if (newExcCls == 0) { + /* Unable to find the new exception class, give up. */ + ERROR0("ThrowJavaMessageException unable to find class!\n"); + return; + } + (*e)->ThrowNew(e, newExcCls, msg); +} --- old/src/java.desktop/share/native/libjsound/Utilities.h 2018-03-15 02:00:52.534586470 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 1998, 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. - */ - -#include -#include "jni_util.h" -#include "SoundDefs.h" -#include "Configure.h" // put flags for debug msgs etc. here - -// return 1 if this platform is big endian, or 0 for little endian -int UTIL_IsBigEndianPlatform(); - - -// ERROR PRINTS -#ifdef USE_ERROR -#define ERROR0(string) { fprintf(stdout, (string)); fflush(stdout); } -#define ERROR1(string, p1) { fprintf(stdout, (string), (p1)); fflush(stdout); } -#define ERROR2(string, p1, p2) { fprintf(stdout, (string), (p1), (p2)); fflush(stdout); } -#define ERROR3(string, p1, p2, p3) { fprintf(stdout, (string), (p1), (p2), (p3)); fflush(stdout); } -#define ERROR4(string, p1, p2, p3, p4) { fprintf(stdout, (string), (p1), (p2), (p3), (p4)); fflush(stdout); } -#else -#define ERROR0(string) -#define ERROR1(string, p1) -#define ERROR2(string, p1, p2) -#define ERROR3(string, p1, p2, p3) -#define ERROR4(string, p1, p2, p3, p4) -#endif - - -// TRACE PRINTS -#ifdef USE_TRACE -#define TRACE0(string) { fprintf(stdout, (string)); fflush(stdout); } -#define TRACE1(string, p1) { fprintf(stdout, (string), (p1)); fflush(stdout); } -#define TRACE2(string, p1, p2) { fprintf(stdout, (string), (p1), (p2)); fflush(stdout); } -#define TRACE3(string, p1, p2, p3) { fprintf(stdout, (string), (p1), (p2), (p3)); fflush(stdout); } -#define TRACE4(string, p1, p2, p3, p4) { fprintf(stdout, (string), (p1), (p2), (p3), (p4)); fflush(stdout); } -#define TRACE5(string, p1, p2, p3, p4, p5) { fprintf(stdout, (string), (p1), (p2), (p3), (p4), (p5)); fflush(stdout); } -#else -#define TRACE0(string) -#define TRACE1(string, p1) -#define TRACE2(string, p1, p2) -#define TRACE3(string, p1, p2, p3) -#define TRACE4(string, p1, p2, p3, p4) -#define TRACE5(string, p1, p2, p3, p4, p5) -#endif - - -// VERBOSE TRACE PRINTS -#ifdef USE_VERBOSE_TRACE -#define VTRACE0(string) fprintf(stdout, (string)); -#define VTRACE1(string, p1) fprintf(stdout, (string), (p1)); -#define VTRACE2(string, p1, p2) fprintf(stdout, (string), (p1), (p2)); -#define VTRACE3(string, p1, p2, p3) fprintf(stdout, (string), (p1), (p2), (p3)); -#define VTRACE4(string, p1, p2, p3, p4) fprintf(stdout, (string), (p1), (p2), (p3), (p4)); -#else -#define VTRACE0(string) -#define VTRACE1(string, p1) -#define VTRACE2(string, p1, p2) -#define VTRACE3(string, p1, p2, p3) -#define VTRACE4(string, p1, p2, p3, p4) -#endif - - -void ThrowJavaMessageException(JNIEnv *e, const char *exClass, const char *msg); --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/share/native/common/sound/Utilities.h 2018-03-15 02:00:52.210586472 +0100 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1998, 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. + */ + +#include +#include "jni_util.h" +#include "SoundDefs.h" +#include "Configure.h" // put flags for debug msgs etc. here + +// return 1 if this platform is big endian, or 0 for little endian +int UTIL_IsBigEndianPlatform(); + + +// ERROR PRINTS +#ifdef USE_ERROR +#define ERROR0(string) { fprintf(stdout, (string)); fflush(stdout); } +#define ERROR1(string, p1) { fprintf(stdout, (string), (p1)); fflush(stdout); } +#define ERROR2(string, p1, p2) { fprintf(stdout, (string), (p1), (p2)); fflush(stdout); } +#define ERROR3(string, p1, p2, p3) { fprintf(stdout, (string), (p1), (p2), (p3)); fflush(stdout); } +#define ERROR4(string, p1, p2, p3, p4) { fprintf(stdout, (string), (p1), (p2), (p3), (p4)); fflush(stdout); } +#else +#define ERROR0(string) +#define ERROR1(string, p1) +#define ERROR2(string, p1, p2) +#define ERROR3(string, p1, p2, p3) +#define ERROR4(string, p1, p2, p3, p4) +#endif + + +// TRACE PRINTS +#ifdef USE_TRACE +#define TRACE0(string) { fprintf(stdout, (string)); fflush(stdout); } +#define TRACE1(string, p1) { fprintf(stdout, (string), (p1)); fflush(stdout); } +#define TRACE2(string, p1, p2) { fprintf(stdout, (string), (p1), (p2)); fflush(stdout); } +#define TRACE3(string, p1, p2, p3) { fprintf(stdout, (string), (p1), (p2), (p3)); fflush(stdout); } +#define TRACE4(string, p1, p2, p3, p4) { fprintf(stdout, (string), (p1), (p2), (p3), (p4)); fflush(stdout); } +#define TRACE5(string, p1, p2, p3, p4, p5) { fprintf(stdout, (string), (p1), (p2), (p3), (p4), (p5)); fflush(stdout); } +#else +#define TRACE0(string) +#define TRACE1(string, p1) +#define TRACE2(string, p1, p2) +#define TRACE3(string, p1, p2, p3) +#define TRACE4(string, p1, p2, p3, p4) +#define TRACE5(string, p1, p2, p3, p4, p5) +#endif + + +// VERBOSE TRACE PRINTS +#ifdef USE_VERBOSE_TRACE +#define VTRACE0(string) fprintf(stdout, (string)); +#define VTRACE1(string, p1) fprintf(stdout, (string), (p1)); +#define VTRACE2(string, p1, p2) fprintf(stdout, (string), (p1), (p2)); +#define VTRACE3(string, p1, p2, p3) fprintf(stdout, (string), (p1), (p2), (p3)); +#define VTRACE4(string, p1, p2, p3, p4) fprintf(stdout, (string), (p1), (p2), (p3), (p4)); +#else +#define VTRACE0(string) +#define VTRACE1(string, p1) +#define VTRACE2(string, p1, p2) +#define VTRACE3(string, p1, p2, p3) +#define VTRACE4(string, p1, p2, p3, p4) +#endif + + +void ThrowJavaMessageException(JNIEnv *e, const char *exClass, const char *msg); --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 2018-03-15 02:00:53.030586466 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,626 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#define USE_ERROR -#define USE_TRACE - -#include "PLATFORM_API_SolarisOS_Utils.h" -#include "DirectAudio.h" - -#if USE_DAUDIO == TRUE - - -// The default buffer time -#define DEFAULT_PERIOD_TIME_MILLIS 50 - -///// implemented functions of DirectAudio.h - -INT32 DAUDIO_GetDirectAudioDeviceCount() { - return (INT32) getAudioDeviceCount(); -} - - -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, - DirectAudioDeviceDescription* description) { - AudioDeviceDescription desc; - - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { - description->maxSimulLines = desc.maxSimulLines; - strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1); - description->name[DAUDIO_STRING_LENGTH-1] = 0; - strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1); - description->vendor[DAUDIO_STRING_LENGTH-1] = 0; - strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1); - description->version[DAUDIO_STRING_LENGTH-1] = 0; - /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/ - strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1); - description->description[DAUDIO_STRING_LENGTH-1] = 0; - return TRUE; - } - return FALSE; - -} - -#define MAX_SAMPLE_RATES 20 - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { - int fd = -1; - AudioDeviceDescription desc; - am_sample_rates_t *sr; - /* hardcoded bits and channels */ - int bits[] = {8, 16}; - int bitsCount = 2; - int channels[] = {1, 2}; - int channelsCount = 2; - /* for querying sample rates */ - int err; - int ch, b, s; - - TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource); - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { - fd = open(desc.pathctl, O_RDONLY); - } - if (fd < 0) { - ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); - return; - } - - /* get sample rates */ - sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES)); - if (sr == NULL) { - ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex); - close(fd); - return; - } - - sr->num_samp_rates = MAX_SAMPLE_RATES; - sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD; - sr->samp_rates[0] = -2; - err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); - if (err < 0) { - ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", - (int)mixerIndex); - ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n", - (int) sr->num_samp_rates, - (int) sr->samp_rates[0]); - /* Some Solaris 8 drivers fail for get sample rates! - * Do as if we support all sample rates - */ - sr->flags = MIXER_SR_LIMITS; - } - if ((sr->flags & MIXER_SR_LIMITS) - || (sr->num_samp_rates > MAX_SAMPLE_RATES)) { -#ifdef USE_TRACE - if ((sr->flags & MIXER_SR_LIMITS)) { - TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", - (int)mixerIndex); - } - if (sr->num_samp_rates > MAX_SAMPLE_RATES) { - TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", - MAX_SAMPLE_RATES, (int)mixerIndex); - } -#endif - /* - * Fake it to have only one sample rate: -1 - */ - sr->num_samp_rates = 1; - sr->samp_rates[0] = -1; - } - close(fd); - - for (ch = 0; ch < channelsCount; ch++) { - for (b = 0; b < bitsCount; b++) { - for (s = 0; s < sr->num_samp_rates; s++) { - DAUDIO_AddAudioFormat(creator, - bits[b], /* significant bits */ - 0, /* frameSize: let it be calculated */ - channels[ch], - (float) ((int) sr->samp_rates[s]), - DAUDIO_PCM, /* encoding - let's only do PCM */ - (bits[b] > 8)?TRUE:TRUE, /* isSigned */ -#ifdef _LITTLE_ENDIAN - FALSE /* little endian */ -#else - (bits[b] > 8)?TRUE:FALSE /* big endian */ -#endif - ); - } - } - } - free(sr); -} - - -typedef struct { - int fd; - audio_info_t info; - int bufferSizeInBytes; - int frameSize; /* storage size in Bytes */ - /* how many bytes were written or read */ - INT32 transferedBytes; - /* if transferedBytes exceed 32-bit boundary, - * it will be reset and positionOffset will receive - * the offset - */ - INT64 positionOffset; -} SolPcmInfo; - - -void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, - int encoding, float sampleRate, int sampleSizeInBits, - int frameSize, int channels, - int isSigned, int isBigEndian, int bufferSizeInBytes) { - int err = 0; - int openMode; - AudioDeviceDescription desc; - SolPcmInfo* info; - - TRACE0("> DAUDIO_Open\n"); - if (encoding != DAUDIO_PCM) { - ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding); - return NULL; - } - if (channels <= 0) { - ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels); - return NULL; - } - - info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo)); - if (!info) { - ERROR0("Out of memory\n"); - return NULL; - } - memset(info, 0, sizeof(SolPcmInfo)); - info->frameSize = frameSize; - info->fd = -1; - - if (isSource) { - openMode = O_WRONLY; - } else { - openMode = O_RDONLY; - } - -#ifndef __linux__ - /* blackdown does not use NONBLOCK */ - openMode |= O_NONBLOCK; -#endif - - if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { - info->fd = open(desc.path, openMode); - } - if (info->fd < 0) { - ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex); - free(info); - return NULL; - } - /* set to multiple open */ - if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) { - TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path); - } else { - ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path); - } - - AUDIO_INITINFO(&(info->info)); - /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */ - err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); - - /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */ - AUDIO_INITINFO(&(info->info)); - - if (isSource) { - info->info.play.sample_rate = sampleRate; - info->info.play.precision = sampleSizeInBits; - info->info.play.channels = channels; - info->info.play.encoding = AUDIO_ENCODING_LINEAR; - info->info.play.buffer_size = bufferSizeInBytes; - info->info.play.pause = 1; - } else { - info->info.record.sample_rate = sampleRate; - info->info.record.precision = sampleSizeInBits; - info->info.record.channels = channels; - info->info.record.encoding = AUDIO_ENCODING_LINEAR; - info->info.record.buffer_size = bufferSizeInBytes; - info->info.record.pause = 1; - } - err = ioctl(info->fd, AUDIO_SETINFO, &(info->info)); - if (err < 0) { - ERROR0("DAUDIO_Open: could not set info!\n"); - DAUDIO_Close((void*) info, isSource); - return NULL; - } - DAUDIO_Flush((void*) info, isSource); - - err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); - if (err >= 0) { - if (isSource) { - info->bufferSizeInBytes = info->info.play.buffer_size; - } else { - info->bufferSizeInBytes = info->info.record.buffer_size; - } - TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n", - (int) bufferSizeInBytes, - (int) info->bufferSizeInBytes); - } else { - ERROR0("DAUDIO_Open: cannot get info!\n"); - DAUDIO_Close((void*) info, isSource); - return NULL; - } - TRACE0("< DAUDIO_Open: Opened device successfully.\n"); - return (void*) info; -} - - -int DAUDIO_Start(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err, modified; - audio_info_t audioInfo; - - TRACE0("> DAUDIO_Start\n"); - - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - // unpause - modified = FALSE; - if (isSource && audioInfo.play.pause) { - audioInfo.play.pause = 0; - modified = TRUE; - } - if (!isSource && audioInfo.record.pause) { - audioInfo.record.pause = 0; - modified = TRUE; - } - if (modified) { - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - } - } - - TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error"); - return (err >= 0)?TRUE:FALSE; -} - -int DAUDIO_Stop(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err, modified; - audio_info_t audioInfo; - - TRACE0("> DAUDIO_Stop\n"); - - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - // pause - modified = FALSE; - if (isSource && !audioInfo.play.pause) { - audioInfo.play.pause = 1; - modified = TRUE; - } - if (!isSource && !audioInfo.record.pause) { - audioInfo.record.pause = 1; - modified = TRUE; - } - if (modified) { - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - } - } - - TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error"); - return (err >= 0)?TRUE:FALSE; -} - -void DAUDIO_Close(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - - TRACE0("DAUDIO_Close\n"); - if (info != NULL) { - if (info->fd >= 0) { - DAUDIO_Flush(id, isSource); - close(info->fd); - } - free(info); - } -} - -#ifndef USE_TRACE -/* close to 2^31 */ -#define POSITION_MAX 2000000000 -#else -/* for testing */ -#define POSITION_MAX 1000000 -#endif - -void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) { - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int err; - int offset = -1; - int underrun = FALSE; - int devBytes = 0; - - if (count > 0) { - info->transferedBytes += count; - - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - underrun = prinfo->error; - devBytes = prinfo->samples * info->frameSize; - } - AUDIO_INITINFO(&audioInfo); - if (underrun) { - /* if an underrun occurred, reset */ - ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n", - (devBytes - info->transferedBytes)); - ERROR1(" devBytes from %d to 0, ", devBytes); - ERROR2(" positionOffset from %d to %d ", - (int) info->positionOffset, - (int) (info->positionOffset + info->transferedBytes)); - ERROR1(" transferedBytes from %d to 0\n", - (int) info->transferedBytes); - prinfo->samples = 0; - info->positionOffset += info->transferedBytes; - info->transferedBytes = 0; - } - else if (info->transferedBytes > POSITION_MAX) { - /* we will reset transferedBytes and - * the samples field in prinfo - */ - offset = devBytes; - prinfo->samples = 0; - } - /* reset error flag */ - prinfo->error = 0; - - err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); - if (err >= 0) { - if (offset > 0) { - /* upon exit of AUDIO_SETINFO, the samples parameter - * was set to the previous value. This is our - * offset. - */ - TRACE1("Adjust samplePos: offset=%d, ", (int) offset); - TRACE2("transferedBytes=%d -> %d, ", - (int) info->transferedBytes, - (int) (info->transferedBytes - offset)); - TRACE2("positionOffset=%d -> %d\n", - (int) (info->positionOffset), - (int) (((int) info->positionOffset) + offset)); - info->transferedBytes -= offset; - info->positionOffset += offset; - } - } else { - ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n"); - } - } -} - -// returns -1 on error -int DAUDIO_Write(void* id, char* data, int byteSize) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = -1; - - TRACE1("> DAUDIO_Write %d bytes\n", byteSize); - if (info!=NULL) { - ret = write(info->fd, data, byteSize); - resetErrorFlagAndAdjustPosition(info, TRUE, ret); - /* sets ret to -1 if buffer full, no error! */ - if (ret < 0) { - ret = 0; - } - } - TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); - return ret; -} - -// returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = -1; - - TRACE1("> DAUDIO_Read %d bytes\n", byteSize); - if (info != NULL) { - ret = read(info->fd, data, byteSize); - resetErrorFlagAndAdjustPosition(info, TRUE, ret); - /* sets ret to -1 if buffer full, no error! */ - if (ret < 0) { - ret = 0; - } - } - TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); - return ret; -} - - -int DAUDIO_GetBufferSize(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - if (info) { - return info->bufferSizeInBytes; - } - return 0; -} - -int DAUDIO_StillDraining(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int ret = FALSE; - - if (info!=NULL) { - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - /* check error flag */ - AUDIO_INITINFO(&audioInfo); - ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - ret = (prinfo->error != 0)?FALSE:TRUE; - } - return ret; -} - - -int getDevicePosition(SolPcmInfo* info, int isSource) { - audio_info_t audioInfo; - audio_prinfo_t* prinfo; - int err; - - if (isSource) { - prinfo = &(audioInfo.play); - } else { - prinfo = &(audioInfo.record); - } - AUDIO_INITINFO(&audioInfo); - err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); - if (err >= 0) { - /*TRACE2("---> device paused: %d eof=%d\n", - prinfo->pause, prinfo->eof); - */ - return (int) (prinfo->samples * info->frameSize); - } - ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n"); - return -1; -} - -int DAUDIO_Flush(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int err = -1; - int pos; - - TRACE0("DAUDIO_Flush\n"); - if (info) { - if (isSource) { - err = ioctl(info->fd, I_FLUSH, FLUSHW); - } else { - err = ioctl(info->fd, I_FLUSH, FLUSHR); - } - if (err >= 0) { - /* resets the transferedBytes parameter to - * the current samples count of the device - */ - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - info->transferedBytes = pos; - } - } - } - if (err < 0) { - ERROR0("ERROR in DAUDIO_Flush\n"); - } - return (err < 0)?FALSE:TRUE; -} - -int DAUDIO_GetAvailable(void* id, int isSource) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret = 0; - int pos; - - if (info) { - /* unfortunately, the STREAMS architecture - * seems to not have a method for querying - * the available bytes to read/write! - * estimate it... - */ - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - if (isSource) { - /* we usually have written more bytes - * to the queue than the device position should be - */ - ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos); - } else { - /* for record, the device stream should - * be usually ahead of our read actions - */ - ret = pos - info->transferedBytes; - } - if (ret > info->bufferSizeInBytes) { - ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n", - (int) ret, (int) info->bufferSizeInBytes); - ERROR2(" devicePos=%d, transferedBytes=%d\n", - (int) pos, (int) info->transferedBytes); - ret = info->bufferSizeInBytes; - } - else if (ret < 0) { - ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n", - (int) ret); - ERROR2(" devicePos=%d, transferedBytes=%d\n", - (int) pos, (int) info->transferedBytes); - ret = 0; - } - } - } - - TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); - return ret; -} - -INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret; - int pos; - INT64 result = javaBytePos; - - if (info) { - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - result = info->positionOffset + pos; - } - } - - //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); - return result; -} - - -void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { - SolPcmInfo* info = (SolPcmInfo*) id; - int ret; - int pos; - - if (info) { - pos = getDevicePosition(info, isSource); - if (pos >= 0) { - info->positionOffset = javaBytePos - pos; - } - } -} - -int DAUDIO_RequiresServicing(void* id, int isSource) { - // never need servicing on Solaris - return FALSE; -} - -void DAUDIO_Service(void* id, int isSource) { - // never need servicing on Solaris -} - - -#endif // USE_DAUDIO --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 2018-03-15 02:00:52.710586469 +0100 @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#define USE_ERROR +#define USE_TRACE + +#include "PLATFORM_API_SolarisOS_Utils.h" +#include "DirectAudio.h" + +#if USE_DAUDIO == TRUE + + +// The default buffer time +#define DEFAULT_PERIOD_TIME_MILLIS 50 + +///// implemented functions of DirectAudio.h + +INT32 DAUDIO_GetDirectAudioDeviceCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, + DirectAudioDeviceDescription* description) { + AudioDeviceDescription desc; + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { + description->maxSimulLines = desc.maxSimulLines; + strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1); + description->name[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1); + description->vendor[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1); + description->version[DAUDIO_STRING_LENGTH-1] = 0; + /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/ + strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1); + description->description[DAUDIO_STRING_LENGTH-1] = 0; + return TRUE; + } + return FALSE; + +} + +#define MAX_SAMPLE_RATES 20 + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { + int fd = -1; + AudioDeviceDescription desc; + am_sample_rates_t *sr; + /* hardcoded bits and channels */ + int bits[] = {8, 16}; + int bitsCount = 2; + int channels[] = {1, 2}; + int channelsCount = 2; + /* for querying sample rates */ + int err; + int ch, b, s; + + TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource); + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + fd = open(desc.pathctl, O_RDONLY); + } + if (fd < 0) { + ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); + return; + } + + /* get sample rates */ + sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES)); + if (sr == NULL) { + ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex); + close(fd); + return; + } + + sr->num_samp_rates = MAX_SAMPLE_RATES; + sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD; + sr->samp_rates[0] = -2; + err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); + if (err < 0) { + ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", + (int)mixerIndex); + ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n", + (int) sr->num_samp_rates, + (int) sr->samp_rates[0]); + /* Some Solaris 8 drivers fail for get sample rates! + * Do as if we support all sample rates + */ + sr->flags = MIXER_SR_LIMITS; + } + if ((sr->flags & MIXER_SR_LIMITS) + || (sr->num_samp_rates > MAX_SAMPLE_RATES)) { +#ifdef USE_TRACE + if ((sr->flags & MIXER_SR_LIMITS)) { + TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", + (int)mixerIndex); + } + if (sr->num_samp_rates > MAX_SAMPLE_RATES) { + TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", + MAX_SAMPLE_RATES, (int)mixerIndex); + } +#endif + /* + * Fake it to have only one sample rate: -1 + */ + sr->num_samp_rates = 1; + sr->samp_rates[0] = -1; + } + close(fd); + + for (ch = 0; ch < channelsCount; ch++) { + for (b = 0; b < bitsCount; b++) { + for (s = 0; s < sr->num_samp_rates; s++) { + DAUDIO_AddAudioFormat(creator, + bits[b], /* significant bits */ + 0, /* frameSize: let it be calculated */ + channels[ch], + (float) ((int) sr->samp_rates[s]), + DAUDIO_PCM, /* encoding - let's only do PCM */ + (bits[b] > 8)?TRUE:TRUE, /* isSigned */ +#ifdef _LITTLE_ENDIAN + FALSE /* little endian */ +#else + (bits[b] > 8)?TRUE:FALSE /* big endian */ +#endif + ); + } + } + } + free(sr); +} + + +typedef struct { + int fd; + audio_info_t info; + int bufferSizeInBytes; + int frameSize; /* storage size in Bytes */ + /* how many bytes were written or read */ + INT32 transferedBytes; + /* if transferedBytes exceed 32-bit boundary, + * it will be reset and positionOffset will receive + * the offset + */ + INT64 positionOffset; +} SolPcmInfo; + + +void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, + int encoding, float sampleRate, int sampleSizeInBits, + int frameSize, int channels, + int isSigned, int isBigEndian, int bufferSizeInBytes) { + int err = 0; + int openMode; + AudioDeviceDescription desc; + SolPcmInfo* info; + + TRACE0("> DAUDIO_Open\n"); + if (encoding != DAUDIO_PCM) { + ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding); + return NULL; + } + if (channels <= 0) { + ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels); + return NULL; + } + + info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo)); + if (!info) { + ERROR0("Out of memory\n"); + return NULL; + } + memset(info, 0, sizeof(SolPcmInfo)); + info->frameSize = frameSize; + info->fd = -1; + + if (isSource) { + openMode = O_WRONLY; + } else { + openMode = O_RDONLY; + } + +#ifndef __linux__ + /* blackdown does not use NONBLOCK */ + openMode |= O_NONBLOCK; +#endif + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + info->fd = open(desc.path, openMode); + } + if (info->fd < 0) { + ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex); + free(info); + return NULL; + } + /* set to multiple open */ + if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) { + TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path); + } else { + ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path); + } + + AUDIO_INITINFO(&(info->info)); + /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */ + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + + /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */ + AUDIO_INITINFO(&(info->info)); + + if (isSource) { + info->info.play.sample_rate = sampleRate; + info->info.play.precision = sampleSizeInBits; + info->info.play.channels = channels; + info->info.play.encoding = AUDIO_ENCODING_LINEAR; + info->info.play.buffer_size = bufferSizeInBytes; + info->info.play.pause = 1; + } else { + info->info.record.sample_rate = sampleRate; + info->info.record.precision = sampleSizeInBits; + info->info.record.channels = channels; + info->info.record.encoding = AUDIO_ENCODING_LINEAR; + info->info.record.buffer_size = bufferSizeInBytes; + info->info.record.pause = 1; + } + err = ioctl(info->fd, AUDIO_SETINFO, &(info->info)); + if (err < 0) { + ERROR0("DAUDIO_Open: could not set info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + DAUDIO_Flush((void*) info, isSource); + + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + if (err >= 0) { + if (isSource) { + info->bufferSizeInBytes = info->info.play.buffer_size; + } else { + info->bufferSizeInBytes = info->info.record.buffer_size; + } + TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n", + (int) bufferSizeInBytes, + (int) info->bufferSizeInBytes); + } else { + ERROR0("DAUDIO_Open: cannot get info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + TRACE0("< DAUDIO_Open: Opened device successfully.\n"); + return (void*) info; +} + + +int DAUDIO_Start(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Start\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // unpause + modified = FALSE; + if (isSource && audioInfo.play.pause) { + audioInfo.play.pause = 0; + modified = TRUE; + } + if (!isSource && audioInfo.record.pause) { + audioInfo.record.pause = 0; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +int DAUDIO_Stop(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Stop\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // pause + modified = FALSE; + if (isSource && !audioInfo.play.pause) { + audioInfo.play.pause = 1; + modified = TRUE; + } + if (!isSource && !audioInfo.record.pause) { + audioInfo.record.pause = 1; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +void DAUDIO_Close(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + + TRACE0("DAUDIO_Close\n"); + if (info != NULL) { + if (info->fd >= 0) { + DAUDIO_Flush(id, isSource); + close(info->fd); + } + free(info); + } +} + +#ifndef USE_TRACE +/* close to 2^31 */ +#define POSITION_MAX 2000000000 +#else +/* for testing */ +#define POSITION_MAX 1000000 +#endif + +void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + int offset = -1; + int underrun = FALSE; + int devBytes = 0; + + if (count > 0) { + info->transferedBytes += count; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + underrun = prinfo->error; + devBytes = prinfo->samples * info->frameSize; + } + AUDIO_INITINFO(&audioInfo); + if (underrun) { + /* if an underrun occurred, reset */ + ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n", + (devBytes - info->transferedBytes)); + ERROR1(" devBytes from %d to 0, ", devBytes); + ERROR2(" positionOffset from %d to %d ", + (int) info->positionOffset, + (int) (info->positionOffset + info->transferedBytes)); + ERROR1(" transferedBytes from %d to 0\n", + (int) info->transferedBytes); + prinfo->samples = 0; + info->positionOffset += info->transferedBytes; + info->transferedBytes = 0; + } + else if (info->transferedBytes > POSITION_MAX) { + /* we will reset transferedBytes and + * the samples field in prinfo + */ + offset = devBytes; + prinfo->samples = 0; + } + /* reset error flag */ + prinfo->error = 0; + + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + if (err >= 0) { + if (offset > 0) { + /* upon exit of AUDIO_SETINFO, the samples parameter + * was set to the previous value. This is our + * offset. + */ + TRACE1("Adjust samplePos: offset=%d, ", (int) offset); + TRACE2("transferedBytes=%d -> %d, ", + (int) info->transferedBytes, + (int) (info->transferedBytes - offset)); + TRACE2("positionOffset=%d -> %d\n", + (int) (info->positionOffset), + (int) (((int) info->positionOffset) + offset)); + info->transferedBytes -= offset; + info->positionOffset += offset; + } + } else { + ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n"); + } + } +} + +// returns -1 on error +int DAUDIO_Write(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Write %d bytes\n", byteSize); + if (info!=NULL) { + ret = write(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); + return ret; +} + +// returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Read %d bytes\n", byteSize); + if (info != NULL) { + ret = read(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); + return ret; +} + + +int DAUDIO_GetBufferSize(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + if (info) { + return info->bufferSizeInBytes; + } + return 0; +} + +int DAUDIO_StillDraining(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int ret = FALSE; + + if (info!=NULL) { + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + /* check error flag */ + AUDIO_INITINFO(&audioInfo); + ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + ret = (prinfo->error != 0)?FALSE:TRUE; + } + return ret; +} + + +int getDevicePosition(SolPcmInfo* info, int isSource) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + /*TRACE2("---> device paused: %d eof=%d\n", + prinfo->pause, prinfo->eof); + */ + return (int) (prinfo->samples * info->frameSize); + } + ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n"); + return -1; +} + +int DAUDIO_Flush(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err = -1; + int pos; + + TRACE0("DAUDIO_Flush\n"); + if (info) { + if (isSource) { + err = ioctl(info->fd, I_FLUSH, FLUSHW); + } else { + err = ioctl(info->fd, I_FLUSH, FLUSHR); + } + if (err >= 0) { + /* resets the transferedBytes parameter to + * the current samples count of the device + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->transferedBytes = pos; + } + } + } + if (err < 0) { + ERROR0("ERROR in DAUDIO_Flush\n"); + } + return (err < 0)?FALSE:TRUE; +} + +int DAUDIO_GetAvailable(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = 0; + int pos; + + if (info) { + /* unfortunately, the STREAMS architecture + * seems to not have a method for querying + * the available bytes to read/write! + * estimate it... + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + if (isSource) { + /* we usually have written more bytes + * to the queue than the device position should be + */ + ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos); + } else { + /* for record, the device stream should + * be usually ahead of our read actions + */ + ret = pos - info->transferedBytes; + } + if (ret > info->bufferSizeInBytes) { + ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n", + (int) ret, (int) info->bufferSizeInBytes); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = info->bufferSizeInBytes; + } + else if (ret < 0) { + ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n", + (int) ret); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = 0; + } + } + } + + TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); + return ret; +} + +INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + INT64 result = javaBytePos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + result = info->positionOffset + pos; + } + } + + //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); + return result; +} + + +void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->positionOffset = javaBytePos - pos; + } + } +} + +int DAUDIO_RequiresServicing(void* id, int isSource) { + // never need servicing on Solaris + return FALSE; +} + +void DAUDIO_Service(void* id, int isSource) { + // never need servicing on Solaris +} + + +#endif // USE_DAUDIO --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c 2018-03-15 02:00:53.526586463 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c 2018-03-15 02:00:53.210586465 +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 --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.c 2018-03-15 02:00:53.998586459 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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; -} --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c 2018-03-15 02:00:53.710586461 +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; +} --- old/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.h 2018-03-15 02:00:54.462586456 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -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 --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h 2018-03-15 02:00:54.150586458 +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 --- old/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.cpp 2018-03-15 02:00:54.906586452 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2017, 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 "PLATFORM_API_WinOS_Charset_Util.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -LPSTR UnicodeToUTF8(const LPCWSTR lpUnicodeStr) -{ - DWORD dwUTF8Len = WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, nullptr, 0, nullptr, nullptr); - LPSTR lpUTF8Str = new CHAR[dwUTF8Len]; - memset(lpUTF8Str, 0, sizeof(CHAR) * (dwUTF8Len)); - WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, lpUTF8Str, dwUTF8Len, nullptr, nullptr); - return lpUTF8Str; -} - -void UnicodeToUTF8AndCopy(LPSTR dest, LPCWSTR src, SIZE_T maxLength) { - LPSTR utf8EncodedName = UnicodeToUTF8(src); - strncpy(dest, utf8EncodedName, maxLength - 1); - delete[] utf8EncodedName; - dest[maxLength - 1] = '\0'; -} - -#ifdef __cplusplus -} -#endif --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/windows/native/common/sound/PLATFORM_API_WinOS_Charset_Util.cpp 2018-03-15 02:00:54.618586455 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, 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 "PLATFORM_API_WinOS_Charset_Util.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +LPSTR UnicodeToUTF8(const LPCWSTR lpUnicodeStr) +{ + DWORD dwUTF8Len = WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, nullptr, 0, nullptr, nullptr); + LPSTR lpUTF8Str = new CHAR[dwUTF8Len]; + memset(lpUTF8Str, 0, sizeof(CHAR) * (dwUTF8Len)); + WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, lpUTF8Str, dwUTF8Len, nullptr, nullptr); + return lpUTF8Str; +} + +void UnicodeToUTF8AndCopy(LPSTR dest, LPCWSTR src, SIZE_T maxLength) { + LPSTR utf8EncodedName = UnicodeToUTF8(src); + strncpy(dest, utf8EncodedName, maxLength - 1); + delete[] utf8EncodedName; + dest[maxLength - 1] = '\0'; +} + +#ifdef __cplusplus +} +#endif --- old/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.h 2018-03-15 02:00:55.398586449 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 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. - */ - -#ifndef PLATFORM_API_WINOS_CHARSET_UTILS_H -#define PLATFORM_API_WINOS_CHARSET_UTILS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// NOTE: It's a caller responbility to free the allocated memory using delete[], just like in UnicodeToUTF8AndCopy function -LPSTR _cdecl UnicodeToUTF8(const LPCWSTR lpAnsiStr); - -void _cdecl UnicodeToUTF8AndCopy(LPSTR dest, LPCWSTR src, SIZE_T maxLength); - -#ifdef __cplusplus -} -#endif - -#endif --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/windows/native/common/sound/PLATFORM_API_WinOS_Charset_Util.h 2018-03-15 02:00:55.082586451 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, 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. + */ + +#ifndef PLATFORM_API_WINOS_CHARSET_UTILS_H +#define PLATFORM_API_WINOS_CHARSET_UTILS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// NOTE: It's a caller responbility to free the allocated memory using delete[], just like in UnicodeToUTF8AndCopy function +LPSTR _cdecl UnicodeToUTF8(const LPCWSTR lpAnsiStr); + +void _cdecl UnicodeToUTF8AndCopy(LPSTR dest, LPCWSTR src, SIZE_T maxLength); + +#ifdef __cplusplus +} +#endif + +#endif --- old/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_DirectSound.cpp 2018-03-15 02:00:55.874586445 +0100 +++ /dev/null 2018-02-16 14:25:25.622524048 +0100 @@ -1,1421 +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 - -/* define this for the silencing/servicing code. Requires USE_TRACE */ -//#define USE_DEBUG_SILENCING - -#ifndef WIN32_EXTRA_LEAN -#define WIN32_EXTRA_LEAN -#endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include -#include -#include - -/* include DirectSound headers */ -#include - -/* include Java Sound specific headers as C code */ -#ifdef __cplusplus -extern "C" { -#endif - #include "DirectAudio.h" -#ifdef __cplusplus -} -#endif - -/* include to prevent charset problem */ -#include "PLATFORM_API_WinOS_Charset_Util.h" - -#ifdef USE_DEBUG_SILENCING -#define DEBUG_SILENCING0(p) TRACE0(p) -#define DEBUG_SILENCING1(p1,p2) TRACE1(p1,p2) -#define DEBUG_SILENCING2(p1,p2,p3) TRACE2(p1,p2,p3) -#else -#define DEBUG_SILENCING0(p) -#define DEBUG_SILENCING1(p1,p2) -#define DEBUG_SILENCING2(p1,p2,p3) -#endif - - -#if USE_DAUDIO == TRUE - -/* half a minute to wait before device list is re-read */ -#define WAIT_BETWEEN_CACHE_REFRESH_MILLIS 30000 - -/* maximum number of supported devices, playback+capture */ -#define MAX_DS_DEVICES 60 - -typedef struct { - INT32 mixerIndex; - BOOL isSource; - /* either LPDIRECTSOUND or LPDIRECTSOUNDCAPTURE */ - void* dev; - /* how many instances use the dev */ - INT32 refCount; - GUID guid; -} DS_AudioDeviceCache; - -static DS_AudioDeviceCache g_audioDeviceCache[MAX_DS_DEVICES]; -static INT32 g_cacheCount = 0; -static UINT64 g_lastCacheRefreshTime = 0; -static INT32 g_mixerCount = 0; - -BOOL DS_lockCache() { - /* dummy implementation for now, Java does locking */ - return TRUE; -} - -void DS_unlockCache() { - /* dummy implementation for now */ -} - -static GUID CLSID_DAUDIO_Zero = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -BOOL isEqualGUID(LPGUID lpGuid1, LPGUID lpGuid2) { - if (lpGuid1 == NULL || lpGuid2 == NULL) { - if (lpGuid1 == lpGuid2) { - return TRUE; - } - if (lpGuid1 == NULL) { - lpGuid1 = (LPGUID) (&CLSID_DAUDIO_Zero); - } else { - lpGuid2 = (LPGUID) (&CLSID_DAUDIO_Zero); - } - } - return memcmp(lpGuid1, lpGuid2, sizeof(GUID)) == 0; -} - -INT32 findCacheItemByGUID(LPGUID lpGuid, BOOL isSource) { - int i; - for (i = 0; i < g_cacheCount; i++) { - if (isSource == g_audioDeviceCache[i].isSource - && isEqualGUID(lpGuid, &(g_audioDeviceCache[i].guid))) { - return i; - } - } - return -1; -} - -INT32 findCacheItemByMixerIndex(INT32 mixerIndex) { - int i; - for (i = 0; i < g_cacheCount; i++) { - if (g_audioDeviceCache[i].mixerIndex == mixerIndex) { - return i; - } - } - return -1; -} - -typedef struct { - INT32 currMixerIndex; - BOOL isSource; -} DS_RefreshCacheStruct; - - -BOOL CALLBACK DS_RefreshCacheEnum(LPGUID lpGuid, - LPCSTR lpstrDescription, - LPCSTR lpstrModule, - DS_RefreshCacheStruct* rs) { - INT32 cacheIndex = findCacheItemByGUID(lpGuid, rs->isSource); - /*TRACE3("Enumerating %d: %s (%s)\n", cacheIndex, lpstrDescription, lpstrModule);*/ - if (cacheIndex == -1) { - /* add this device */ - if (g_cacheCount < MAX_DS_DEVICES-1) { - g_audioDeviceCache[g_cacheCount].mixerIndex = rs->currMixerIndex; - g_audioDeviceCache[g_cacheCount].isSource = rs->isSource; - g_audioDeviceCache[g_cacheCount].dev = NULL; - g_audioDeviceCache[g_cacheCount].refCount = 0; - if (lpGuid == NULL) { - memset(&(g_audioDeviceCache[g_cacheCount].guid), 0, sizeof(GUID)); - } else { - memcpy(&(g_audioDeviceCache[g_cacheCount].guid), lpGuid, sizeof(GUID)); - } - g_cacheCount++; - rs->currMixerIndex++; - } else { - /* failure case: more than MAX_DS_DEVICES available... */ - } - } else { - /* device already exists in cache... update mixer number */ - g_audioDeviceCache[cacheIndex].mixerIndex = rs->currMixerIndex; - rs->currMixerIndex++; - } - /* continue enumeration */ - return TRUE; -} - -///// implemented functions of DirectAudio.h - -INT32 DAUDIO_GetDirectAudioDeviceCount() { - DS_RefreshCacheStruct rs; - INT32 oldCount; - INT32 cacheIndex; - - if (!DS_lockCache()) { - return 0; - } - - if (g_lastCacheRefreshTime == 0 - || (UINT64) timeGetTime() > (UINT64) (g_lastCacheRefreshTime + WAIT_BETWEEN_CACHE_REFRESH_MILLIS)) { - /* first, initialize any old cache items */ - for (cacheIndex = 0; cacheIndex < g_cacheCount; cacheIndex++) { - g_audioDeviceCache[cacheIndex].mixerIndex = -1; - } - - /* enumerate all devices and either add them to the device cache, - * or refresh the mixer number - */ - rs.currMixerIndex = 0; - rs.isSource = TRUE; - DirectSoundEnumerate((LPDSENUMCALLBACK) DS_RefreshCacheEnum, &rs); - /* if we only got the Primary Sound Driver (GUID=NULL), - * then there aren't any playback devices installed */ - if (rs.currMixerIndex == 1) { - cacheIndex = findCacheItemByGUID(NULL, TRUE); - if (cacheIndex == 0) { - rs.currMixerIndex = 0; - g_audioDeviceCache[0].mixerIndex = -1; - TRACE0("Removing stale Primary Sound Driver from list.\n"); - } - } - oldCount = rs.currMixerIndex; - rs.isSource = FALSE; - DirectSoundCaptureEnumerate((LPDSENUMCALLBACK) DS_RefreshCacheEnum, &rs); - /* if we only got the Primary Sound Capture Driver (GUID=NULL), - * then there aren't any capture devices installed */ - if ((rs.currMixerIndex - oldCount) == 1) { - cacheIndex = findCacheItemByGUID(NULL, FALSE); - if (cacheIndex != -1) { - rs.currMixerIndex = oldCount; - g_audioDeviceCache[cacheIndex].mixerIndex = -1; - TRACE0("Removing stale Primary Sound Capture Driver from list.\n"); - } - } - g_mixerCount = rs.currMixerIndex; - - g_lastCacheRefreshTime = (UINT64) timeGetTime(); - } - DS_unlockCache(); - /*TRACE1("DirectSound: %d installed devices\n", g_mixerCount);*/ - return g_mixerCount; -} - -BOOL CALLBACK DS_GetDescEnum(LPGUID lpGuid, - LPCWSTR lpstrDescription, - LPCWSTR lpstrModule, - DirectAudioDeviceDescription* desc) { - - INT32 cacheIndex = findCacheItemByGUID(lpGuid, g_audioDeviceCache[desc->deviceID].isSource); - if (cacheIndex == desc->deviceID) { - UnicodeToUTF8AndCopy(desc->name, lpstrDescription, DAUDIO_STRING_LENGTH); - //strncpy(desc->description, lpstrModule, DAUDIO_STRING_LENGTH); - desc->maxSimulLines = -1; - /* do not continue enumeration */ - return FALSE; - } - return TRUE; -} - - -INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* desc) { - - if (!DS_lockCache()) { - return FALSE; - } - - /* set the deviceID field to the cache index */ - desc->deviceID = findCacheItemByMixerIndex(mixerIndex); - if (desc->deviceID < 0) { - DS_unlockCache(); - return FALSE; - } - desc->maxSimulLines = 0; - if (g_audioDeviceCache[desc->deviceID].isSource) { - DirectSoundEnumerateW((LPDSENUMCALLBACKW) DS_GetDescEnum, desc); - strncpy(desc->description, "DirectSound Playback", DAUDIO_STRING_LENGTH); - } else { - DirectSoundCaptureEnumerateW((LPDSENUMCALLBACKW) DS_GetDescEnum, desc); - strncpy(desc->description, "DirectSound Capture", DAUDIO_STRING_LENGTH); - } - - /*desc->vendor; - desc->version;*/ - - DS_unlockCache(); - return (desc->maxSimulLines == -1)?TRUE:FALSE; -} - -/* multi-channel info: http://www.microsoft.com/whdc/hwdev/tech/audio/multichaud.mspx */ - -//static UINT32 sampleRateArray[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 56000, 88000, 96000, 172000, 192000 }; -static INT32 sampleRateArray[] = { -1 }; -static INT32 channelsArray[] = { 1, 2}; -static INT32 bitsArray[] = { 8, 16}; - -#define SAMPLERATE_COUNT sizeof(sampleRateArray)/sizeof(INT32) -#define CHANNELS_COUNT sizeof(channelsArray)/sizeof(INT32) -#define BITS_COUNT sizeof(bitsArray)/sizeof(INT32) - -void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { - - int rateIndex, channelIndex, bitIndex; - - /* no need to lock, since deviceID identifies the device sufficiently */ - - /* sanity */ - if (deviceID >= g_cacheCount) { - return; - } - if ((g_audioDeviceCache[deviceID].isSource && !isSource) - || (!g_audioDeviceCache[deviceID].isSource && isSource)) { - /* only support Playback or Capture */ - return; - } - - for (rateIndex = 0; rateIndex < SAMPLERATE_COUNT; rateIndex++) { - for (channelIndex = 0; channelIndex < CHANNELS_COUNT; channelIndex++) { - for (bitIndex = 0; bitIndex < BITS_COUNT; bitIndex++) { - DAUDIO_AddAudioFormat(creator, bitsArray[bitIndex], - ((bitsArray[bitIndex] + 7) / 8) * channelsArray[channelIndex], - channelsArray[channelIndex], - (float) sampleRateArray[rateIndex], - DAUDIO_PCM, - (bitsArray[bitIndex]==8)?FALSE:TRUE, /* signed */ - (bitsArray[bitIndex]==8)?FALSE: -#ifndef _LITTLE_ENDIAN - TRUE /* big endian */ -#else - FALSE /* little endian */ -#endif - ); - } - } - } -} - -typedef struct { - int deviceID; - /* for convenience */ - BOOL isSource; - /* the secondary buffer (Playback) */ - LPDIRECTSOUNDBUFFER playBuffer; - /* the secondary buffer (Capture) */ - LPDIRECTSOUNDCAPTUREBUFFER captureBuffer; - - /* size of the directsound buffer, usually 2 seconds */ - int dsBufferSizeInBytes; - - /* size of the read/write-ahead, as specified by Java */ - int bufferSizeInBytes; - int bitsPerSample; - int frameSize; // storage size in Bytes - - UINT64 framePos; - /* where to write into the buffer. - * -1 if at current position (Playback) - * For Capture, this is the read position - */ - int writePos; - - /* if start() had been called */ - BOOL started; - - /* how many bytes there is silence from current write position */ - int silencedBytes; - - BOOL underrun; - -} DS_Info; - - -LPSTR TranslateDSError(HRESULT hr) { - switch(hr) { - case DSERR_ALLOCATED: - return "DSERR_ALLOCATED"; - - case DSERR_CONTROLUNAVAIL: - return "DSERR_CONTROLUNAVAIL"; - - case DSERR_INVALIDPARAM: - return "DSERR_INVALIDPARAM"; - - case DSERR_INVALIDCALL: - return "DSERR_INVALIDCALL"; - - case DSERR_GENERIC: - return "DSERR_GENERIC"; - - case DSERR_PRIOLEVELNEEDED: - return "DSERR_PRIOLEVELNEEDED"; - - case DSERR_OUTOFMEMORY: - return "DSERR_OUTOFMEMORY"; - - case DSERR_BADFORMAT: - return "DSERR_BADFORMAT"; - - case DSERR_UNSUPPORTED: - return "DSERR_UNSUPPORTED"; - - case DSERR_NODRIVER: - return "DSERR_NODRIVER"; - - case DSERR_ALREADYINITIALIZED: - return "DSERR_ALREADYINITIALIZED"; - - case DSERR_NOAGGREGATION: - return "DSERR_NOAGGREGATION"; - - case DSERR_BUFFERLOST: - return "DSERR_BUFFERLOST"; - - case DSERR_OTHERAPPHASPRIO: - return "DSERR_OTHERAPPHASPRIO"; - - case DSERR_UNINITIALIZED: - return "DSERR_UNINITIALIZED"; - - default: - return "Unknown HRESULT"; - } -} - -/* -** data/routines for starting DS buffers by separate thread -** (joint into DS_StartBufferHelper class) -** see cr6372428: playback fails after exiting from thread that has started it -** due IDirectSoundBuffer8::Play() description: -** http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c -** /directx/htm/idirectsoundbuffer8play.asp -** (remark section): If the application is multithreaded, the thread that plays -** the buffer must continue to exist as long as the buffer is playing. -** Buffers created on WDM drivers stop playing when the thread is terminated. -** IDirectSoundCaptureBuffer8::Start() has the same remark: -** http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c -** /directx/htm/idirectsoundcapturebuffer8start.asp -*/ -class DS_StartBufferHelper { -public: - /* starts DirectSound buffer (playback or capture) */ - static HRESULT StartBuffer(DS_Info* info); - /* checks for initialization success */ - static inline BOOL isInitialized() { return data.threadHandle != NULL; } -protected: - DS_StartBufferHelper() {} // no need to create an instance - - /* data class */ - class Data { - public: - Data(); - ~Data(); - // public data to access from parent class - CRITICAL_SECTION crit_sect; - volatile HANDLE threadHandle; - volatile HANDLE startEvent; - volatile HANDLE startedEvent; - volatile DS_Info* line2Start; - volatile HRESULT startResult; - } static data; - - /* StartThread function */ - static DWORD WINAPI __stdcall ThreadProc(void *param); -}; - -/* StartBufferHelper class implementation -*/ -DS_StartBufferHelper::Data DS_StartBufferHelper::data; - -DS_StartBufferHelper::Data::Data() { - threadHandle = NULL; - ::InitializeCriticalSection(&crit_sect); - startEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); - startedEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); - if (startEvent != NULL && startedEvent != NULL) - threadHandle = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); -} - -DS_StartBufferHelper::Data::~Data() { - ::EnterCriticalSection(&crit_sect); - if (threadHandle != NULL) { - // terminate thread - line2Start = NULL; - ::SetEvent(startEvent); - ::CloseHandle(threadHandle); - threadHandle = NULL; - } - ::LeaveCriticalSection(&crit_sect); - // won't delete startEvent/startedEvent/crit_sect - // - Windows will do during process shutdown -} - -DWORD WINAPI __stdcall DS_StartBufferHelper::ThreadProc(void *param) -{ - ::CoInitialize(NULL); - while (1) { - // wait for something to do - ::WaitForSingleObject(data.startEvent, INFINITE); - if (data.line2Start == NULL) { - // (data.line2Start == NULL) is a signal to terminate thread - break; - } - if (data.line2Start->isSource) { - data.startResult = - data.line2Start->playBuffer->Play(0, 0, DSBPLAY_LOOPING); - } else { - data.startResult = - data.line2Start->captureBuffer->Start(DSCBSTART_LOOPING); - } - ::SetEvent(data.startedEvent); - } - ::CoUninitialize(); - return 0; -} - -HRESULT DS_StartBufferHelper::StartBuffer(DS_Info* info) { - HRESULT hr; - ::EnterCriticalSection(&data.crit_sect); - if (!isInitialized()) { - ::LeaveCriticalSection(&data.crit_sect); - return E_FAIL; - } - data.line2Start = info; - ::SetEvent(data.startEvent); - ::WaitForSingleObject(data.startedEvent, INFINITE); - hr = data.startResult; - ::LeaveCriticalSection(&data.crit_sect); - return hr; -} - - -/* helper routines for DS buffer positions */ -/* returns distance from pos1 to pos2 - */ -inline int DS_getDistance(DS_Info* info, int pos1, int pos2) { - int distance = pos2 - pos1; - while (distance < 0) - distance += info->dsBufferSizeInBytes; - return distance; -} - -/* adds 2 positions - */ -inline int DS_addPos(DS_Info* info, int pos1, int pos2) { - int result = pos1 + pos2; - while (result >= info->dsBufferSizeInBytes) - result -= info->dsBufferSizeInBytes; - return result; -} - - -BOOL DS_addDeviceRef(INT32 deviceID) { - HWND ownerWindow; - HRESULT res = DS_OK; - LPDIRECTSOUND devPlay; - LPDIRECTSOUNDCAPTURE devCapture; - LPGUID lpGuid = NULL; - - - if (g_audioDeviceCache[deviceID].dev == NULL) { - /* Create DirectSound */ - TRACE1("Creating DirectSound object for device %d\n", deviceID); - lpGuid = &(g_audioDeviceCache[deviceID].guid); - if (isEqualGUID(lpGuid, NULL)) { - lpGuid = NULL; - } - if (g_audioDeviceCache[deviceID].isSource) { - res = DirectSoundCreate(lpGuid, &devPlay, NULL); - g_audioDeviceCache[deviceID].dev = (void*) devPlay; - } else { - res = DirectSoundCaptureCreate(lpGuid, &devCapture, NULL); - g_audioDeviceCache[deviceID].dev = (void*) devCapture; - } - g_audioDeviceCache[deviceID].refCount = 0; - if (FAILED(res)) { - ERROR1("DAUDIO_Open: ERROR: Failed to create DirectSound: %s", TranslateDSError(res)); - g_audioDeviceCache[deviceID].dev = NULL; - return FALSE; - } - if (g_audioDeviceCache[deviceID].isSource) { - ownerWindow = GetForegroundWindow(); - if (ownerWindow == NULL) { - ownerWindow = GetDesktopWindow(); - } - TRACE0("DAUDIO_Open: Setting cooperative level\n"); - res = devPlay->SetCooperativeLevel(ownerWindow, DSSCL_NORMAL); - if (FAILED(res)) { - ERROR1("DAUDIO_Open: ERROR: Failed to set cooperative level: %s", TranslateDSError(res)); - return FALSE; - } - } - } - g_audioDeviceCache[deviceID].refCount++; - return TRUE; -} - -#define DEV_PLAY(devID) ((LPDIRECTSOUND) g_audioDeviceCache[devID].dev) -#define DEV_CAPTURE(devID) ((LPDIRECTSOUNDCAPTURE) g_audioDeviceCache[devID].dev) - -void DS_removeDeviceRef(INT32 deviceID) { - - if (g_audioDeviceCache[deviceID].refCount) { - g_audioDeviceCache[deviceID].refCount--; - } - if (g_audioDeviceCache[deviceID].refCount == 0) { - if (g_audioDeviceCache[deviceID].dev != NULL) { - if (g_audioDeviceCache[deviceID].isSource) { - DEV_PLAY(deviceID)->Release(); - } else { - DEV_CAPTURE(deviceID)->Release(); - } - g_audioDeviceCache[deviceID].dev = NULL; - } - } -} - -#ifndef _WAVEFORMATEXTENSIBLE_ -#define _WAVEFORMATEXTENSIBLE_ -typedef struct { - WAVEFORMATEX Format; - union { - WORD wValidBitsPerSample; /* bits of precision */ - WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ - WORD wReserved; /* If neither applies, set to zero. */ - } Samples; - DWORD dwChannelMask; /* which channels are */ - /* present in stream */ - GUID SubFormat; -} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; -#endif // !_WAVEFORMATEXTENSIBLE_ - -#if !defined(WAVE_FORMAT_EXTENSIBLE) -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif // !defined(WAVE_FORMAT_EXTENSIBLE) - -#if !defined(DEFINE_WAVEFORMATEX_GUID) -#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 -#endif -#ifndef STATIC_KSDATAFORMAT_SUBTYPE_PCM -#define STATIC_KSDATAFORMAT_SUBTYPE_PCM\ - DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_PCM) -#endif - - -void createWaveFormat(WAVEFORMATEXTENSIBLE* format, - int sampleRate, - int channels, - int bits, - int significantBits) { - GUID subtypePCM = {STATIC_KSDATAFORMAT_SUBTYPE_PCM}; - format->Format.nSamplesPerSec = (DWORD)sampleRate; - format->Format.nChannels = (WORD) channels; - /* do not support useless padding, like 24-bit samples stored in 32-bit containers */ - format->Format.wBitsPerSample = (WORD) ((bits + 7) & 0xFFF8); - - if (channels <= 2 && bits <= 16) { - format->Format.wFormatTag = WAVE_FORMAT_PCM; - format->Format.cbSize = 0; - } else { - format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - format->Format.cbSize = 22; - format->Samples.wValidBitsPerSample = bits; - /* no way to specify speaker locations */ - format->dwChannelMask = 0xFFFFFFFF; - format->SubFormat = subtypePCM; - } - format->Format.nBlockAlign = (WORD)((format->Format.wBitsPerSample * format->Format.nChannels) / 8); - format->Format.nAvgBytesPerSec = format->Format.nSamplesPerSec * format->Format.nBlockAlign; -} - -/* fill buffer with silence - */ -void DS_clearBuffer(DS_Info* info, BOOL fromWritePos) { - UBYTE* pb1=NULL, *pb2=NULL; - DWORD cb1=0, cb2=0; - DWORD flags = 0; - int start, count; - TRACE1("> DS_clearBuffer for device %d\n", info->deviceID); - if (info->isSource) { - if (fromWritePos) { - DWORD playCursor, writeCursor; - int end; - if (FAILED(info->playBuffer->GetCurrentPosition(&playCursor, &writeCursor))) { - ERROR0(" DS_clearBuffer: ERROR: Failed to get current position."); - TRACE0("< DS_clearbuffer\n"); - return; - } - DEBUG_SILENCING2(" DS_clearBuffer: DS playPos=%d myWritePos=%d", (int) playCursor, (int) info->writePos); - if (info->writePos >= 0) { - start = info->writePos + info->silencedBytes; - } else { - start = writeCursor + info->silencedBytes; - //flags |= DSBLOCK_FROMWRITECURSOR; - } - while (start >= info->dsBufferSizeInBytes) { - start -= info->dsBufferSizeInBytes; - } - - // fix for bug 6251460 (REGRESSION: short sounds do not play) - // for unknown reason with hardware DS buffer playCursor sometimes - // jumps back for little interval (mostly 2-8 bytes) (writeCursor moves forward as usual) - // The issue happens right after start playing and for short sounds only (less then DS buffer, - // when whole sound written into the buffer and remaining space filled by silence) - // the case doesn't produce any audible aftifacts so just catch it to prevent filling - // whole buffer by silence. - if (((int)playCursor <= start && start < (int)writeCursor) - || (writeCursor < playCursor // buffer bound is between playCursor & writeCursor - && (start < (int)writeCursor || (int)playCursor <= start))) { - return; - } - - count = info->dsBufferSizeInBytes - info->silencedBytes; - // why / 4? - //if (count > info->dsBufferSizeInBytes / 4) { - // count = info->dsBufferSizeInBytes / 4; - //} - end = start + count; - if ((int) playCursor < start) { - playCursor += (DWORD) info->dsBufferSizeInBytes; - } - if (start <= (int) playCursor && end > (int) playCursor) { - /* at maximum, silence until play cursor */ - count = (int) playCursor - start; -#ifdef USE_TRACE - if ((int) playCursor >= info->dsBufferSizeInBytes) playCursor -= (DWORD) info->dsBufferSizeInBytes; - TRACE3("\n DS_clearBuffer: Start Writing from %d, " - "would overwrite playCursor=%d, so reduce count to %d\n", - start, playCursor, count); -#endif - } - DEBUG_SILENCING2(" clearing buffer from %d, count=%d. ", (int)start, (int) count); - if (count <= 0) { - DEBUG_SILENCING0("\n"); - TRACE1("< DS_clearBuffer: no need to clear, silencedBytes=%d\n", info->silencedBytes); - return; - } - } else { - start = 0; - count = info->dsBufferSizeInBytes; - flags |= DSBLOCK_ENTIREBUFFER; - } - if (FAILED(info->playBuffer->Lock(start, - count, - (LPVOID*) &pb1, &cb1, - (LPVOID*) &pb2, &cb2, flags))) { - ERROR0("\n DS_clearBuffer: ERROR: Failed to lock sound buffer.\n"); - TRACE0("< DS_clearbuffer\n"); - return; - } - } else { - if (FAILED(info->captureBuffer->Lock(0, - info->dsBufferSizeInBytes, - (LPVOID*) &pb1, &cb1, - (LPVOID*) &pb2, &cb2, DSCBLOCK_ENTIREBUFFER))) { - ERROR0(" DS_clearBuffer: ERROR: Failed to lock sound buffer.\n"); - TRACE0("< DS_clearbuffer\n"); - return; - } - } - if (pb1!=NULL) { - memset(pb1, (info->bitsPerSample == 8)?128:0, cb1); - } - if (pb2!=NULL) { - memset(pb2, (info->bitsPerSample == 8)?128:0, cb2); - } - if (info->isSource) { - info->playBuffer->Unlock( pb1, cb1, pb2, cb2 ); - if (!fromWritePos) { - /* doesn't matter where to start writing next time */ - info->writePos = -1; - info->silencedBytes = info->dsBufferSizeInBytes; - } else { - info->silencedBytes += (cb1+cb2); - if (info->silencedBytes > info->dsBufferSizeInBytes) { - ERROR1(" DS_clearbuffer: ERROR: silencedBytes=%d exceeds buffer size!\n", - info->silencedBytes); - info->silencedBytes = info->dsBufferSizeInBytes; - } - } - DEBUG_SILENCING2(" silencedBytes=%d, my writePos=%d\n", (int)info->silencedBytes, (int)info->writePos); - } else { - info->captureBuffer->Unlock( pb1, cb1, pb2, cb2 ); - } - TRACE0("< DS_clearbuffer\n"); -} - -/* returns pointer to buffer */ -void* DS_createSoundBuffer(DS_Info* info, - float sampleRate, - int sampleSizeInBits, - int channels, - int bufferSizeInBytes) { - DSBUFFERDESC dsbdesc; - DSCBUFFERDESC dscbdesc; - HRESULT res; - WAVEFORMATEXTENSIBLE format; - void* buffer; - - TRACE1("Creating secondary buffer for device %d\n", info->deviceID); - createWaveFormat(&format, - (int) sampleRate, - channels, - info->frameSize / channels * 8, - sampleSizeInBits); - - /* 2 second secondary buffer */ - info->dsBufferSizeInBytes = 2 * ((int) sampleRate) * info->frameSize; - - if (bufferSizeInBytes > info->dsBufferSizeInBytes / 2) { - bufferSizeInBytes = info->dsBufferSizeInBytes / 2; - } - bufferSizeInBytes = (bufferSizeInBytes / info->frameSize) * info->frameSize; - info->bufferSizeInBytes = bufferSizeInBytes; - - if (info->isSource) { - memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 - | DSBCAPS_GLOBALFOCUS; - - dsbdesc.dwBufferBytes = info->dsBufferSizeInBytes; - dsbdesc.lpwfxFormat = (WAVEFORMATEX*) &format; - res = DEV_PLAY(info->deviceID)->CreateSoundBuffer - (&dsbdesc, (LPDIRECTSOUNDBUFFER*) &buffer, NULL); - } else { - memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC)); - dscbdesc.dwSize = sizeof(DSCBUFFERDESC); - dscbdesc.dwFlags = 0; - dscbdesc.dwBufferBytes = info->dsBufferSizeInBytes; - dscbdesc.lpwfxFormat = (WAVEFORMATEX*) &format; - res = DEV_CAPTURE(info->deviceID)->CreateCaptureBuffer - (&dscbdesc, (LPDIRECTSOUNDCAPTUREBUFFER*) &buffer, NULL); - } - if (FAILED(res)) { - ERROR1("DS_createSoundBuffer: ERROR: Failed to create sound buffer: %s", TranslateDSError(res)); - return NULL; - } - return buffer; -} - -void DS_destroySoundBuffer(DS_Info* info) { - if (info->playBuffer != NULL) { - info->playBuffer->Release(); - info->playBuffer = NULL; - } - if (info->captureBuffer != NULL) { - info->captureBuffer->Release(); - info->captureBuffer = 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) { - - DS_Info* info; - void* buffer; - - TRACE0("> DAUDIO_Open\n"); - - /* some sanity checks */ - if (deviceID >= g_cacheCount) { - ERROR1("DAUDIO_Open: ERROR: cannot open the device with deviceID=%d!\n", deviceID); - return NULL; - } - if ((g_audioDeviceCache[deviceID].isSource && !isSource) - || (!g_audioDeviceCache[deviceID].isSource && isSource)) { - /* only support Playback or Capture */ - ERROR0("DAUDIO_Open: ERROR: Cache is corrupt: cannot open the device in specified isSource mode!\n"); - return NULL; - } - if (encoding != DAUDIO_PCM) { - ERROR1("DAUDIO_Open: ERROR: cannot open the device with encoding=%d!\n", encoding); - return NULL; - } - if (channels <= 0) { - ERROR1("DAUDIO_Open: ERROR: Invalid number of channels=%d!\n", channels); - return NULL; - } - if (sampleSizeInBits > 8 && -#ifdef _LITTLE_ENDIAN - isBigEndian -#else - !isBigEndian -#endif - ) { - ERROR1("DAUDIO_Open: ERROR: wrong endianness: isBigEndian==%d!\n", isBigEndian); - return NULL; - } - if (sampleSizeInBits == 8 && isSigned) { - ERROR0("DAUDIO_Open: ERROR: wrong signed'ness: with 8 bits, data must be unsigned!\n"); - return NULL; - } - if (!DS_StartBufferHelper::isInitialized()) { - ERROR0("DAUDIO_Open: ERROR: StartBufferHelper initialization was failed!\n"); - return NULL; - } - - info = (DS_Info*) malloc(sizeof(DS_Info)); - if (!info) { - ERROR0("DAUDIO_Open: ERROR: Out of memory\n"); - return NULL; - } - memset(info, 0, sizeof(DS_Info)); - - info->deviceID = deviceID; - info->isSource = isSource; - info->bitsPerSample = sampleSizeInBits; - info->frameSize = frameSize; - info->framePos = 0; - info->started = FALSE; - info->underrun = FALSE; - - if (!DS_addDeviceRef(deviceID)) { - DS_removeDeviceRef(deviceID); - free(info); - return NULL; - } - - buffer = DS_createSoundBuffer(info, - sampleRate, - sampleSizeInBits, - channels, - bufferSizeInBytes); - if (!buffer) { - DS_removeDeviceRef(deviceID); - free(info); - return NULL; - } - - if (info->isSource) { - info->playBuffer = (LPDIRECTSOUNDBUFFER) buffer; - } else { - info->captureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) buffer; - } - DS_clearBuffer(info, FALSE /* entire buffer */); - - /* use writepos of device */ - if (info->isSource) { - info->writePos = -1; - } else { - info->writePos = 0; - } - - TRACE0("< DAUDIO_Open: Opened device successfully.\n"); - return (void*) info; -} - -int DAUDIO_Start(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - HRESULT res = DS_OK; - DWORD status; - - TRACE0("> DAUDIO_Start\n"); - - if (info->isSource) { - res = info->playBuffer->GetStatus(&status); - if (res == DS_OK) { - if (status & DSBSTATUS_LOOPING) { - ERROR0("DAUDIO_Start: ERROR: Already started!"); - return TRUE; - } - - /* only start buffer if already something written to it */ - if (info->writePos >= 0) { - res = DS_StartBufferHelper::StartBuffer(info); - if (res == DSERR_BUFFERLOST) { - res = info->playBuffer->Restore(); - if (res == DS_OK) { - DS_clearBuffer(info, FALSE /* entire buffer */); - /* write() will trigger actual device start */ - } - } else { - /* make sure that we will have silence after - the currently valid audio data */ - DS_clearBuffer(info, TRUE /* from write position */); - } - } - } - } else { - if (info->captureBuffer->GetStatus(&status) == DS_OK) { - if (status & DSCBSTATUS_LOOPING) { - ERROR0("DAUDIO_Start: ERROR: Already started!"); - return TRUE; - } - } - res = DS_StartBufferHelper::StartBuffer(info); - } - if (FAILED(res)) { - ERROR1("DAUDIO_Start: ERROR: Failed to start: %s", TranslateDSError(res)); - return FALSE; - } - info->started = TRUE; - return TRUE; -} - -int DAUDIO_Stop(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - - TRACE0("> DAUDIO_Stop\n"); - - info->started = FALSE; - if (info->isSource) { - info->playBuffer->Stop(); - } else { - info->captureBuffer->Stop(); - } - - TRACE0("< DAUDIO_Stop\n"); - return TRUE; -} - - -void DAUDIO_Close(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - - TRACE0("DAUDIO_Close\n"); - - if (info != NULL) { - DS_destroySoundBuffer(info); - DS_removeDeviceRef(info->deviceID); - free(info); - } -} - -/* Check buffer for underrun - * This method is only meaningful for Output devices (write devices). - */ -void DS_CheckUnderrun(DS_Info* info, DWORD playCursor, DWORD writeCursor) { - TRACE5("DS_CheckUnderrun: playCursor=%d, writeCursor=%d, " - "info->writePos=%d silencedBytes=%d dsBufferSizeInBytes=%d\n", - (int) playCursor, (int) writeCursor, (int) info->writePos, - (int) info->silencedBytes, (int) info->dsBufferSizeInBytes); - if (info->underrun || info->writePos < 0) return; - int writeAhead = DS_getDistance(info, writeCursor, info->writePos); - if (writeAhead > info->bufferSizeInBytes) { - // this may occur after Stop(), when writeCursor decreases (real valid data size > bufferSizeInBytes) - // But the case can occur only when we have more then info->bufferSizeInBytes valid bytes - // (and less then (info->dsBufferSizeInBytes - info->bufferSizeInBytes) silenced bytes) - // If we already have a lot of silencedBytes after valid data (written by - // DAUDIO_StillDraining() or DAUDIO_Service()) then it's underrun - if (info->silencedBytes >= info->dsBufferSizeInBytes - info->bufferSizeInBytes) { - // underrun! - ERROR0("DS_CheckUnderrun: ERROR: underrun detected!\n"); - info->underrun = TRUE; - } - } -} - -/* For source (playback) line: - * (a) if (fromPlayCursor == FALSE), returns number of bytes available - * for writing: bufferSize - (info->writePos - writeCursor); - * (b) if (fromPlayCursor == TRUE), playCursor is used instead writeCursor - * and returned value can be used for play position calculation (see also - * note about bufferSize) - * For destination (capture) line: - * (c) if (fromPlayCursor == FALSE), returns number of bytes available - * for reading from the buffer: readCursor - info->writePos; - * (d) if (fromPlayCursor == TRUE), captureCursor is used instead readCursor - * and returned value can be used for capture position calculation (see - * note about bufferSize) - * bufferSize parameter are filled by "actual" buffer size: - * if (fromPlayCursor == FALSE), bufferSize = info->bufferSizeInBytes - * otherwise it increase by number of bytes currently processed by DirectSound - * (writeCursor - playCursor) or (captureCursor - readCursor) - */ -int DS_GetAvailable(DS_Info* info, - DWORD* playCursor, DWORD* writeCursor, - int* bufferSize, BOOL fromPlayCursor) { - int available; - int newReadPos; - - TRACE2("DS_GetAvailable: fromPlayCursor=%d, deviceID=%d\n", fromPlayCursor, info->deviceID); - if (!info->playBuffer && !info->captureBuffer) { - ERROR0("DS_GetAvailable: ERROR: buffer not yet created"); - return 0; - } - - if (info->isSource) { - if (FAILED(info->playBuffer->GetCurrentPosition(playCursor, writeCursor))) { - ERROR0("DS_GetAvailable: ERROR: Failed to get current position.\n"); - return 0; - } - int processing = DS_getDistance(info, (int)*playCursor, (int)*writeCursor); - // workaround: sometimes DirectSound report writeCursor is less (for several bytes) then playCursor - if (processing > info->dsBufferSizeInBytes / 2) { - *writeCursor = *playCursor; - processing = 0; - } - TRACE3(" playCursor=%d, writeCursor=%d, info->writePos=%d\n", - *playCursor, *writeCursor, info->writePos); - *bufferSize = info->bufferSizeInBytes; - if (fromPlayCursor) { - *bufferSize += processing; - } - DS_CheckUnderrun(info, *playCursor, *writeCursor); - if (info->writePos == -1 || (info->underrun && !fromPlayCursor)) { - /* always full buffer if at beginning */ - available = *bufferSize; - } else { - int currWriteAhead = DS_getDistance(info, fromPlayCursor ? (int)*playCursor : (int)*writeCursor, info->writePos); - if (currWriteAhead > *bufferSize) { - if (info->underrun) { - // playCursor surpassed writePos - no valid data, whole buffer available - available = *bufferSize; - } else { - // the case may occur after stop(), when writeCursor jumps back to playCursor - // so "actual" buffer size has grown - *bufferSize = currWriteAhead; - available = 0; - } - } else { - available = *bufferSize - currWriteAhead; - } - } - } else { - if (FAILED(info->captureBuffer->GetCurrentPosition(playCursor, writeCursor))) { - ERROR0("DS_GetAvailable: ERROR: Failed to get current position.\n"); - return 0; - } - *bufferSize = info->bufferSizeInBytes; - if (fromPlayCursor) { - *bufferSize += DS_getDistance(info, (int)*playCursor, (int)*writeCursor); - } - TRACE4(" captureCursor=%d, readCursor=%d, info->readPos=%d refBufferSize=%d\n", - *playCursor, *writeCursor, info->writePos, *bufferSize); - if (info->writePos == -1) { - /* always empty buffer if at beginning */ - info->writePos = (int) (*writeCursor); - } - if (fromPlayCursor) { - available = ((int) (*playCursor) - info->writePos); - } else { - available = ((int) (*writeCursor) - info->writePos); - } - if (available < 0) { - available += info->dsBufferSizeInBytes; - } - if (!fromPlayCursor && available > info->bufferSizeInBytes) { - /* overflow */ - ERROR2("DS_GetAvailable: ERROR: overflow detected: " - "DirectSoundBufferSize=%d, bufferSize=%d, ", - info->dsBufferSizeInBytes, info->bufferSizeInBytes); - ERROR3("captureCursor=%d, readCursor=%d, info->readPos=%d\n", - *playCursor, *writeCursor, info->writePos); - /* advance read position, to allow exactly one buffer worth of data */ - newReadPos = (int) (*writeCursor) - info->bufferSizeInBytes; - if (newReadPos < 0) { - newReadPos += info->dsBufferSizeInBytes; - } - info->writePos = newReadPos; - available = info->bufferSizeInBytes; - } - } - available = (available / info->frameSize) * info->frameSize; - - TRACE1("DS_available: Returning %d available bytes\n", (int) available); - return available; -} - -// returns -1 on error, otherwise bytes written -int DAUDIO_Write(void* id, char* data, int byteSize) { - DS_Info* info = (DS_Info*) id; - int available; - int thisWritePos; - DWORD playCursor, writeCursor; - HRESULT res; - void* buffer1, *buffer2; - DWORD buffer1len, buffer2len; - BOOL needRestart = FALSE; - int bufferLostTrials = 2; - int bufferSize; - - TRACE1("> DAUDIO_Write %d bytes\n", byteSize); - - while (--bufferLostTrials > 0) { - available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, FALSE /* fromPlayCursor */); - if (byteSize > available) byteSize = available; - if (byteSize == 0) break; - thisWritePos = info->writePos; - if (thisWritePos == -1 || info->underrun) { - // play from current write cursor after flush, etc. - needRestart = TRUE; - thisWritePos = writeCursor; - info->underrun = FALSE; - } - DEBUG_SILENCING2("DAUDIO_Write: writing from %d, count=%d\n", (int) thisWritePos, (int) byteSize); - res = info->playBuffer->Lock(thisWritePos, byteSize, - (LPVOID *) &buffer1, &buffer1len, - (LPVOID *) &buffer2, &buffer2len, - 0); - if (res != DS_OK) { - /* some DS failure */ - if (res == DSERR_BUFFERLOST) { - ERROR0("DAUDIO_write: ERROR: Restoring lost Buffer."); - if (info->playBuffer->Restore() == DS_OK) { - DS_clearBuffer(info, FALSE /* entire buffer */); - info->writePos = -1; - /* try again */ - continue; - } - } - /* can't recover from error */ - byteSize = 0; - break; - } - /* buffer could be locked successfully */ - /* first fill first buffer */ - if (buffer1) { - memcpy(buffer1, data, buffer1len); - data = (char*) (((UINT_PTR) data) + buffer1len); - } else buffer1len = 0; - if (buffer2) { - memcpy(buffer2, data, buffer2len); - } else buffer2len = 0; - byteSize = buffer1len + buffer2len; - - /* update next write pos */ - thisWritePos += byteSize; - while (thisWritePos >= info->dsBufferSizeInBytes) { - thisWritePos -= info->dsBufferSizeInBytes; - } - /* commit data to directsound */ - info->playBuffer->Unlock(buffer1, buffer1len, buffer2, buffer2len); - - info->writePos = thisWritePos; - - /* update position - * must be AFTER updating writePos, - * so that getSvailable doesn't return too little, - * so that getFramePos doesn't jump - */ - info->framePos += (byteSize / info->frameSize); - - /* decrease silenced bytes */ - if (info->silencedBytes > byteSize) { - info->silencedBytes -= byteSize; - } else { - info->silencedBytes = 0; - } - break; - } /* while */ - - /* start the device, if necessary */ - if (info->started && needRestart && (info->writePos >= 0)) { - DS_StartBufferHelper::StartBuffer(info); - } - - TRACE1("< DAUDIO_Write: returning %d bytes.\n", byteSize); - return byteSize; -} - -// returns -1 on error -int DAUDIO_Read(void* id, char* data, int byteSize) { - DS_Info* info = (DS_Info*) id; - int available; - int thisReadPos; - DWORD captureCursor, readCursor; - HRESULT res; - void* buffer1, *buffer2; - DWORD buffer1len, buffer2len; - int bufferSize; - - TRACE1("> DAUDIO_Read %d bytes\n", byteSize); - - available = DS_GetAvailable(info, &captureCursor, &readCursor, &bufferSize, FALSE /* fromCaptureCursor? */); - if (byteSize > available) byteSize = available; - if (byteSize > 0) { - thisReadPos = info->writePos; - if (thisReadPos == -1) { - /* from beginning */ - thisReadPos = 0; - } - res = info->captureBuffer->Lock(thisReadPos, byteSize, - (LPVOID *) &buffer1, &buffer1len, - (LPVOID *) &buffer2, &buffer2len, - 0); - if (res != DS_OK) { - /* can't recover from error */ - byteSize = 0; - } else { - /* buffer could be locked successfully */ - /* first fill first buffer */ - if (buffer1) { - memcpy(data, buffer1, buffer1len); - data = (char*) (((UINT_PTR) data) + buffer1len); - } else buffer1len = 0; - if (buffer2) { - memcpy(data, buffer2, buffer2len); - } else buffer2len = 0; - byteSize = buffer1len + buffer2len; - - /* update next read pos */ - thisReadPos = DS_addPos(info, thisReadPos, byteSize); - /* commit data to directsound */ - info->captureBuffer->Unlock(buffer1, buffer1len, buffer2, buffer2len); - - /* update position - * must be BEFORE updating readPos, - * so that getAvailable doesn't return too much, - * so that getFramePos doesn't jump - */ - info->framePos += (byteSize / info->frameSize); - - info->writePos = thisReadPos; - } - } - - TRACE1("< DAUDIO_Read: returning %d bytes.\n", byteSize); - return byteSize; -} - - -int DAUDIO_GetBufferSize(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - return info->bufferSizeInBytes; -} - -int DAUDIO_StillDraining(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - BOOL draining = FALSE; - int available, bufferSize; - DWORD playCursor, writeCursor; - - DS_clearBuffer(info, TRUE /* from write position */); - available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, TRUE /* fromPlayCursor */); - draining = (available < bufferSize); - - TRACE3("DAUDIO_StillDraining: available=%d silencedBytes=%d Still draining: %s\n", - available, info->silencedBytes, draining?"TRUE":"FALSE"); - return draining; -} - - -int DAUDIO_Flush(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - - TRACE0("DAUDIO_Flush\n"); - - if (info->isSource) { - info->playBuffer->Stop(); - DS_clearBuffer(info, FALSE /* entire buffer */); - } else { - DWORD captureCursor, readCursor; - /* set the read pointer to the current read position */ - if (FAILED(info->captureBuffer->GetCurrentPosition(&captureCursor, &readCursor))) { - ERROR0("DAUDIO_Flush: ERROR: Failed to get current position."); - return FALSE; - } - DS_clearBuffer(info, FALSE /* entire buffer */); - /* SHOULD set to *captureCursor*, - * but that would be detected as overflow - * in a subsequent GetAvailable() call. - */ - info->writePos = (int) readCursor; - } - return TRUE; -} - -int DAUDIO_GetAvailable(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - DWORD playCursor, writeCursor; - int ret, bufferSize; - - ret = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, /*fromPlayCursor?*/ FALSE); - - TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); - return ret; -} - -INT64 estimatePositionFromAvail(DS_Info* info, INT64 javaBytePos, int bufferSize, 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 (info->isSource) { - // javaBytePos is the position that is reached when the current - // buffer is played completely - return (INT64) (javaBytePos - bufferSize + 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) { - DS_Info* info = (DS_Info*) id; - int available, bufferSize; - DWORD playCursor, writeCursor; - INT64 result = javaBytePos; - - available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, /*fromPlayCursor?*/ TRUE); - result = estimatePositionFromAvail(info, javaBytePos, bufferSize, available); - 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) { - // need servicing on for SourceDataLines - return isSource?TRUE:FALSE; -} - -void DAUDIO_Service(void* id, int isSource) { - DS_Info* info = (DS_Info*) id; - if (isSource) { - if (info->silencedBytes < info->dsBufferSizeInBytes) { - // clear buffer - TRACE0("DAUDIO_Service\n"); - DS_clearBuffer(info, TRUE /* from write position */); - } - if (info->writePos >= 0 - && info->started - && !info->underrun - && info->silencedBytes >= info->dsBufferSizeInBytes) { - // if we're currently playing, and the entire buffer is silenced... - // then we are underrunning! - info->underrun = TRUE; - ERROR0("DAUDIO_Service: ERROR: DirectSound: underrun detected!\n"); - } - } -} - - -#endif // USE_DAUDIO --- /dev/null 2018-02-16 14:25:25.622524048 +0100 +++ new/src/java.desktop/windows/native/libjsoundds/PLATFORM_API_WinOS_DirectSound.cpp 2018-03-15 02:00:55.554586448 +0100 @@ -0,0 +1,1421 @@ +/* + * 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 + +/* define this for the silencing/servicing code. Requires USE_TRACE */ +//#define USE_DEBUG_SILENCING + +#ifndef WIN32_EXTRA_LEAN +#define WIN32_EXTRA_LEAN +#endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include + +/* include DirectSound headers */ +#include + +/* include Java Sound specific headers as C code */ +#ifdef __cplusplus +extern "C" { +#endif + #include "DirectAudio.h" +#ifdef __cplusplus +} +#endif + +/* include to prevent charset problem */ +#include "PLATFORM_API_WinOS_Charset_Util.h" + +#ifdef USE_DEBUG_SILENCING +#define DEBUG_SILENCING0(p) TRACE0(p) +#define DEBUG_SILENCING1(p1,p2) TRACE1(p1,p2) +#define DEBUG_SILENCING2(p1,p2,p3) TRACE2(p1,p2,p3) +#else +#define DEBUG_SILENCING0(p) +#define DEBUG_SILENCING1(p1,p2) +#define DEBUG_SILENCING2(p1,p2,p3) +#endif + + +#if USE_DAUDIO == TRUE + +/* half a minute to wait before device list is re-read */ +#define WAIT_BETWEEN_CACHE_REFRESH_MILLIS 30000 + +/* maximum number of supported devices, playback+capture */ +#define MAX_DS_DEVICES 60 + +typedef struct { + INT32 mixerIndex; + BOOL isSource; + /* either LPDIRECTSOUND or LPDIRECTSOUNDCAPTURE */ + void* dev; + /* how many instances use the dev */ + INT32 refCount; + GUID guid; +} DS_AudioDeviceCache; + +static DS_AudioDeviceCache g_audioDeviceCache[MAX_DS_DEVICES]; +static INT32 g_cacheCount = 0; +static UINT64 g_lastCacheRefreshTime = 0; +static INT32 g_mixerCount = 0; + +BOOL DS_lockCache() { + /* dummy implementation for now, Java does locking */ + return TRUE; +} + +void DS_unlockCache() { + /* dummy implementation for now */ +} + +static GUID CLSID_DAUDIO_Zero = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +BOOL isEqualGUID(LPGUID lpGuid1, LPGUID lpGuid2) { + if (lpGuid1 == NULL || lpGuid2 == NULL) { + if (lpGuid1 == lpGuid2) { + return TRUE; + } + if (lpGuid1 == NULL) { + lpGuid1 = (LPGUID) (&CLSID_DAUDIO_Zero); + } else { + lpGuid2 = (LPGUID) (&CLSID_DAUDIO_Zero); + } + } + return memcmp(lpGuid1, lpGuid2, sizeof(GUID)) == 0; +} + +INT32 findCacheItemByGUID(LPGUID lpGuid, BOOL isSource) { + int i; + for (i = 0; i < g_cacheCount; i++) { + if (isSource == g_audioDeviceCache[i].isSource + && isEqualGUID(lpGuid, &(g_audioDeviceCache[i].guid))) { + return i; + } + } + return -1; +} + +INT32 findCacheItemByMixerIndex(INT32 mixerIndex) { + int i; + for (i = 0; i < g_cacheCount; i++) { + if (g_audioDeviceCache[i].mixerIndex == mixerIndex) { + return i; + } + } + return -1; +} + +typedef struct { + INT32 currMixerIndex; + BOOL isSource; +} DS_RefreshCacheStruct; + + +BOOL CALLBACK DS_RefreshCacheEnum(LPGUID lpGuid, + LPCSTR lpstrDescription, + LPCSTR lpstrModule, + DS_RefreshCacheStruct* rs) { + INT32 cacheIndex = findCacheItemByGUID(lpGuid, rs->isSource); + /*TRACE3("Enumerating %d: %s (%s)\n", cacheIndex, lpstrDescription, lpstrModule);*/ + if (cacheIndex == -1) { + /* add this device */ + if (g_cacheCount < MAX_DS_DEVICES-1) { + g_audioDeviceCache[g_cacheCount].mixerIndex = rs->currMixerIndex; + g_audioDeviceCache[g_cacheCount].isSource = rs->isSource; + g_audioDeviceCache[g_cacheCount].dev = NULL; + g_audioDeviceCache[g_cacheCount].refCount = 0; + if (lpGuid == NULL) { + memset(&(g_audioDeviceCache[g_cacheCount].guid), 0, sizeof(GUID)); + } else { + memcpy(&(g_audioDeviceCache[g_cacheCount].guid), lpGuid, sizeof(GUID)); + } + g_cacheCount++; + rs->currMixerIndex++; + } else { + /* failure case: more than MAX_DS_DEVICES available... */ + } + } else { + /* device already exists in cache... update mixer number */ + g_audioDeviceCache[cacheIndex].mixerIndex = rs->currMixerIndex; + rs->currMixerIndex++; + } + /* continue enumeration */ + return TRUE; +} + +///// implemented functions of DirectAudio.h + +INT32 DAUDIO_GetDirectAudioDeviceCount() { + DS_RefreshCacheStruct rs; + INT32 oldCount; + INT32 cacheIndex; + + if (!DS_lockCache()) { + return 0; + } + + if (g_lastCacheRefreshTime == 0 + || (UINT64) timeGetTime() > (UINT64) (g_lastCacheRefreshTime + WAIT_BETWEEN_CACHE_REFRESH_MILLIS)) { + /* first, initialize any old cache items */ + for (cacheIndex = 0; cacheIndex < g_cacheCount; cacheIndex++) { + g_audioDeviceCache[cacheIndex].mixerIndex = -1; + } + + /* enumerate all devices and either add them to the device cache, + * or refresh the mixer number + */ + rs.currMixerIndex = 0; + rs.isSource = TRUE; + DirectSoundEnumerate((LPDSENUMCALLBACK) DS_RefreshCacheEnum, &rs); + /* if we only got the Primary Sound Driver (GUID=NULL), + * then there aren't any playback devices installed */ + if (rs.currMixerIndex == 1) { + cacheIndex = findCacheItemByGUID(NULL, TRUE); + if (cacheIndex == 0) { + rs.currMixerIndex = 0; + g_audioDeviceCache[0].mixerIndex = -1; + TRACE0("Removing stale Primary Sound Driver from list.\n"); + } + } + oldCount = rs.currMixerIndex; + rs.isSource = FALSE; + DirectSoundCaptureEnumerate((LPDSENUMCALLBACK) DS_RefreshCacheEnum, &rs); + /* if we only got the Primary Sound Capture Driver (GUID=NULL), + * then there aren't any capture devices installed */ + if ((rs.currMixerIndex - oldCount) == 1) { + cacheIndex = findCacheItemByGUID(NULL, FALSE); + if (cacheIndex != -1) { + rs.currMixerIndex = oldCount; + g_audioDeviceCache[cacheIndex].mixerIndex = -1; + TRACE0("Removing stale Primary Sound Capture Driver from list.\n"); + } + } + g_mixerCount = rs.currMixerIndex; + + g_lastCacheRefreshTime = (UINT64) timeGetTime(); + } + DS_unlockCache(); + /*TRACE1("DirectSound: %d installed devices\n", g_mixerCount);*/ + return g_mixerCount; +} + +BOOL CALLBACK DS_GetDescEnum(LPGUID lpGuid, + LPCWSTR lpstrDescription, + LPCWSTR lpstrModule, + DirectAudioDeviceDescription* desc) { + + INT32 cacheIndex = findCacheItemByGUID(lpGuid, g_audioDeviceCache[desc->deviceID].isSource); + if (cacheIndex == desc->deviceID) { + UnicodeToUTF8AndCopy(desc->name, lpstrDescription, DAUDIO_STRING_LENGTH); + //strncpy(desc->description, lpstrModule, DAUDIO_STRING_LENGTH); + desc->maxSimulLines = -1; + /* do not continue enumeration */ + return FALSE; + } + return TRUE; +} + + +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* desc) { + + if (!DS_lockCache()) { + return FALSE; + } + + /* set the deviceID field to the cache index */ + desc->deviceID = findCacheItemByMixerIndex(mixerIndex); + if (desc->deviceID < 0) { + DS_unlockCache(); + return FALSE; + } + desc->maxSimulLines = 0; + if (g_audioDeviceCache[desc->deviceID].isSource) { + DirectSoundEnumerateW((LPDSENUMCALLBACKW) DS_GetDescEnum, desc); + strncpy(desc->description, "DirectSound Playback", DAUDIO_STRING_LENGTH); + } else { + DirectSoundCaptureEnumerateW((LPDSENUMCALLBACKW) DS_GetDescEnum, desc); + strncpy(desc->description, "DirectSound Capture", DAUDIO_STRING_LENGTH); + } + + /*desc->vendor; + desc->version;*/ + + DS_unlockCache(); + return (desc->maxSimulLines == -1)?TRUE:FALSE; +} + +/* multi-channel info: http://www.microsoft.com/whdc/hwdev/tech/audio/multichaud.mspx */ + +//static UINT32 sampleRateArray[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 56000, 88000, 96000, 172000, 192000 }; +static INT32 sampleRateArray[] = { -1 }; +static INT32 channelsArray[] = { 1, 2}; +static INT32 bitsArray[] = { 8, 16}; + +#define SAMPLERATE_COUNT sizeof(sampleRateArray)/sizeof(INT32) +#define CHANNELS_COUNT sizeof(channelsArray)/sizeof(INT32) +#define BITS_COUNT sizeof(bitsArray)/sizeof(INT32) + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { + + int rateIndex, channelIndex, bitIndex; + + /* no need to lock, since deviceID identifies the device sufficiently */ + + /* sanity */ + if (deviceID >= g_cacheCount) { + return; + } + if ((g_audioDeviceCache[deviceID].isSource && !isSource) + || (!g_audioDeviceCache[deviceID].isSource && isSource)) { + /* only support Playback or Capture */ + return; + } + + for (rateIndex = 0; rateIndex < SAMPLERATE_COUNT; rateIndex++) { + for (channelIndex = 0; channelIndex < CHANNELS_COUNT; channelIndex++) { + for (bitIndex = 0; bitIndex < BITS_COUNT; bitIndex++) { + DAUDIO_AddAudioFormat(creator, bitsArray[bitIndex], + ((bitsArray[bitIndex] + 7) / 8) * channelsArray[channelIndex], + channelsArray[channelIndex], + (float) sampleRateArray[rateIndex], + DAUDIO_PCM, + (bitsArray[bitIndex]==8)?FALSE:TRUE, /* signed */ + (bitsArray[bitIndex]==8)?FALSE: +#ifndef _LITTLE_ENDIAN + TRUE /* big endian */ +#else + FALSE /* little endian */ +#endif + ); + } + } + } +} + +typedef struct { + int deviceID; + /* for convenience */ + BOOL isSource; + /* the secondary buffer (Playback) */ + LPDIRECTSOUNDBUFFER playBuffer; + /* the secondary buffer (Capture) */ + LPDIRECTSOUNDCAPTUREBUFFER captureBuffer; + + /* size of the directsound buffer, usually 2 seconds */ + int dsBufferSizeInBytes; + + /* size of the read/write-ahead, as specified by Java */ + int bufferSizeInBytes; + int bitsPerSample; + int frameSize; // storage size in Bytes + + UINT64 framePos; + /* where to write into the buffer. + * -1 if at current position (Playback) + * For Capture, this is the read position + */ + int writePos; + + /* if start() had been called */ + BOOL started; + + /* how many bytes there is silence from current write position */ + int silencedBytes; + + BOOL underrun; + +} DS_Info; + + +LPSTR TranslateDSError(HRESULT hr) { + switch(hr) { + case DSERR_ALLOCATED: + return "DSERR_ALLOCATED"; + + case DSERR_CONTROLUNAVAIL: + return "DSERR_CONTROLUNAVAIL"; + + case DSERR_INVALIDPARAM: + return "DSERR_INVALIDPARAM"; + + case DSERR_INVALIDCALL: + return "DSERR_INVALIDCALL"; + + case DSERR_GENERIC: + return "DSERR_GENERIC"; + + case DSERR_PRIOLEVELNEEDED: + return "DSERR_PRIOLEVELNEEDED"; + + case DSERR_OUTOFMEMORY: + return "DSERR_OUTOFMEMORY"; + + case DSERR_BADFORMAT: + return "DSERR_BADFORMAT"; + + case DSERR_UNSUPPORTED: + return "DSERR_UNSUPPORTED"; + + case DSERR_NODRIVER: + return "DSERR_NODRIVER"; + + case DSERR_ALREADYINITIALIZED: + return "DSERR_ALREADYINITIALIZED"; + + case DSERR_NOAGGREGATION: + return "DSERR_NOAGGREGATION"; + + case DSERR_BUFFERLOST: + return "DSERR_BUFFERLOST"; + + case DSERR_OTHERAPPHASPRIO: + return "DSERR_OTHERAPPHASPRIO"; + + case DSERR_UNINITIALIZED: + return "DSERR_UNINITIALIZED"; + + default: + return "Unknown HRESULT"; + } +} + +/* +** data/routines for starting DS buffers by separate thread +** (joint into DS_StartBufferHelper class) +** see cr6372428: playback fails after exiting from thread that has started it +** due IDirectSoundBuffer8::Play() description: +** http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c +** /directx/htm/idirectsoundbuffer8play.asp +** (remark section): If the application is multithreaded, the thread that plays +** the buffer must continue to exist as long as the buffer is playing. +** Buffers created on WDM drivers stop playing when the thread is terminated. +** IDirectSoundCaptureBuffer8::Start() has the same remark: +** http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c +** /directx/htm/idirectsoundcapturebuffer8start.asp +*/ +class DS_StartBufferHelper { +public: + /* starts DirectSound buffer (playback or capture) */ + static HRESULT StartBuffer(DS_Info* info); + /* checks for initialization success */ + static inline BOOL isInitialized() { return data.threadHandle != NULL; } +protected: + DS_StartBufferHelper() {} // no need to create an instance + + /* data class */ + class Data { + public: + Data(); + ~Data(); + // public data to access from parent class + CRITICAL_SECTION crit_sect; + volatile HANDLE threadHandle; + volatile HANDLE startEvent; + volatile HANDLE startedEvent; + volatile DS_Info* line2Start; + volatile HRESULT startResult; + } static data; + + /* StartThread function */ + static DWORD WINAPI __stdcall ThreadProc(void *param); +}; + +/* StartBufferHelper class implementation +*/ +DS_StartBufferHelper::Data DS_StartBufferHelper::data; + +DS_StartBufferHelper::Data::Data() { + threadHandle = NULL; + ::InitializeCriticalSection(&crit_sect); + startEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + startedEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + if (startEvent != NULL && startedEvent != NULL) + threadHandle = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); +} + +DS_StartBufferHelper::Data::~Data() { + ::EnterCriticalSection(&crit_sect); + if (threadHandle != NULL) { + // terminate thread + line2Start = NULL; + ::SetEvent(startEvent); + ::CloseHandle(threadHandle); + threadHandle = NULL; + } + ::LeaveCriticalSection(&crit_sect); + // won't delete startEvent/startedEvent/crit_sect + // - Windows will do during process shutdown +} + +DWORD WINAPI __stdcall DS_StartBufferHelper::ThreadProc(void *param) +{ + ::CoInitialize(NULL); + while (1) { + // wait for something to do + ::WaitForSingleObject(data.startEvent, INFINITE); + if (data.line2Start == NULL) { + // (data.line2Start == NULL) is a signal to terminate thread + break; + } + if (data.line2Start->isSource) { + data.startResult = + data.line2Start->playBuffer->Play(0, 0, DSBPLAY_LOOPING); + } else { + data.startResult = + data.line2Start->captureBuffer->Start(DSCBSTART_LOOPING); + } + ::SetEvent(data.startedEvent); + } + ::CoUninitialize(); + return 0; +} + +HRESULT DS_StartBufferHelper::StartBuffer(DS_Info* info) { + HRESULT hr; + ::EnterCriticalSection(&data.crit_sect); + if (!isInitialized()) { + ::LeaveCriticalSection(&data.crit_sect); + return E_FAIL; + } + data.line2Start = info; + ::SetEvent(data.startEvent); + ::WaitForSingleObject(data.startedEvent, INFINITE); + hr = data.startResult; + ::LeaveCriticalSection(&data.crit_sect); + return hr; +} + + +/* helper routines for DS buffer positions */ +/* returns distance from pos1 to pos2 + */ +inline int DS_getDistance(DS_Info* info, int pos1, int pos2) { + int distance = pos2 - pos1; + while (distance < 0) + distance += info->dsBufferSizeInBytes; + return distance; +} + +/* adds 2 positions + */ +inline int DS_addPos(DS_Info* info, int pos1, int pos2) { + int result = pos1 + pos2; + while (result >= info->dsBufferSizeInBytes) + result -= info->dsBufferSizeInBytes; + return result; +} + + +BOOL DS_addDeviceRef(INT32 deviceID) { + HWND ownerWindow; + HRESULT res = DS_OK; + LPDIRECTSOUND devPlay; + LPDIRECTSOUNDCAPTURE devCapture; + LPGUID lpGuid = NULL; + + + if (g_audioDeviceCache[deviceID].dev == NULL) { + /* Create DirectSound */ + TRACE1("Creating DirectSound object for device %d\n", deviceID); + lpGuid = &(g_audioDeviceCache[deviceID].guid); + if (isEqualGUID(lpGuid, NULL)) { + lpGuid = NULL; + } + if (g_audioDeviceCache[deviceID].isSource) { + res = DirectSoundCreate(lpGuid, &devPlay, NULL); + g_audioDeviceCache[deviceID].dev = (void*) devPlay; + } else { + res = DirectSoundCaptureCreate(lpGuid, &devCapture, NULL); + g_audioDeviceCache[deviceID].dev = (void*) devCapture; + } + g_audioDeviceCache[deviceID].refCount = 0; + if (FAILED(res)) { + ERROR1("DAUDIO_Open: ERROR: Failed to create DirectSound: %s", TranslateDSError(res)); + g_audioDeviceCache[deviceID].dev = NULL; + return FALSE; + } + if (g_audioDeviceCache[deviceID].isSource) { + ownerWindow = GetForegroundWindow(); + if (ownerWindow == NULL) { + ownerWindow = GetDesktopWindow(); + } + TRACE0("DAUDIO_Open: Setting cooperative level\n"); + res = devPlay->SetCooperativeLevel(ownerWindow, DSSCL_NORMAL); + if (FAILED(res)) { + ERROR1("DAUDIO_Open: ERROR: Failed to set cooperative level: %s", TranslateDSError(res)); + return FALSE; + } + } + } + g_audioDeviceCache[deviceID].refCount++; + return TRUE; +} + +#define DEV_PLAY(devID) ((LPDIRECTSOUND) g_audioDeviceCache[devID].dev) +#define DEV_CAPTURE(devID) ((LPDIRECTSOUNDCAPTURE) g_audioDeviceCache[devID].dev) + +void DS_removeDeviceRef(INT32 deviceID) { + + if (g_audioDeviceCache[deviceID].refCount) { + g_audioDeviceCache[deviceID].refCount--; + } + if (g_audioDeviceCache[deviceID].refCount == 0) { + if (g_audioDeviceCache[deviceID].dev != NULL) { + if (g_audioDeviceCache[deviceID].isSource) { + DEV_PLAY(deviceID)->Release(); + } else { + DEV_CAPTURE(deviceID)->Release(); + } + g_audioDeviceCache[deviceID].dev = NULL; + } + } +} + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) + +#if !defined(DEFINE_WAVEFORMATEX_GUID) +#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 +#endif +#ifndef STATIC_KSDATAFORMAT_SUBTYPE_PCM +#define STATIC_KSDATAFORMAT_SUBTYPE_PCM\ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_PCM) +#endif + + +void createWaveFormat(WAVEFORMATEXTENSIBLE* format, + int sampleRate, + int channels, + int bits, + int significantBits) { + GUID subtypePCM = {STATIC_KSDATAFORMAT_SUBTYPE_PCM}; + format->Format.nSamplesPerSec = (DWORD)sampleRate; + format->Format.nChannels = (WORD) channels; + /* do not support useless padding, like 24-bit samples stored in 32-bit containers */ + format->Format.wBitsPerSample = (WORD) ((bits + 7) & 0xFFF8); + + if (channels <= 2 && bits <= 16) { + format->Format.wFormatTag = WAVE_FORMAT_PCM; + format->Format.cbSize = 0; + } else { + format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + format->Format.cbSize = 22; + format->Samples.wValidBitsPerSample = bits; + /* no way to specify speaker locations */ + format->dwChannelMask = 0xFFFFFFFF; + format->SubFormat = subtypePCM; + } + format->Format.nBlockAlign = (WORD)((format->Format.wBitsPerSample * format->Format.nChannels) / 8); + format->Format.nAvgBytesPerSec = format->Format.nSamplesPerSec * format->Format.nBlockAlign; +} + +/* fill buffer with silence + */ +void DS_clearBuffer(DS_Info* info, BOOL fromWritePos) { + UBYTE* pb1=NULL, *pb2=NULL; + DWORD cb1=0, cb2=0; + DWORD flags = 0; + int start, count; + TRACE1("> DS_clearBuffer for device %d\n", info->deviceID); + if (info->isSource) { + if (fromWritePos) { + DWORD playCursor, writeCursor; + int end; + if (FAILED(info->playBuffer->GetCurrentPosition(&playCursor, &writeCursor))) { + ERROR0(" DS_clearBuffer: ERROR: Failed to get current position."); + TRACE0("< DS_clearbuffer\n"); + return; + } + DEBUG_SILENCING2(" DS_clearBuffer: DS playPos=%d myWritePos=%d", (int) playCursor, (int) info->writePos); + if (info->writePos >= 0) { + start = info->writePos + info->silencedBytes; + } else { + start = writeCursor + info->silencedBytes; + //flags |= DSBLOCK_FROMWRITECURSOR; + } + while (start >= info->dsBufferSizeInBytes) { + start -= info->dsBufferSizeInBytes; + } + + // fix for bug 6251460 (REGRESSION: short sounds do not play) + // for unknown reason with hardware DS buffer playCursor sometimes + // jumps back for little interval (mostly 2-8 bytes) (writeCursor moves forward as usual) + // The issue happens right after start playing and for short sounds only (less then DS buffer, + // when whole sound written into the buffer and remaining space filled by silence) + // the case doesn't produce any audible aftifacts so just catch it to prevent filling + // whole buffer by silence. + if (((int)playCursor <= start && start < (int)writeCursor) + || (writeCursor < playCursor // buffer bound is between playCursor & writeCursor + && (start < (int)writeCursor || (int)playCursor <= start))) { + return; + } + + count = info->dsBufferSizeInBytes - info->silencedBytes; + // why / 4? + //if (count > info->dsBufferSizeInBytes / 4) { + // count = info->dsBufferSizeInBytes / 4; + //} + end = start + count; + if ((int) playCursor < start) { + playCursor += (DWORD) info->dsBufferSizeInBytes; + } + if (start <= (int) playCursor && end > (int) playCursor) { + /* at maximum, silence until play cursor */ + count = (int) playCursor - start; +#ifdef USE_TRACE + if ((int) playCursor >= info->dsBufferSizeInBytes) playCursor -= (DWORD) info->dsBufferSizeInBytes; + TRACE3("\n DS_clearBuffer: Start Writing from %d, " + "would overwrite playCursor=%d, so reduce count to %d\n", + start, playCursor, count); +#endif + } + DEBUG_SILENCING2(" clearing buffer from %d, count=%d. ", (int)start, (int) count); + if (count <= 0) { + DEBUG_SILENCING0("\n"); + TRACE1("< DS_clearBuffer: no need to clear, silencedBytes=%d\n", info->silencedBytes); + return; + } + } else { + start = 0; + count = info->dsBufferSizeInBytes; + flags |= DSBLOCK_ENTIREBUFFER; + } + if (FAILED(info->playBuffer->Lock(start, + count, + (LPVOID*) &pb1, &cb1, + (LPVOID*) &pb2, &cb2, flags))) { + ERROR0("\n DS_clearBuffer: ERROR: Failed to lock sound buffer.\n"); + TRACE0("< DS_clearbuffer\n"); + return; + } + } else { + if (FAILED(info->captureBuffer->Lock(0, + info->dsBufferSizeInBytes, + (LPVOID*) &pb1, &cb1, + (LPVOID*) &pb2, &cb2, DSCBLOCK_ENTIREBUFFER))) { + ERROR0(" DS_clearBuffer: ERROR: Failed to lock sound buffer.\n"); + TRACE0("< DS_clearbuffer\n"); + return; + } + } + if (pb1!=NULL) { + memset(pb1, (info->bitsPerSample == 8)?128:0, cb1); + } + if (pb2!=NULL) { + memset(pb2, (info->bitsPerSample == 8)?128:0, cb2); + } + if (info->isSource) { + info->playBuffer->Unlock( pb1, cb1, pb2, cb2 ); + if (!fromWritePos) { + /* doesn't matter where to start writing next time */ + info->writePos = -1; + info->silencedBytes = info->dsBufferSizeInBytes; + } else { + info->silencedBytes += (cb1+cb2); + if (info->silencedBytes > info->dsBufferSizeInBytes) { + ERROR1(" DS_clearbuffer: ERROR: silencedBytes=%d exceeds buffer size!\n", + info->silencedBytes); + info->silencedBytes = info->dsBufferSizeInBytes; + } + } + DEBUG_SILENCING2(" silencedBytes=%d, my writePos=%d\n", (int)info->silencedBytes, (int)info->writePos); + } else { + info->captureBuffer->Unlock( pb1, cb1, pb2, cb2 ); + } + TRACE0("< DS_clearbuffer\n"); +} + +/* returns pointer to buffer */ +void* DS_createSoundBuffer(DS_Info* info, + float sampleRate, + int sampleSizeInBits, + int channels, + int bufferSizeInBytes) { + DSBUFFERDESC dsbdesc; + DSCBUFFERDESC dscbdesc; + HRESULT res; + WAVEFORMATEXTENSIBLE format; + void* buffer; + + TRACE1("Creating secondary buffer for device %d\n", info->deviceID); + createWaveFormat(&format, + (int) sampleRate, + channels, + info->frameSize / channels * 8, + sampleSizeInBits); + + /* 2 second secondary buffer */ + info->dsBufferSizeInBytes = 2 * ((int) sampleRate) * info->frameSize; + + if (bufferSizeInBytes > info->dsBufferSizeInBytes / 2) { + bufferSizeInBytes = info->dsBufferSizeInBytes / 2; + } + bufferSizeInBytes = (bufferSizeInBytes / info->frameSize) * info->frameSize; + info->bufferSizeInBytes = bufferSizeInBytes; + + if (info->isSource) { + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 + | DSBCAPS_GLOBALFOCUS; + + dsbdesc.dwBufferBytes = info->dsBufferSizeInBytes; + dsbdesc.lpwfxFormat = (WAVEFORMATEX*) &format; + res = DEV_PLAY(info->deviceID)->CreateSoundBuffer + (&dsbdesc, (LPDIRECTSOUNDBUFFER*) &buffer, NULL); + } else { + memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC)); + dscbdesc.dwSize = sizeof(DSCBUFFERDESC); + dscbdesc.dwFlags = 0; + dscbdesc.dwBufferBytes = info->dsBufferSizeInBytes; + dscbdesc.lpwfxFormat = (WAVEFORMATEX*) &format; + res = DEV_CAPTURE(info->deviceID)->CreateCaptureBuffer + (&dscbdesc, (LPDIRECTSOUNDCAPTUREBUFFER*) &buffer, NULL); + } + if (FAILED(res)) { + ERROR1("DS_createSoundBuffer: ERROR: Failed to create sound buffer: %s", TranslateDSError(res)); + return NULL; + } + return buffer; +} + +void DS_destroySoundBuffer(DS_Info* info) { + if (info->playBuffer != NULL) { + info->playBuffer->Release(); + info->playBuffer = NULL; + } + if (info->captureBuffer != NULL) { + info->captureBuffer->Release(); + info->captureBuffer = 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) { + + DS_Info* info; + void* buffer; + + TRACE0("> DAUDIO_Open\n"); + + /* some sanity checks */ + if (deviceID >= g_cacheCount) { + ERROR1("DAUDIO_Open: ERROR: cannot open the device with deviceID=%d!\n", deviceID); + return NULL; + } + if ((g_audioDeviceCache[deviceID].isSource && !isSource) + || (!g_audioDeviceCache[deviceID].isSource && isSource)) { + /* only support Playback or Capture */ + ERROR0("DAUDIO_Open: ERROR: Cache is corrupt: cannot open the device in specified isSource mode!\n"); + return NULL; + } + if (encoding != DAUDIO_PCM) { + ERROR1("DAUDIO_Open: ERROR: cannot open the device with encoding=%d!\n", encoding); + return NULL; + } + if (channels <= 0) { + ERROR1("DAUDIO_Open: ERROR: Invalid number of channels=%d!\n", channels); + return NULL; + } + if (sampleSizeInBits > 8 && +#ifdef _LITTLE_ENDIAN + isBigEndian +#else + !isBigEndian +#endif + ) { + ERROR1("DAUDIO_Open: ERROR: wrong endianness: isBigEndian==%d!\n", isBigEndian); + return NULL; + } + if (sampleSizeInBits == 8 && isSigned) { + ERROR0("DAUDIO_Open: ERROR: wrong signed'ness: with 8 bits, data must be unsigned!\n"); + return NULL; + } + if (!DS_StartBufferHelper::isInitialized()) { + ERROR0("DAUDIO_Open: ERROR: StartBufferHelper initialization was failed!\n"); + return NULL; + } + + info = (DS_Info*) malloc(sizeof(DS_Info)); + if (!info) { + ERROR0("DAUDIO_Open: ERROR: Out of memory\n"); + return NULL; + } + memset(info, 0, sizeof(DS_Info)); + + info->deviceID = deviceID; + info->isSource = isSource; + info->bitsPerSample = sampleSizeInBits; + info->frameSize = frameSize; + info->framePos = 0; + info->started = FALSE; + info->underrun = FALSE; + + if (!DS_addDeviceRef(deviceID)) { + DS_removeDeviceRef(deviceID); + free(info); + return NULL; + } + + buffer = DS_createSoundBuffer(info, + sampleRate, + sampleSizeInBits, + channels, + bufferSizeInBytes); + if (!buffer) { + DS_removeDeviceRef(deviceID); + free(info); + return NULL; + } + + if (info->isSource) { + info->playBuffer = (LPDIRECTSOUNDBUFFER) buffer; + } else { + info->captureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) buffer; + } + DS_clearBuffer(info, FALSE /* entire buffer */); + + /* use writepos of device */ + if (info->isSource) { + info->writePos = -1; + } else { + info->writePos = 0; + } + + TRACE0("< DAUDIO_Open: Opened device successfully.\n"); + return (void*) info; +} + +int DAUDIO_Start(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + HRESULT res = DS_OK; + DWORD status; + + TRACE0("> DAUDIO_Start\n"); + + if (info->isSource) { + res = info->playBuffer->GetStatus(&status); + if (res == DS_OK) { + if (status & DSBSTATUS_LOOPING) { + ERROR0("DAUDIO_Start: ERROR: Already started!"); + return TRUE; + } + + /* only start buffer if already something written to it */ + if (info->writePos >= 0) { + res = DS_StartBufferHelper::StartBuffer(info); + if (res == DSERR_BUFFERLOST) { + res = info->playBuffer->Restore(); + if (res == DS_OK) { + DS_clearBuffer(info, FALSE /* entire buffer */); + /* write() will trigger actual device start */ + } + } else { + /* make sure that we will have silence after + the currently valid audio data */ + DS_clearBuffer(info, TRUE /* from write position */); + } + } + } + } else { + if (info->captureBuffer->GetStatus(&status) == DS_OK) { + if (status & DSCBSTATUS_LOOPING) { + ERROR0("DAUDIO_Start: ERROR: Already started!"); + return TRUE; + } + } + res = DS_StartBufferHelper::StartBuffer(info); + } + if (FAILED(res)) { + ERROR1("DAUDIO_Start: ERROR: Failed to start: %s", TranslateDSError(res)); + return FALSE; + } + info->started = TRUE; + return TRUE; +} + +int DAUDIO_Stop(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + + TRACE0("> DAUDIO_Stop\n"); + + info->started = FALSE; + if (info->isSource) { + info->playBuffer->Stop(); + } else { + info->captureBuffer->Stop(); + } + + TRACE0("< DAUDIO_Stop\n"); + return TRUE; +} + + +void DAUDIO_Close(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + + TRACE0("DAUDIO_Close\n"); + + if (info != NULL) { + DS_destroySoundBuffer(info); + DS_removeDeviceRef(info->deviceID); + free(info); + } +} + +/* Check buffer for underrun + * This method is only meaningful for Output devices (write devices). + */ +void DS_CheckUnderrun(DS_Info* info, DWORD playCursor, DWORD writeCursor) { + TRACE5("DS_CheckUnderrun: playCursor=%d, writeCursor=%d, " + "info->writePos=%d silencedBytes=%d dsBufferSizeInBytes=%d\n", + (int) playCursor, (int) writeCursor, (int) info->writePos, + (int) info->silencedBytes, (int) info->dsBufferSizeInBytes); + if (info->underrun || info->writePos < 0) return; + int writeAhead = DS_getDistance(info, writeCursor, info->writePos); + if (writeAhead > info->bufferSizeInBytes) { + // this may occur after Stop(), when writeCursor decreases (real valid data size > bufferSizeInBytes) + // But the case can occur only when we have more then info->bufferSizeInBytes valid bytes + // (and less then (info->dsBufferSizeInBytes - info->bufferSizeInBytes) silenced bytes) + // If we already have a lot of silencedBytes after valid data (written by + // DAUDIO_StillDraining() or DAUDIO_Service()) then it's underrun + if (info->silencedBytes >= info->dsBufferSizeInBytes - info->bufferSizeInBytes) { + // underrun! + ERROR0("DS_CheckUnderrun: ERROR: underrun detected!\n"); + info->underrun = TRUE; + } + } +} + +/* For source (playback) line: + * (a) if (fromPlayCursor == FALSE), returns number of bytes available + * for writing: bufferSize - (info->writePos - writeCursor); + * (b) if (fromPlayCursor == TRUE), playCursor is used instead writeCursor + * and returned value can be used for play position calculation (see also + * note about bufferSize) + * For destination (capture) line: + * (c) if (fromPlayCursor == FALSE), returns number of bytes available + * for reading from the buffer: readCursor - info->writePos; + * (d) if (fromPlayCursor == TRUE), captureCursor is used instead readCursor + * and returned value can be used for capture position calculation (see + * note about bufferSize) + * bufferSize parameter are filled by "actual" buffer size: + * if (fromPlayCursor == FALSE), bufferSize = info->bufferSizeInBytes + * otherwise it increase by number of bytes currently processed by DirectSound + * (writeCursor - playCursor) or (captureCursor - readCursor) + */ +int DS_GetAvailable(DS_Info* info, + DWORD* playCursor, DWORD* writeCursor, + int* bufferSize, BOOL fromPlayCursor) { + int available; + int newReadPos; + + TRACE2("DS_GetAvailable: fromPlayCursor=%d, deviceID=%d\n", fromPlayCursor, info->deviceID); + if (!info->playBuffer && !info->captureBuffer) { + ERROR0("DS_GetAvailable: ERROR: buffer not yet created"); + return 0; + } + + if (info->isSource) { + if (FAILED(info->playBuffer->GetCurrentPosition(playCursor, writeCursor))) { + ERROR0("DS_GetAvailable: ERROR: Failed to get current position.\n"); + return 0; + } + int processing = DS_getDistance(info, (int)*playCursor, (int)*writeCursor); + // workaround: sometimes DirectSound report writeCursor is less (for several bytes) then playCursor + if (processing > info->dsBufferSizeInBytes / 2) { + *writeCursor = *playCursor; + processing = 0; + } + TRACE3(" playCursor=%d, writeCursor=%d, info->writePos=%d\n", + *playCursor, *writeCursor, info->writePos); + *bufferSize = info->bufferSizeInBytes; + if (fromPlayCursor) { + *bufferSize += processing; + } + DS_CheckUnderrun(info, *playCursor, *writeCursor); + if (info->writePos == -1 || (info->underrun && !fromPlayCursor)) { + /* always full buffer if at beginning */ + available = *bufferSize; + } else { + int currWriteAhead = DS_getDistance(info, fromPlayCursor ? (int)*playCursor : (int)*writeCursor, info->writePos); + if (currWriteAhead > *bufferSize) { + if (info->underrun) { + // playCursor surpassed writePos - no valid data, whole buffer available + available = *bufferSize; + } else { + // the case may occur after stop(), when writeCursor jumps back to playCursor + // so "actual" buffer size has grown + *bufferSize = currWriteAhead; + available = 0; + } + } else { + available = *bufferSize - currWriteAhead; + } + } + } else { + if (FAILED(info->captureBuffer->GetCurrentPosition(playCursor, writeCursor))) { + ERROR0("DS_GetAvailable: ERROR: Failed to get current position.\n"); + return 0; + } + *bufferSize = info->bufferSizeInBytes; + if (fromPlayCursor) { + *bufferSize += DS_getDistance(info, (int)*playCursor, (int)*writeCursor); + } + TRACE4(" captureCursor=%d, readCursor=%d, info->readPos=%d refBufferSize=%d\n", + *playCursor, *writeCursor, info->writePos, *bufferSize); + if (info->writePos == -1) { + /* always empty buffer if at beginning */ + info->writePos = (int) (*writeCursor); + } + if (fromPlayCursor) { + available = ((int) (*playCursor) - info->writePos); + } else { + available = ((int) (*writeCursor) - info->writePos); + } + if (available < 0) { + available += info->dsBufferSizeInBytes; + } + if (!fromPlayCursor && available > info->bufferSizeInBytes) { + /* overflow */ + ERROR2("DS_GetAvailable: ERROR: overflow detected: " + "DirectSoundBufferSize=%d, bufferSize=%d, ", + info->dsBufferSizeInBytes, info->bufferSizeInBytes); + ERROR3("captureCursor=%d, readCursor=%d, info->readPos=%d\n", + *playCursor, *writeCursor, info->writePos); + /* advance read position, to allow exactly one buffer worth of data */ + newReadPos = (int) (*writeCursor) - info->bufferSizeInBytes; + if (newReadPos < 0) { + newReadPos += info->dsBufferSizeInBytes; + } + info->writePos = newReadPos; + available = info->bufferSizeInBytes; + } + } + available = (available / info->frameSize) * info->frameSize; + + TRACE1("DS_available: Returning %d available bytes\n", (int) available); + return available; +} + +// returns -1 on error, otherwise bytes written +int DAUDIO_Write(void* id, char* data, int byteSize) { + DS_Info* info = (DS_Info*) id; + int available; + int thisWritePos; + DWORD playCursor, writeCursor; + HRESULT res; + void* buffer1, *buffer2; + DWORD buffer1len, buffer2len; + BOOL needRestart = FALSE; + int bufferLostTrials = 2; + int bufferSize; + + TRACE1("> DAUDIO_Write %d bytes\n", byteSize); + + while (--bufferLostTrials > 0) { + available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, FALSE /* fromPlayCursor */); + if (byteSize > available) byteSize = available; + if (byteSize == 0) break; + thisWritePos = info->writePos; + if (thisWritePos == -1 || info->underrun) { + // play from current write cursor after flush, etc. + needRestart = TRUE; + thisWritePos = writeCursor; + info->underrun = FALSE; + } + DEBUG_SILENCING2("DAUDIO_Write: writing from %d, count=%d\n", (int) thisWritePos, (int) byteSize); + res = info->playBuffer->Lock(thisWritePos, byteSize, + (LPVOID *) &buffer1, &buffer1len, + (LPVOID *) &buffer2, &buffer2len, + 0); + if (res != DS_OK) { + /* some DS failure */ + if (res == DSERR_BUFFERLOST) { + ERROR0("DAUDIO_write: ERROR: Restoring lost Buffer."); + if (info->playBuffer->Restore() == DS_OK) { + DS_clearBuffer(info, FALSE /* entire buffer */); + info->writePos = -1; + /* try again */ + continue; + } + } + /* can't recover from error */ + byteSize = 0; + break; + } + /* buffer could be locked successfully */ + /* first fill first buffer */ + if (buffer1) { + memcpy(buffer1, data, buffer1len); + data = (char*) (((UINT_PTR) data) + buffer1len); + } else buffer1len = 0; + if (buffer2) { + memcpy(buffer2, data, buffer2len); + } else buffer2len = 0; + byteSize = buffer1len + buffer2len; + + /* update next write pos */ + thisWritePos += byteSize; + while (thisWritePos >= info->dsBufferSizeInBytes) { + thisWritePos -= info->dsBufferSizeInBytes; + } + /* commit data to directsound */ + info->playBuffer->Unlock(buffer1, buffer1len, buffer2, buffer2len); + + info->writePos = thisWritePos; + + /* update position + * must be AFTER updating writePos, + * so that getSvailable doesn't return too little, + * so that getFramePos doesn't jump + */ + info->framePos += (byteSize / info->frameSize); + + /* decrease silenced bytes */ + if (info->silencedBytes > byteSize) { + info->silencedBytes -= byteSize; + } else { + info->silencedBytes = 0; + } + break; + } /* while */ + + /* start the device, if necessary */ + if (info->started && needRestart && (info->writePos >= 0)) { + DS_StartBufferHelper::StartBuffer(info); + } + + TRACE1("< DAUDIO_Write: returning %d bytes.\n", byteSize); + return byteSize; +} + +// returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize) { + DS_Info* info = (DS_Info*) id; + int available; + int thisReadPos; + DWORD captureCursor, readCursor; + HRESULT res; + void* buffer1, *buffer2; + DWORD buffer1len, buffer2len; + int bufferSize; + + TRACE1("> DAUDIO_Read %d bytes\n", byteSize); + + available = DS_GetAvailable(info, &captureCursor, &readCursor, &bufferSize, FALSE /* fromCaptureCursor? */); + if (byteSize > available) byteSize = available; + if (byteSize > 0) { + thisReadPos = info->writePos; + if (thisReadPos == -1) { + /* from beginning */ + thisReadPos = 0; + } + res = info->captureBuffer->Lock(thisReadPos, byteSize, + (LPVOID *) &buffer1, &buffer1len, + (LPVOID *) &buffer2, &buffer2len, + 0); + if (res != DS_OK) { + /* can't recover from error */ + byteSize = 0; + } else { + /* buffer could be locked successfully */ + /* first fill first buffer */ + if (buffer1) { + memcpy(data, buffer1, buffer1len); + data = (char*) (((UINT_PTR) data) + buffer1len); + } else buffer1len = 0; + if (buffer2) { + memcpy(data, buffer2, buffer2len); + } else buffer2len = 0; + byteSize = buffer1len + buffer2len; + + /* update next read pos */ + thisReadPos = DS_addPos(info, thisReadPos, byteSize); + /* commit data to directsound */ + info->captureBuffer->Unlock(buffer1, buffer1len, buffer2, buffer2len); + + /* update position + * must be BEFORE updating readPos, + * so that getAvailable doesn't return too much, + * so that getFramePos doesn't jump + */ + info->framePos += (byteSize / info->frameSize); + + info->writePos = thisReadPos; + } + } + + TRACE1("< DAUDIO_Read: returning %d bytes.\n", byteSize); + return byteSize; +} + + +int DAUDIO_GetBufferSize(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + return info->bufferSizeInBytes; +} + +int DAUDIO_StillDraining(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + BOOL draining = FALSE; + int available, bufferSize; + DWORD playCursor, writeCursor; + + DS_clearBuffer(info, TRUE /* from write position */); + available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, TRUE /* fromPlayCursor */); + draining = (available < bufferSize); + + TRACE3("DAUDIO_StillDraining: available=%d silencedBytes=%d Still draining: %s\n", + available, info->silencedBytes, draining?"TRUE":"FALSE"); + return draining; +} + + +int DAUDIO_Flush(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + + TRACE0("DAUDIO_Flush\n"); + + if (info->isSource) { + info->playBuffer->Stop(); + DS_clearBuffer(info, FALSE /* entire buffer */); + } else { + DWORD captureCursor, readCursor; + /* set the read pointer to the current read position */ + if (FAILED(info->captureBuffer->GetCurrentPosition(&captureCursor, &readCursor))) { + ERROR0("DAUDIO_Flush: ERROR: Failed to get current position."); + return FALSE; + } + DS_clearBuffer(info, FALSE /* entire buffer */); + /* SHOULD set to *captureCursor*, + * but that would be detected as overflow + * in a subsequent GetAvailable() call. + */ + info->writePos = (int) readCursor; + } + return TRUE; +} + +int DAUDIO_GetAvailable(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + DWORD playCursor, writeCursor; + int ret, bufferSize; + + ret = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, /*fromPlayCursor?*/ FALSE); + + TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); + return ret; +} + +INT64 estimatePositionFromAvail(DS_Info* info, INT64 javaBytePos, int bufferSize, 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 (info->isSource) { + // javaBytePos is the position that is reached when the current + // buffer is played completely + return (INT64) (javaBytePos - bufferSize + 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) { + DS_Info* info = (DS_Info*) id; + int available, bufferSize; + DWORD playCursor, writeCursor; + INT64 result = javaBytePos; + + available = DS_GetAvailable(info, &playCursor, &writeCursor, &bufferSize, /*fromPlayCursor?*/ TRUE); + result = estimatePositionFromAvail(info, javaBytePos, bufferSize, available); + 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) { + // need servicing on for SourceDataLines + return isSource?TRUE:FALSE; +} + +void DAUDIO_Service(void* id, int isSource) { + DS_Info* info = (DS_Info*) id; + if (isSource) { + if (info->silencedBytes < info->dsBufferSizeInBytes) { + // clear buffer + TRACE0("DAUDIO_Service\n"); + DS_clearBuffer(info, TRUE /* from write position */); + } + if (info->writePos >= 0 + && info->started + && !info->underrun + && info->silencedBytes >= info->dsBufferSizeInBytes) { + // if we're currently playing, and the entire buffer is silenced... + // then we are underrunning! + info->underrun = TRUE; + ERROR0("DAUDIO_Service: ERROR: DirectSound: underrun detected!\n"); + } + } +} + + +#endif // USE_DAUDIO