8071469: Cleanup include and exclude of sound native libraries
Reviewed-by: amenkov, erikj
--- a/make/lib/SoundLibraries.gmk Fri Mar 23 09:26:59 2018 +0100
+++ b/make/lib/SoundLibraries.gmk Fri Mar 23 09:51:02 2018 +0100
@@ -23,101 +23,50 @@
# questions.
#
-LIBJSOUND_SRC_DIRS := \
+LIBJSOUND_SRC_DIRS := $(wildcard \
$(TOPDIR)/src/java.desktop/share/native/libjsound \
- $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libjsound \
- #
+ $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libjsound \
+ )
+
LIBJSOUND_CFLAGS := \
-I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
$(LIBJAVA_HEADER_FLAGS) \
$(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \
+ -DUSE_PORTS=TRUE \
+ -DUSE_DAUDIO=TRUE \
#
-LIBJSOUND_SRC_FILES := Utilities.c Platform.c
-
-EXTRA_SOUND_JNI_LIBS :=
-
-LIBJSOUND_MIDIFILES := \
- MidiInDevice.c \
- MidiInDeviceProvider.c \
- MidiOutDevice.c \
- MidiOutDeviceProvider.c \
- PlatformMidi.c
-
-# files needed for ports
-LIBJSOUND_PORTFILES := \
- PortMixerProvider.c \
- PortMixer.c
-
-# files needed for direct audio
-LIBJSOUND_DAUDIOFILES := \
- DirectAudioDeviceProvider.c \
- DirectAudioDevice.c
+ifneq ($(OPENJDK_TARGET_OS), solaris)
+ LIBJSOUND_CFLAGS += \
+ -DUSE_PLATFORM_MIDI_OUT=TRUE \
+ -DUSE_PLATFORM_MIDI_IN=TRUE \
+ #
+endif
ifeq ($(OPENJDK_TARGET_OS), windows)
- EXTRA_SOUND_JNI_LIBS += jsoundds
- LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS \
- -DUSE_PLATFORM_MIDI_OUT=TRUE \
- -DUSE_PLATFORM_MIDI_IN=TRUE \
- -DUSE_PORTS=TRUE
- LIBJSOUND_SRC_FILES += \
- PLATFORM_API_WinOS_Charset_Util.cpp \
- PLATFORM_API_WinOS_MidiIn.cpp \
- PLATFORM_API_WinOS_MidiOut.c \
- PLATFORM_API_WinOS_Util.c \
- PLATFORM_API_WinOS_Ports.c
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
-endif # OPENJDK_TARGET_OS windows
+ LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS
+endif
ifeq ($(OPENJDK_TARGET_OS), linux)
- EXTRA_SOUND_JNI_LIBS += jsoundalsa
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_LINUX
-endif # OPENJDK_TARGET_OS linux
+endif
ifeq ($(OPENJDK_TARGET_OS), aix)
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_AIX
-endif # OPENJDK_TARGET_OS aix
+endif
ifeq ($(OPENJDK_TARGET_OS), macosx)
LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX
- LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX \
- -DUSE_PORTS=TRUE \
- -DUSE_DAUDIO=TRUE \
- -DUSE_PLATFORM_MIDI_OUT=TRUE \
- -DUSE_PLATFORM_MIDI_IN=TRUE
- LIBJSOUND_SRC_DIRS += $(TOPDIR)/src/java.desktop/macosx/native/libjsound
- LIBJSOUND_SRC_FILES += \
- PLATFORM_API_MacOSX_Utils.cpp \
- PLATFORM_API_MacOSX_PCM.cpp \
- PLATFORM_API_MacOSX_Ports.cpp \
- PLATFORM_API_MacOSX_MidiIn.c \
- PLATFORM_API_MacOSX_MidiOut.c \
- PLATFORM_API_MacOSX_MidiUtils.c
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES)
-endif # OPENJDK_TARGET_OS macosx
+ LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX
+endif
ifeq ($(OPENJDK_TARGET_OS), solaris)
- LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS \
- -DUSE_PORTS=TRUE \
- -DUSE_DAUDIO=TRUE
- LIBJSOUND_SRC_FILES += \
- PLATFORM_API_SolarisOS_Utils.c \
- PLATFORM_API_SolarisOS_Ports.c \
- PLATFORM_API_SolarisOS_PCM.c
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
- LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES)
-endif # OPENJDK_TARGET_OS solaris
-
-LIBJSOUND_CFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"'
+ LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS
+endif
$(eval $(call SetupJdkLibrary, BUILD_LIBJSOUND, \
NAME := jsound, \
SRC := $(LIBJSOUND_SRC_DIRS), \
- INCLUDE_FILES := $(LIBJSOUND_SRC_FILES), \
TOOLCHAIN := $(LIBJSOUND_TOOLCHAIN), \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) \
@@ -127,10 +76,11 @@
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_unix := -ljava -ljvm, \
+ LIBS_linux := $(ALSA_LIBS), \
LIBS_macosx := -framework CoreAudio -framework CoreFoundation \
- -framework CoreServices -framework AudioUnit $(LIBCXX) \
- -framework CoreMIDI -framework AudioToolbox, \
- LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib winmm.lib, \
+ -framework CoreServices -framework AudioUnit \
+ -framework CoreMIDI -framework AudioToolbox $(LIBCXX), \
+ LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib dsound.lib winmm.lib user32.lib ole32.lib, \
))
$(BUILD_LIBJSOUND): $(call FindLib, java.base, java)
@@ -138,61 +88,3 @@
TARGETS += $(BUILD_LIBJSOUND)
##########################################################################################
-
-ifneq ($(filter jsoundalsa, $(EXTRA_SOUND_JNI_LIBS)), )
-
- $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDALSA, \
- NAME := jsoundalsa, \
- SRC := $(LIBJSOUND_SRC_DIRS), \
- INCLUDE_FILES := Utilities.c $(LIBJSOUND_MIDIFILES) $(LIBJSOUND_PORTFILES) \
- $(LIBJSOUND_DAUDIOFILES) \
- PLATFORM_API_LinuxOS_ALSA_CommonUtils.c \
- PLATFORM_API_LinuxOS_ALSA_PCM.c \
- PLATFORM_API_LinuxOS_ALSA_PCMUtils.c \
- PLATFORM_API_LinuxOS_ALSA_MidiIn.c \
- PLATFORM_API_LinuxOS_ALSA_MidiOut.c \
- PLATFORM_API_LinuxOS_ALSA_MidiUtils.c \
- PLATFORM_API_LinuxOS_ALSA_Ports.c, \
- OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \
- $(LIBJSOUND_CFLAGS) \
- -DUSE_DAUDIO=TRUE \
- -DUSE_PORTS=TRUE \
- -DUSE_PLATFORM_MIDI_OUT=TRUE \
- -DUSE_PLATFORM_MIDI_IN=TRUE, \
- MAPFILE := $(TOPDIR)/make/mapfiles/libjsoundalsa/mapfile-vers, \
- LDFLAGS := $(LDFLAGS_JDKLIB) \
- $(call SET_SHARED_LIBRARY_ORIGIN), \
- LIBS := $(ALSA_LIBS) -ljava -ljvm, \
- ))
-
- $(BUILD_LIBJSOUNDALSA): $(call FindLib, java.base, java)
-
- TARGETS += $(BUILD_LIBJSOUNDALSA)
-
-endif
-
-##########################################################################################
-
-ifneq ($(filter jsoundds, $(EXTRA_SOUND_JNI_LIBS)), )
-
- $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDDS, \
- NAME := jsoundds, \
- SRC := $(LIBJSOUND_SRC_DIRS), \
- INCLUDE_FILES := Utilities.c $(LIBJSOUND_DAUDIOFILES) \
- PLATFORM_API_WinOS_Charset_Util.cpp \
- PLATFORM_API_WinOS_DirectSound.cpp, \
- OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB) \
- $(LIBJSOUND_CFLAGS) \
- -DUSE_DAUDIO=TRUE, \
- LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
- $(call SET_SHARED_LIBRARY_ORIGIN), \
- LIBS := $(JDKLIB_LIBS) dsound.lib winmm.lib user32.lib ole32.lib, \
- ))
-
- $(BUILD_LIBJSOUNDDS): $(call FindLib, java.base, java)
-
- TARGETS += $(BUILD_LIBJSOUNDDS)
-
-endif
--- a/make/mapfiles/libjsound/mapfile-vers Fri Mar 23 09:26:59 2018 +0100
+++ b/make/mapfiles/libjsound/mapfile-vers Fri Mar 23 09:51:02 2018 +0100
@@ -65,8 +65,6 @@
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices;
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor;
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion;
- Java_com_sun_media_sound_Platform_nGetExtraLibraries;
- Java_com_sun_media_sound_Platform_nGetLibraryForFeature;
Java_com_sun_media_sound_Platform_nIsBigEndian;
Java_com_sun_media_sound_PortMixer_nClose;
Java_com_sun_media_sound_PortMixer_nControlGetFloatValue;
--- a/make/mapfiles/libjsoundalsa/mapfile-vers Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# Define library interface.
-
-SUNWprivate_1.1 {
- global:
- Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices;
- Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo;
- Java_com_sun_media_sound_DirectAudioDevice_nAvailable;
- Java_com_sun_media_sound_DirectAudioDevice_nClose;
- Java_com_sun_media_sound_DirectAudioDevice_nFlush;
- Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize;
- Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition;
- Java_com_sun_media_sound_DirectAudioDevice_nGetFormats;
- Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining;
- Java_com_sun_media_sound_DirectAudioDevice_nOpen;
- Java_com_sun_media_sound_DirectAudioDevice_nRead;
- Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing;
- Java_com_sun_media_sound_DirectAudioDevice_nService;
- Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition;
- Java_com_sun_media_sound_DirectAudioDevice_nStart;
- Java_com_sun_media_sound_DirectAudioDevice_nStop;
- Java_com_sun_media_sound_DirectAudioDevice_nWrite;
- Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription;
- Java_com_sun_media_sound_MidiInDeviceProvider_nGetName;
- Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices;
- Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor;
- Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion;
- Java_com_sun_media_sound_MidiInDevice_nClose;
- Java_com_sun_media_sound_MidiInDevice_nGetMessages;
- Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp;
- Java_com_sun_media_sound_MidiInDevice_nOpen;
- Java_com_sun_media_sound_MidiInDevice_nStart;
- Java_com_sun_media_sound_MidiInDevice_nStop;
- Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription;
- Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName;
- Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices;
- Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor;
- Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion;
- Java_com_sun_media_sound_MidiOutDevice_nClose;
- Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp;
- Java_com_sun_media_sound_MidiOutDevice_nOpen;
- Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage;
- Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage;
- Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices;
- Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo;
- Java_com_sun_media_sound_PortMixer_nClose;
- Java_com_sun_media_sound_PortMixer_nControlGetFloatValue;
- Java_com_sun_media_sound_PortMixer_nControlGetIntValue;
- Java_com_sun_media_sound_PortMixer_nControlSetFloatValue;
- Java_com_sun_media_sound_PortMixer_nControlSetIntValue;
- Java_com_sun_media_sound_PortMixer_nGetControls;
- Java_com_sun_media_sound_PortMixer_nGetPortCount;
- Java_com_sun_media_sound_PortMixer_nGetPortName;
- Java_com_sun_media_sound_PortMixer_nGetPortType;
- Java_com_sun_media_sound_PortMixer_nOpen;
- local:
- *;
-};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//#define USE_ERROR
+//#define USE_TRACE
+
+#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
+
+static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) {
+#ifdef USE_ERROR
+ va_list args;
+ va_start(args, fmt);
+ printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err));
+ if (strlen(fmt) > 0) {
+ vprintf(fmt, args);
+ }
+ va_end(args);
+#endif
+}
+
+static int alsa_inited = 0;
+static int alsa_enumerate_pcm_subdevices = FALSE; // default: no
+static int alsa_enumerate_midi_subdevices = FALSE; // default: no
+
+/*
+ * Declare library specific JNI_Onload entry if static build
+ */
+DEF_STATIC_JNI_OnLoad
+
+void initAlsaSupport() {
+ char* enumerate;
+ if (!alsa_inited) {
+ alsa_inited = TRUE;
+ snd_lib_error_set_handler(&alsaDebugOutput);
+
+ enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES);
+ if (enumerate != NULL && strlen(enumerate) > 0
+ && (enumerate[0] != 'f') // false
+ && (enumerate[0] != 'F') // False
+ && (enumerate[0] != 'n') // no
+ && (enumerate[0] != 'N')) { // NO
+ alsa_enumerate_pcm_subdevices = TRUE;
+ }
+#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES
+ alsa_enumerate_midi_subdevices = TRUE;
+#endif
+ }
+}
+
+
+/* if true (non-zero), ALSA sub devices should be listed as separate devices
+ */
+int needEnumerateSubdevices(int isMidi) {
+ initAlsaSupport();
+ return isMidi ? alsa_enumerate_midi_subdevices
+ : alsa_enumerate_pcm_subdevices;
+}
+
+
+/*
+ * deviceID contains packed card, device and subdevice numbers
+ * each number takes 10 bits
+ * "default" device has id == ALSA_DEFAULT_DEVICE_ID
+ */
+UINT32 encodeDeviceID(int card, int device, int subdevice) {
+ return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10)
+ | (subdevice & 0x3FF)) + 1;
+}
+
+
+void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
+ int isMidi) {
+ deviceID--;
+ *card = (deviceID >> 20) & 0x3FF;
+ *device = (deviceID >> 10) & 0x3FF;
+ if (needEnumerateSubdevices(isMidi)) {
+ *subdevice = deviceID & 0x3FF;
+ } else {
+ *subdevice = -1; // ALSA will choose any subdevices
+ }
+}
+
+
+void getDeviceString(char* buffer, int card, int device, int subdevice,
+ int usePlugHw, int isMidi) {
+ if (needEnumerateSubdevices(isMidi)) {
+ sprintf(buffer, "%s:%d,%d,%d",
+ usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
+ card, device, subdevice);
+ } else {
+ sprintf(buffer, "%s:%d,%d",
+ usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
+ card, device);
+ }
+}
+
+
+void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
+ int usePlugHw, int isMidi) {
+ int card, device, subdevice;
+
+ if (deviceID == ALSA_DEFAULT_DEVICE_ID) {
+ strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME);
+ } else {
+ decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi);
+ getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi);
+ }
+}
+
+
+static int hasGottenALSAVersion = FALSE;
+#define ALSAVersionString_LENGTH 200
+static char ALSAVersionString[ALSAVersionString_LENGTH];
+
+void getALSAVersion(char* buffer, int len) {
+ if (!hasGottenALSAVersion) {
+ // get alsa version from proc interface
+ FILE* file;
+ int curr, len, totalLen, inVersionString;
+ file = fopen(ALSA_VERSION_PROC_FILE, "r");
+ ALSAVersionString[0] = 0;
+ if (file) {
+ if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) {
+ // parse for version number
+ totalLen = strlen(ALSAVersionString);
+ inVersionString = FALSE;
+ len = 0;
+ curr = 0;
+ while (curr < totalLen) {
+ if (!inVersionString) {
+ // is this char the beginning of a version string ?
+ if (ALSAVersionString[curr] >= '0'
+ && ALSAVersionString[curr] <= '9') {
+ inVersionString = TRUE;
+ }
+ }
+ if (inVersionString) {
+ // the version string ends with white space
+ if (ALSAVersionString[curr] <= 32) {
+ break;
+ }
+ if (curr != len) {
+ // copy this char to the beginning of the string
+ ALSAVersionString[len] = ALSAVersionString[curr];
+ }
+ len++;
+ }
+ curr++;
+ }
+ // remove trailing dots
+ while ((len > 0) && (ALSAVersionString[len - 1] == '.')) {
+ len--;
+ }
+ // null terminate
+ ALSAVersionString[len] = 0;
+ }
+ fclose(file);
+ hasGottenALSAVersion = TRUE;
+ }
+ }
+ strncpy(buffer, ALSAVersionString, len);
+}
+
+
+/* end */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <alsa/asoundlib.h>
+#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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#if USE_PLATFORM_MIDI_IN == TRUE
+
+
+#include <alsa/asoundlib.h>
+#include "PlatformMidi.h"
+#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h"
+#if defined(i586)
+#include <sys/utsname.h>
+#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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#if USE_PLATFORM_MIDI_OUT == TRUE
+
+#include <alsa/asoundlib.h>
+#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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h"
+#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
+#include <string.h>
+#include <sys/time.h>
+
+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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <alsa/asoundlib.h>
+#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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,941 @@
+/*
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_LinuxOS_ALSA_PCMUtils.h"
+#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
+#include "DirectAudio.h"
+
+#if USE_DAUDIO == TRUE
+
+// GetPosition method 1: based on how many bytes are passed to the kernel driver
+// + does not need much processor resources
+// - not very exact, "jumps"
+// GetPosition method 2: ask kernel about actual position of playback.
+// - very exact
+// - switch to kernel layer for each call
+// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA
+// quick tests on a Pentium 200MMX showed max. 1.5% processor usage
+// for playing back a CD-quality file and printing 20x per second a line
+// on the console with the current time. So I guess performance is not such a
+// factor here.
+//#define GET_POSITION_METHOD1
+#define GET_POSITION_METHOD2
+
+
+// The default time for a period in microseconds.
+// For very small buffers, only 2 periods are used.
+#define DEFAULT_PERIOD_TIME 20000 /* 20ms */
+
+///// implemented functions of DirectAudio.h
+
+INT32 DAUDIO_GetDirectAudioDeviceCount() {
+ return (INT32) getAudioDeviceCount();
+}
+
+
+INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) {
+ ALSA_AudioDeviceDescription adesc;
+
+ adesc.index = (int) mixerIndex;
+ adesc.strLen = DAUDIO_STRING_LENGTH;
+
+ adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines));
+ adesc.deviceID = &(description->deviceID);
+ adesc.name = description->name;
+ adesc.vendor = description->vendor;
+ adesc.description = description->description;
+ adesc.version = description->version;
+
+ return getAudioDeviceDescriptionByIndex(&adesc);
+}
+
+#define MAX_BIT_INDEX 6
+// returns
+// 6: for anything above 24-bit
+// 5: for 4 bytes sample size, 24-bit
+// 4: for 3 bytes sample size, 24-bit
+// 3: for 3 bytes sample size, 20-bit
+// 2: for 2 bytes sample size, 16-bit
+// 1: for 1 byte sample size, 8-bit
+// 0: for anything else
+int getBitIndex(int sampleSizeInBytes, int significantBits) {
+ if (significantBits > 24) return 6;
+ if (sampleSizeInBytes == 4 && significantBits == 24) return 5;
+ if (sampleSizeInBytes == 3) {
+ if (significantBits == 24) return 4;
+ if (significantBits == 20) return 3;
+ }
+ if (sampleSizeInBytes == 2 && significantBits == 16) return 2;
+ if (sampleSizeInBytes == 1 && significantBits == 8) return 1;
+ return 0;
+}
+
+int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) {
+ switch(bitIndex) {
+ case 1: return 1;
+ case 2: return 2;
+ case 3: /* fall through */
+ case 4: return 3;
+ case 5: return 4;
+ }
+ return sampleSizeInBytes;
+}
+
+int getSignificantBits(int bitIndex, int significantBits) {
+ switch(bitIndex) {
+ case 1: return 8;
+ case 2: return 16;
+ case 3: return 20;
+ case 4: /* fall through */
+ case 5: return 24;
+ }
+ return significantBits;
+}
+
+void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
+ snd_pcm_t* handle;
+ snd_pcm_format_mask_t* formatMask;
+ snd_pcm_format_t format;
+ snd_pcm_hw_params_t* hwParams;
+ int handledBits[MAX_BIT_INDEX+1];
+
+ int ret;
+ int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc;
+ int origSampleSizeInBytes, origSignificantBits;
+ unsigned int channels, minChannels, maxChannels;
+ int rate, bitIndex;
+
+ for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE;
+ if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) {
+ return;
+ }
+ ret = snd_pcm_format_mask_malloc(&formatMask);
+ if (ret != 0) {
+ ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret);
+ } else {
+ ret = snd_pcm_hw_params_malloc(&hwParams);
+ if (ret != 0) {
+ ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
+ } else {
+ ret = snd_pcm_hw_params_any(handle, hwParams);
+ /* snd_pcm_hw_params_any can return a positive value on success too */
+ if (ret < 0) {
+ ERROR1("snd_pcm_hw_params_any returned error %d\n", ret);
+ } else {
+ /* for the logic following this code, set ret to 0 to indicate success */
+ ret = 0;
+ }
+ }
+ snd_pcm_hw_params_get_format_mask(hwParams, formatMask);
+ if (ret == 0) {
+ ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels);
+ if (ret != 0) {
+ ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret);
+ }
+ }
+ if (ret == 0) {
+ ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels);
+ if (ret != 0) {
+ ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret);
+ }
+ }
+
+ // since we queried the hw: device, for many soundcards, it will only
+ // report the maximum number of channels (which is the only way to talk
+ // to the hw: device). Since we will, however, open the plughw: device
+ // when opening the Source/TargetDataLine, we can safely assume that
+ // also the channels 1..maxChannels are available.
+#ifdef ALSA_PCM_USE_PLUGHW
+ minChannels = 1;
+#endif
+ if (ret == 0) {
+ // plughw: supports any sample rate
+ rate = -1;
+ for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
+ if (snd_pcm_format_mask_test(formatMask, format)) {
+ // format exists
+ if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes,
+ &origSignificantBits,
+ &isSigned, &isBigEndian, &enc)) {
+ // now if we use plughw:, we can use any bit size below the
+ // natively supported ones. Some ALSA drivers only support the maximum
+ // bit size, so we add any sample rates below the reported one.
+ // E.g. this iteration reports support for 16-bit.
+ // getBitIndex will return 2, so it will add entries for
+ // 16-bit (bitIndex=2) and in the next do-while loop iteration,
+ // it will decrease bitIndex and will therefore add 8-bit support.
+ bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits);
+ do {
+ if (bitIndex == 0
+ || bitIndex == MAX_BIT_INDEX
+ || !handledBits[bitIndex]) {
+ handledBits[bitIndex] = TRUE;
+ sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes);
+ significantBits = getSignificantBits(bitIndex, origSignificantBits);
+ if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) {
+ // avoid too many channels explicitly listed
+ // just add -1, min, and max
+ DAUDIO_AddAudioFormat(creator, significantBits,
+ -1, -1, rate,
+ enc, isSigned, isBigEndian);
+ DAUDIO_AddAudioFormat(creator, significantBits,
+ sampleSizeInBytes * minChannels,
+ minChannels, rate,
+ enc, isSigned, isBigEndian);
+ DAUDIO_AddAudioFormat(creator, significantBits,
+ sampleSizeInBytes * maxChannels,
+ maxChannels, rate,
+ enc, isSigned, isBigEndian);
+ } else {
+ for (channels = minChannels; channels <= maxChannels; channels++) {
+ DAUDIO_AddAudioFormat(creator, significantBits,
+ sampleSizeInBytes * channels,
+ channels, rate,
+ enc, isSigned, isBigEndian);
+ }
+ }
+ }
+#ifndef ALSA_PCM_USE_PLUGHW
+ // without plugin, do not add fake formats
+ break;
+#endif
+ } while (--bitIndex > 0);
+ } else {
+ TRACE1("could not get format from alsa for format %d\n", format);
+ }
+ } else {
+ //TRACE1("Format %d not supported\n", format);
+ }
+ } // for loop
+ snd_pcm_hw_params_free(hwParams);
+ }
+ snd_pcm_format_mask_free(formatMask);
+ }
+ snd_pcm_close(handle);
+}
+
+/** Workaround for cr 7033899, 7030629:
+ * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty
+ * (just opened, underruned or already flushed).
+ * Sometimes it causes PCM falls to -EBADFD error,
+ * sometimes causes bufferSize change.
+ * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used.
+ */
+/* ******* ALSA PCM INFO ******************** */
+typedef struct tag_AlsaPcmInfo {
+ snd_pcm_t* handle;
+ snd_pcm_hw_params_t* hwParams;
+ snd_pcm_sw_params_t* swParams;
+ int bufferSizeInBytes;
+ int frameSize; // storage size in Bytes
+ unsigned int periods;
+ snd_pcm_uframes_t periodSize;
+ short int isRunning; // see comment above
+ short int isFlushed; // see comment above
+#ifdef GET_POSITION_METHOD2
+ // to be used exclusively by getBytePosition!
+ snd_pcm_status_t* positionStatus;
+#endif
+} AlsaPcmInfo;
+
+
+int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) {
+ int ret;
+ int threshold;
+
+ if (useThreshold) {
+ // start device whenever anything is written to the buffer
+ threshold = 1;
+ } else {
+ // never start the device automatically
+ threshold = 2000000000; /* near UINT_MAX */
+ }
+ ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold);
+ if (ret < 0) {
+ ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int setStartThreshold(AlsaPcmInfo* info, int useThreshold) {
+ int ret = 0;
+
+ if (!setStartThresholdNoCommit(info, useThreshold)) {
+ ret = -1;
+ }
+ if (ret == 0) {
+ // commit it
+ ret = snd_pcm_sw_params(info->handle, info->swParams);
+ if (ret < 0) {
+ ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
+ }
+ }
+ return (ret == 0)?TRUE:FALSE;
+}
+
+
+// returns TRUE if successful
+int setHWParams(AlsaPcmInfo* info,
+ float sampleRate,
+ int channels,
+ int bufferSizeInFrames,
+ snd_pcm_format_t format) {
+ unsigned int rrate, periodTime, periods;
+ int ret, dir;
+ snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;
+
+ /* choose all parameters */
+ ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
+ if (ret < 0) {
+ ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ /* set the interleaved read/write format */
+ ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (ret < 0) {
+ ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ /* set the sample format */
+ ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
+ if (ret < 0) {
+ ERROR1("Sample format not available: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ /* set the count of channels */
+ ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
+ if (ret < 0) {
+ ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
+ return FALSE;
+ }
+ /* set the stream rate */
+ rrate = (int) (sampleRate + 0.5f);
+ dir = 0;
+ ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
+ if (ret < 0) {
+ ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
+ return FALSE;
+ }
+ if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
+ ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
+ return FALSE;
+ }
+ /* set the buffer time */
+ ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
+ if (ret < 0) {
+ ERROR2("Unable to set buffer size to %d frames: %s\n",
+ (int) alsaBufferSizeInFrames, snd_strerror(ret));
+ return FALSE;
+ }
+ bufferSizeInFrames = (int) alsaBufferSizeInFrames;
+ /* set the period time */
+ if (bufferSizeInFrames > 1024) {
+ dir = 0;
+ periodTime = DEFAULT_PERIOD_TIME;
+ ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
+ if (ret < 0) {
+ ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
+ return FALSE;
+ }
+ } else {
+ /* set the period count for very small buffer sizes to 2 */
+ dir = 0;
+ periods = 2;
+ ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
+ if (ret < 0) {
+ ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
+ return FALSE;
+ }
+ }
+ /* write the parameters to device */
+ ret = snd_pcm_hw_params(info->handle, info->hwParams);
+ if (ret < 0) {
+ ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// returns 1 if successful
+int setSWParams(AlsaPcmInfo* info) {
+ int ret;
+
+ /* get the current swparams */
+ ret = snd_pcm_sw_params_current(info->handle, info->swParams);
+ if (ret < 0) {
+ ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ /* never start the transfer automatically */
+ if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
+ return FALSE;
+ }
+
+ /* allow the transfer when at least period_size samples can be processed */
+ ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
+ if (ret < 0) {
+ ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ /* write the parameters to the playback device */
+ ret = snd_pcm_sw_params(info->handle, info->swParams);
+ if (ret < 0) {
+ ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static snd_output_t* ALSA_OUTPUT = NULL;
+
+void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
+ int encoding, float sampleRate, int sampleSizeInBits,
+ int frameSize, int channels,
+ int isSigned, int isBigEndian, int bufferSizeInBytes) {
+ snd_pcm_format_mask_t* formatMask;
+ snd_pcm_format_t format;
+ int dir;
+ int ret = 0;
+ AlsaPcmInfo* info = NULL;
+ /* snd_pcm_uframes_t is 64 bit on 64-bit systems */
+ snd_pcm_uframes_t alsaBufferSizeInFrames = 0;
+
+
+ TRACE0("> DAUDIO_Open\n");
+#ifdef USE_TRACE
+ // for using ALSA debug dump methods
+ if (ALSA_OUTPUT == NULL) {
+ snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0);
+ }
+#endif
+ if (channels <= 0) {
+ ERROR1("ERROR: Invalid number of channels=%d!\n", channels);
+ return NULL;
+ }
+ info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo));
+ if (!info) {
+ ERROR0("Out of memory\n");
+ return NULL;
+ }
+ memset(info, 0, sizeof(AlsaPcmInfo));
+ // initial values are: stopped, flushed
+ info->isRunning = 0;
+ info->isFlushed = 1;
+
+ ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
+ if (ret == 0) {
+ // set to blocking mode
+ snd_pcm_nonblock(info->handle, 0);
+ ret = snd_pcm_hw_params_malloc(&(info->hwParams));
+ if (ret != 0) {
+ ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret);
+ } else {
+ ret = -1;
+ if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits,
+ isSigned, isBigEndian, encoding)) {
+ if (setHWParams(info,
+ sampleRate,
+ channels,
+ bufferSizeInBytes / frameSize,
+ format)) {
+ info->frameSize = frameSize;
+ ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir);
+ if (ret < 0) {
+ ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret));
+ }
+ snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir);
+ snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames);
+ info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize;
+ TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n",
+ (int) info->periodSize, info->periods, info->bufferSizeInBytes);
+ }
+ }
+ }
+ if (ret == 0) {
+ // set software parameters
+ ret = snd_pcm_sw_params_malloc(&(info->swParams));
+ if (ret != 0) {
+ ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
+ } else {
+ if (!setSWParams(info)) {
+ ret = -1;
+ }
+ }
+ }
+ if (ret == 0) {
+ // prepare device
+ ret = snd_pcm_prepare(info->handle);
+ if (ret < 0) {
+ ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
+ }
+ }
+
+#ifdef GET_POSITION_METHOD2
+ if (ret == 0) {
+ ret = snd_pcm_status_malloc(&(info->positionStatus));
+ if (ret != 0) {
+ ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret));
+ }
+ }
+#endif
+ }
+ if (ret != 0) {
+ DAUDIO_Close((void*) info, isSource);
+ info = NULL;
+ } else {
+ // set to non-blocking mode
+ snd_pcm_nonblock(info->handle, 1);
+ TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n",
+ (void*) info->handle);
+ }
+ return (void*) info;
+}
+
+#ifdef USE_TRACE
+void printState(snd_pcm_state_t state) {
+ if (state == SND_PCM_STATE_OPEN) {
+ TRACE0("State: SND_PCM_STATE_OPEN\n");
+ }
+ else if (state == SND_PCM_STATE_SETUP) {
+ TRACE0("State: SND_PCM_STATE_SETUP\n");
+ }
+ else if (state == SND_PCM_STATE_PREPARED) {
+ TRACE0("State: SND_PCM_STATE_PREPARED\n");
+ }
+ else if (state == SND_PCM_STATE_RUNNING) {
+ TRACE0("State: SND_PCM_STATE_RUNNING\n");
+ }
+ else if (state == SND_PCM_STATE_XRUN) {
+ TRACE0("State: SND_PCM_STATE_XRUN\n");
+ }
+ else if (state == SND_PCM_STATE_DRAINING) {
+ TRACE0("State: SND_PCM_STATE_DRAINING\n");
+ }
+ else if (state == SND_PCM_STATE_PAUSED) {
+ TRACE0("State: SND_PCM_STATE_PAUSED\n");
+ }
+ else if (state == SND_PCM_STATE_SUSPENDED) {
+ TRACE0("State: SND_PCM_STATE_SUSPENDED\n");
+ }
+}
+#endif
+
+int DAUDIO_Start(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret;
+ snd_pcm_state_t state;
+
+ TRACE0("> DAUDIO_Start\n");
+ // set to blocking mode
+ snd_pcm_nonblock(info->handle, 0);
+ // set start mode so that it always starts as soon as data is there
+ setStartThreshold(info, TRUE /* use threshold */);
+ state = snd_pcm_state(info->handle);
+ if (state == SND_PCM_STATE_PAUSED) {
+ // in case it was stopped previously
+ TRACE0(" Un-pausing...\n");
+ ret = snd_pcm_pause(info->handle, FALSE);
+ if (ret != 0) {
+ ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret));
+ }
+ }
+ if (state == SND_PCM_STATE_SUSPENDED) {
+ TRACE0(" Resuming...\n");
+ ret = snd_pcm_resume(info->handle);
+ if (ret < 0) {
+ if ((ret != -EAGAIN) && (ret != -ENOSYS)) {
+ ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret));
+ }
+ }
+ }
+ if (state == SND_PCM_STATE_SETUP) {
+ TRACE0("need to call prepare again...\n");
+ // prepare device
+ ret = snd_pcm_prepare(info->handle);
+ if (ret < 0) {
+ ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
+ }
+ }
+ // in case there is still data in the buffers
+ ret = snd_pcm_start(info->handle);
+ if (ret != 0) {
+ if (ret != -EPIPE) {
+ ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret));
+ }
+ }
+ // set to non-blocking mode
+ ret = snd_pcm_nonblock(info->handle, 1);
+ if (ret != 0) {
+ ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret));
+ }
+ state = snd_pcm_state(info->handle);
+#ifdef USE_TRACE
+ printState(state);
+#endif
+ ret = (state == SND_PCM_STATE_PREPARED)
+ || (state == SND_PCM_STATE_RUNNING)
+ || (state == SND_PCM_STATE_XRUN)
+ || (state == SND_PCM_STATE_SUSPENDED);
+ if (ret) {
+ info->isRunning = 1;
+ // source line should keep isFlushed value until Write() is called;
+ // for target data line reset it right now.
+ if (!isSource) {
+ info->isFlushed = 0;
+ }
+ }
+ TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
+ return ret?TRUE:FALSE;
+}
+
+int DAUDIO_Stop(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret;
+
+ TRACE0("> DAUDIO_Stop\n");
+ // set to blocking mode
+ snd_pcm_nonblock(info->handle, 0);
+ setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun
+ ret = snd_pcm_pause(info->handle, 1);
+ // set to non-blocking mode
+ snd_pcm_nonblock(info->handle, 1);
+ if (ret != 0) {
+ ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+ info->isRunning = 0;
+ TRACE0("< DAUDIO_Stop success\n");
+ return TRUE;
+}
+
+void DAUDIO_Close(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+
+ TRACE0("DAUDIO_Close\n");
+ if (info != NULL) {
+ if (info->handle != NULL) {
+ snd_pcm_close(info->handle);
+ }
+ if (info->hwParams) {
+ snd_pcm_hw_params_free(info->hwParams);
+ }
+ if (info->swParams) {
+ snd_pcm_sw_params_free(info->swParams);
+ }
+#ifdef GET_POSITION_METHOD2
+ if (info->positionStatus) {
+ snd_pcm_status_free(info->positionStatus);
+ }
+#endif
+ free(info);
+ }
+}
+
+/*
+ * Underrun and suspend recovery
+ * returns
+ * 0: exit native and return 0
+ * 1: try again to write/read
+ * -1: error - exit native with return value -1
+ */
+int xrun_recovery(AlsaPcmInfo* info, int err) {
+ int ret;
+
+ if (err == -EPIPE) { /* underrun / overflow */
+ TRACE0("xrun_recovery: underrun/overflow.\n");
+ ret = snd_pcm_prepare(info->handle);
+ if (ret < 0) {
+ ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
+ return -1;
+ }
+ return 1;
+ } else if (err == -ESTRPIPE) {
+ TRACE0("xrun_recovery: suspended.\n");
+ ret = snd_pcm_resume(info->handle);
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+ return 0; /* wait until the suspend flag is released */
+ }
+ return -1;
+ }
+ ret = snd_pcm_prepare(info->handle);
+ if (ret < 0) {
+ ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
+ return -1;
+ }
+ return 1;
+ } else if (err == -EAGAIN) {
+ TRACE0("xrun_recovery: EAGAIN try again flag.\n");
+ return 0;
+ }
+
+ TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
+ return -1;
+}
+
+// returns -1 on error
+int DAUDIO_Write(void* id, char* data, int byteSize) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret, count;
+ snd_pcm_sframes_t frameSize, writtenFrames;
+
+ TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
+
+ /* sanity */
+ if (byteSize <= 0 || info->frameSize <= 0) {
+ ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n",
+ (int) byteSize, (int) info->frameSize);
+ TRACE0("< DAUDIO_Write returning -1\n");
+ return -1;
+ }
+
+ count = 2; // maximum number of trials to recover from underrun
+ //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
+ frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
+ do {
+ writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize);
+
+ if (writtenFrames < 0) {
+ ret = xrun_recovery(info, (int) writtenFrames);
+ if (ret <= 0) {
+ TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret);
+ return ret;
+ }
+ if (count-- <= 0) {
+ ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n");
+ return -1;
+ }
+ } else {
+ break;
+ }
+ } while (TRUE);
+ //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames);
+
+ if (writtenFrames > 0) {
+ // reset "flushed" flag
+ info->isFlushed = 0;
+ }
+
+ ret = (int) (writtenFrames * info->frameSize);
+ TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
+ return ret;
+}
+
+// returns -1 on error
+int DAUDIO_Read(void* id, char* data, int byteSize) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret, count;
+ snd_pcm_sframes_t frameSize, readFrames;
+
+ TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
+ /*TRACE3(" info=%p, data=%p, byteSize=%d\n",
+ (void*) info, (void*) data, (int) byteSize);
+ TRACE2(" info->frameSize=%d, info->handle=%p\n",
+ (int) info->frameSize, (void*) info->handle);
+ */
+ /* sanity */
+ if (byteSize <= 0 || info->frameSize <= 0) {
+ ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n",
+ (int) byteSize, (int) info->frameSize);
+ TRACE0("< DAUDIO_Read returning -1\n");
+ return -1;
+ }
+ if (!info->isRunning && info->isFlushed) {
+ // PCM has nothing to read
+ return 0;
+ }
+
+ count = 2; // maximum number of trials to recover from error
+ //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
+ frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
+ do {
+ readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize);
+ if (readFrames < 0) {
+ ret = xrun_recovery(info, (int) readFrames);
+ if (ret <= 0) {
+ TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret);
+ return ret;
+ }
+ if (count-- <= 0) {
+ ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n");
+ return -1;
+ }
+ } else {
+ break;
+ }
+ } while (TRUE);
+ //ret = snd_pcm_frames_to_bytes(info->handle, readFrames);
+ ret = (int) (readFrames * info->frameSize);
+ TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
+ return ret;
+}
+
+
+int DAUDIO_GetBufferSize(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+
+ return info->bufferSizeInBytes;
+}
+
+int DAUDIO_StillDraining(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ snd_pcm_state_t state;
+
+ state = snd_pcm_state(info->handle);
+ //printState(state);
+ //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE");
+ return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE;
+}
+
+
+int DAUDIO_Flush(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret;
+
+ TRACE0("DAUDIO_Flush\n");
+
+ if (info->isFlushed) {
+ // nothing to drop
+ return 1;
+ }
+
+ ret = snd_pcm_drop(info->handle);
+ if (ret != 0) {
+ ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
+ return FALSE;
+ }
+
+ info->isFlushed = 1;
+ if (info->isRunning) {
+ ret = DAUDIO_Start(id, isSource);
+ }
+ return ret;
+}
+
+int DAUDIO_GetAvailable(void* id, int isSource) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ snd_pcm_sframes_t availableInFrames;
+ snd_pcm_state_t state;
+ int ret;
+
+ state = snd_pcm_state(info->handle);
+ if (info->isFlushed || state == SND_PCM_STATE_XRUN) {
+ // if in xrun state then we have the entire buffer available,
+ // not 0 as alsa reports
+ ret = info->bufferSizeInBytes;
+ } else {
+ availableInFrames = snd_pcm_avail_update(info->handle);
+ if (availableInFrames < 0) {
+ ret = 0;
+ } else {
+ //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames);
+ ret = (int) (availableInFrames * info->frameSize);
+ }
+ }
+ TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
+ return ret;
+}
+
+INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) {
+ // estimate the current position with the buffer size and
+ // the available bytes to read or write in the buffer.
+ // not an elegant solution - bytePos will stop on xruns,
+ // and in race conditions it may jump backwards
+ // Advantage is that it is indeed based on the samples that go through
+ // the system (rather than time-based methods)
+ if (isSource) {
+ // javaBytePos is the position that is reached when the current
+ // buffer is played completely
+ return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes);
+ } else {
+ // javaBytePos is the position that was when the current buffer was empty
+ return (INT64) (javaBytePos + availInBytes);
+ }
+}
+
+INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+ AlsaPcmInfo* info = (AlsaPcmInfo*) id;
+ int ret;
+ INT64 result = javaBytePos;
+ snd_pcm_state_t state;
+ state = snd_pcm_state(info->handle);
+
+ if (!info->isFlushed && state != SND_PCM_STATE_XRUN) {
+#ifdef GET_POSITION_METHOD2
+ snd_timestamp_t* ts;
+ snd_pcm_uframes_t framesAvail;
+
+ // note: slight race condition if this is called simultaneously from 2 threads
+ ret = snd_pcm_status(info->handle, info->positionStatus);
+ if (ret != 0) {
+ ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret));
+ result = javaBytePos;
+ } else {
+ // calculate from time value, or from available bytes
+ framesAvail = snd_pcm_status_get_avail(info->positionStatus);
+ result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
+ }
+#endif
+#ifdef GET_POSITION_METHOD3
+ snd_pcm_uframes_t framesAvail;
+ ret = snd_pcm_avail(info->handle, &framesAvail);
+ if (ret != 0) {
+ ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret));
+ result = javaBytePos;
+ } else {
+ result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
+ }
+#endif
+#ifdef GET_POSITION_METHOD1
+ result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource));
+#endif
+ }
+ //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
+ return result;
+}
+
+
+
+void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+ /* save to ignore, since GetBytePosition
+ * takes the javaBytePos param into account
+ */
+}
+
+int DAUDIO_RequiresServicing(void* id, int isSource) {
+ // never need servicing on Linux
+ return FALSE;
+}
+
+void DAUDIO_Service(void* id, int isSource) {
+ // never need servicing on Linux
+}
+
+
+#endif // USE_DAUDIO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//#define USE_ERROR
+//#define USE_TRACE
+
+#include "PLATFORM_API_LinuxOS_ALSA_PCMUtils.h"
+#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
+
+
+
+// callback for iteration through devices
+// returns TRUE if iteration should continue
+// NOTE: cardinfo may be NULL (for "default" device)
+typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo,
+ snd_ctl_card_info_t* cardinfo, void *userData);
+
+// for each ALSA device, call iterator. userData is passed to the iterator
+// returns total number of iterations
+int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) {
+ int count = 0;
+ int subdeviceCount;
+ int card, dev, subDev;
+ char devname[16];
+ int err;
+ snd_ctl_t *handle;
+ snd_pcm_t *pcm;
+ snd_pcm_info_t* pcminfo;
+ snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL;
+ UINT32 deviceID;
+ int doContinue = TRUE;
+
+ snd_pcm_info_malloc(&pcminfo);
+ snd_ctl_card_info_malloc(&cardinfo);
+
+ // 1st try "default" device
+ err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
+ SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ if (err < 0) {
+ // try with the other direction
+ err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
+ SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ }
+ if (err < 0) {
+ ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err));
+ } else {
+ err = snd_pcm_info(pcm, pcminfo);
+ snd_pcm_close(pcm);
+ if (err < 0) {
+ ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n",
+ snd_strerror(err));
+ } else {
+ // try to get card info
+ card = snd_pcm_info_get_card(pcminfo);
+ if (card >= 0) {
+ sprintf(devname, ALSA_HARDWARE_CARD, card);
+ if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) {
+ if (snd_ctl_card_info(handle, cardinfo) >= 0) {
+ defcardinfo = cardinfo;
+ }
+ snd_ctl_close(handle);
+ }
+ }
+ // call callback function for the device
+ if (iterator != NULL) {
+ doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo,
+ defcardinfo, userData);
+ }
+ count++;
+ }
+ }
+
+ // iterate cards
+ card = -1;
+ while (doContinue) {
+ if (snd_card_next(&card) < 0) {
+ break;
+ }
+ if (card < 0) {
+ break;
+ }
+ sprintf(devname, ALSA_HARDWARE_CARD, card);
+ TRACE1("Opening alsa device \"%s\"...\n", devname);
+ err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK);
+ if (err < 0) {
+ ERROR2("ERROR: snd_ctl_open, card=%d: %s\n",
+ card, snd_strerror(err));
+ } else {
+ err = snd_ctl_card_info(handle, cardinfo);
+ if (err < 0) {
+ ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n",
+ card, snd_strerror(err));
+ } else {
+ dev = -1;
+ while (doContinue) {
+ if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
+ ERROR0("snd_ctl_pcm_next_device\n");
+ }
+ if (dev < 0) {
+ break;
+ }
+ snd_pcm_info_set_device(pcminfo, dev);
+ snd_pcm_info_set_subdevice(pcminfo, 0);
+ snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
+ err = snd_ctl_pcm_info(handle, pcminfo);
+ if (err == -ENOENT) {
+ // try with the other direction
+ snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
+ err = snd_ctl_pcm_info(handle, pcminfo);
+ }
+ if (err < 0) {
+ if (err != -ENOENT) {
+ ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s",
+ card, snd_strerror(err));
+ }
+ } else {
+ subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ?
+ snd_pcm_info_get_subdevices_count(pcminfo) : 1;
+ if (iterator!=NULL) {
+ for (subDev = 0; subDev < subdeviceCount; subDev++) {
+ deviceID = encodeDeviceID(card, dev, subDev);
+ doContinue = (*iterator)(deviceID, pcminfo,
+ cardinfo, userData);
+ count++;
+ if (!doContinue) {
+ break;
+ }
+ }
+ } else {
+ count += subdeviceCount;
+ }
+ }
+ } // of while(doContinue)
+ }
+ snd_ctl_close(handle);
+ }
+ }
+ snd_ctl_card_info_free(cardinfo);
+ snd_pcm_info_free(pcminfo);
+ return count;
+}
+
+int getAudioDeviceCount() {
+ initAlsaSupport();
+ return iteratePCMDevices(NULL, NULL);
+}
+
+int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo,
+ snd_ctl_card_info_t* cardinfo, void* userData) {
+ char buffer[300];
+ ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData;
+#ifdef ALSA_PCM_USE_PLUGHW
+ int usePlugHw = 1;
+#else
+ int usePlugHw = 0;
+#endif
+
+ initAlsaSupport();
+ if (desc->index == 0) {
+ // we found the device with correct index
+ *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ?
+ 1 : snd_pcm_info_get_subdevices_count(pcminfo);
+ *desc->deviceID = deviceID;
+ buffer[0]=' '; buffer[1]='[';
+ // buffer[300] is enough to store the actual device string w/o overrun
+ getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM);
+ strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
+ strncpy(desc->name,
+ (cardinfo != NULL)
+ ? snd_ctl_card_info_get_id(cardinfo)
+ : snd_pcm_info_get_id(pcminfo),
+ desc->strLen - strlen(buffer));
+ strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
+ strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen);
+ strncpy(desc->description,
+ (cardinfo != NULL)
+ ? snd_ctl_card_info_get_name(cardinfo)
+ : snd_pcm_info_get_name(pcminfo),
+ desc->strLen);
+ strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
+ strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description));
+ strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
+ strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description));
+ getALSAVersion(desc->version, desc->strLen);
+ TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version);
+ return FALSE; // do not continue iteration
+ }
+ desc->index--;
+ return TRUE;
+}
+
+// returns 0 if successful
+int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) {
+ char buffer[200];
+ int ret;
+
+ initAlsaSupport();
+ getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM);
+
+ TRACE1("Opening ALSA device %s\n", buffer);
+ ret = snd_pcm_open(handle, buffer,
+ isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE,
+ SND_PCM_NONBLOCK);
+ if (ret != 0) {
+ ERROR1("snd_pcm_open returned error code %d \n", ret);
+ *handle = NULL;
+ }
+ return ret;
+}
+
+
+int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) {
+ initAlsaSupport();
+ TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index);
+ iteratePCMDevices(&deviceInfoIterator, desc);
+ return (desc->index == 0)?TRUE:FALSE;
+}
+
+// returns 1 if successful
+// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h)
+int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat,
+ int* sampleSizeInBytes, int* significantBits,
+ int* isSigned, int* isBigEndian, int* enc) {
+
+ *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8;
+ *significantBits = snd_pcm_format_width(alsaFormat);
+
+ // defaults
+ *enc = 0; // PCM
+ *isSigned = (snd_pcm_format_signed(alsaFormat) > 0);
+ *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0);
+
+ // non-PCM formats
+ if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law
+ *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes;
+ }
+ else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law
+ *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes;
+ }
+ else if (snd_pcm_format_linear(alsaFormat) < 1) {
+ return 0;
+ }
+ return (*sampleSizeInBytes > 0);
+}
+
+// returns 1 if successful
+int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat,
+ int sampleSizeInBytes, int significantBits,
+ int isSigned, int isBigEndian, int enc) {
+ *alsaFormat = SND_PCM_FORMAT_UNKNOWN;
+
+ if (enc == 0) {
+ *alsaFormat = snd_pcm_build_linear_format(significantBits,
+ sampleSizeInBytes * 8,
+ isSigned?0:1,
+ isBigEndian?1:0);
+ }
+ else if ((sampleSizeInBytes == 1) && (significantBits == 8)) {
+ if (enc == 1) { // ULAW
+ *alsaFormat = SND_PCM_FORMAT_MU_LAW;
+ }
+ else if (enc == 2) { // ALAW
+ *alsaFormat = SND_PCM_FORMAT_A_LAW;
+ }
+ }
+ return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1;
+}
+
+
+/* end */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// define this with a later version of ALSA than 0.9.0rc3
+// (starting from 1.0.0 it became default behaviour)
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#include <alsa/asoundlib.h>
+#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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+//#define USE_TRACE
+
+#include "Ports.h"
+#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
+#include <alsa/asoundlib.h>
+
+#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
--- a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java Fri Mar 23 09:26:59 2018 +0100
+++ b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java Fri Mar 23 09:51:02 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,23 +38,9 @@
final class Platform {
// native library we need to load
- private static final String libNameMain = "jsound";
- private static final String libNameALSA = "jsoundalsa";
- private static final String libNameDSound = "jsoundds";
-
- // extra libs handling: bit flags for each different library
- public static final int LIB_MAIN = 1;
- public static final int LIB_ALSA = 2;
- public static final int LIB_DSOUND = 4;
+ private static final String libName = "jsound";
- // bit field of the constants above. Willbe set in loadLibraries
- private static int loadedLibs = 0;
-
- // features: the main native library jsound reports which feature is
- // contained in which lib
- public static final int FEATURE_MIDIIO = 1;
- public static final int FEATURE_PORTS = 2;
- public static final int FEATURE_DIRECT_AUDIO = 3;
+ private static boolean isNativeLibLoaded;
// SYSTEM CHARACTERISTICS
// vary according to hardware architecture
@@ -66,7 +52,6 @@
if(Printer.trace)Printer.trace(">> Platform.java: static");
loadLibraries();
- readProperties();
}
/**
@@ -95,72 +80,37 @@
private static void loadLibraries() {
if(Printer.trace)Printer.trace(">>Platform.loadLibraries");
- // load the main library
- AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
- System.loadLibrary(libNameMain);
- return null;
- });
- // just for the heck of it...
- loadedLibs |= LIB_MAIN;
-
- // now try to load extra libs. They are defined at compile time in the Makefile
- // with the define EXTRA_SOUND_JNI_LIBS
- String extraLibs = nGetExtraLibraries();
- // the string is the libraries, separated by white space
- StringTokenizer st = new StringTokenizer(extraLibs);
- while (st.hasMoreTokens()) {
- final String lib = st.nextToken();
- try {
- AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
- System.loadLibrary(lib);
- return null;
- });
-
- if (lib.equals(libNameALSA)) {
- loadedLibs |= LIB_ALSA;
- if (Printer.debug) Printer.debug("Loaded ALSA lib successfully.");
- } else if (lib.equals(libNameDSound)) {
- loadedLibs |= LIB_DSOUND;
- if (Printer.debug) Printer.debug("Loaded DirectSound lib successfully.");
- } else {
- if (Printer.err) Printer.err("Loaded unknown lib '"+lib+"' successfully.");
- }
- } catch (Throwable t) {
- if (Printer.err) Printer.err("Couldn't load library "+lib+": "+t.toString());
- }
+ // load the native library
+ isNativeLibLoaded = true;
+ try {
+ AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+ System.loadLibrary(libName);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (Printer.err) Printer.err("Couldn't load library "+libName+": "+t.toString());
+ isNativeLibLoaded = false;
+ }
+ if (isNativeLibLoaded) {
+ bigEndian = nIsBigEndian();
}
}
static boolean isMidiIOEnabled() {
- return isFeatureLibLoaded(FEATURE_MIDIIO);
+ if (Printer.debug) Printer.debug("Platform: Checking for MidiIO; library is loaded=" + isNativeLibLoaded);
+ return isNativeLibLoaded;
}
static boolean isPortsEnabled() {
- return isFeatureLibLoaded(FEATURE_PORTS);
+ if (Printer.debug) Printer.debug("Platform: Checking for Ports; library is loaded=" + isNativeLibLoaded);
+ return isNativeLibLoaded;
}
static boolean isDirectAudioEnabled() {
- return isFeatureLibLoaded(FEATURE_DIRECT_AUDIO);
- }
-
- private static boolean isFeatureLibLoaded(int feature) {
- if (Printer.debug) Printer.debug("Platform: Checking for feature "+feature+"...");
- int requiredLib = nGetLibraryForFeature(feature);
- boolean isLoaded = (requiredLib != 0) && ((loadedLibs & requiredLib) == requiredLib);
- if (Printer.debug) Printer.debug(" ...needs library "+requiredLib+". Result is loaded="+isLoaded);
- return isLoaded;
+ if (Printer.debug) Printer.debug("Platform: Checking for DirectAudio; library is loaded=" + isNativeLibLoaded);
+ return isNativeLibLoaded;
}
- // the following native methods are implemented in Platform.c
+ // the following native method is implemented in Platform.c
private static native boolean nIsBigEndian();
- private static native String nGetExtraLibraries();
- private static native int nGetLibraryForFeature(int feature);
-
- /**
- * Read the required system properties.
- */
- private static void readProperties() {
- // $$fb 2002-03-06: implement check for endianness in native. Facilitates porting !
- bigEndian = nIsBigEndian();
- }
}
--- a/src/java.desktop/share/native/libjsound/Platform.c Fri Mar 23 09:26:59 2018 +0100
+++ b/src/java.desktop/share/native/libjsound/Platform.c Fri Mar 23 09:51:02 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,83 +41,3 @@
JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_Platform_nIsBigEndian(JNIEnv *env, jclass clss) {
return UTIL_IsBigEndianPlatform();
}
-
-/*
- * Class: com_sun_media_sound_Platform
- * Method: nGetExtraLibraries
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_com_sun_media_sound_Platform_nGetExtraLibraries(JNIEnv *env, jclass clss) {
- return (*env)->NewStringUTF(env, EXTRA_SOUND_JNI_LIBS);
-}
-
-/*
- * Class: com_sun_media_sound_Platform
- * Method: nGetLibraryForFeature
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_com_sun_media_sound_Platform_nGetLibraryForFeature
- (JNIEnv *env, jclass clazz, jint feature) {
-
-// for every OS
-#if X_PLATFORM == X_WINDOWS
- switch (feature) {
- case com_sun_media_sound_Platform_FEATURE_MIDIIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- return com_sun_media_sound_Platform_LIB_DSOUND;
- }
-#endif
-#if (X_PLATFORM == X_SOLARIS)
- switch (feature) {
- case com_sun_media_sound_Platform_FEATURE_MIDIIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
- }
-#endif
-#if (X_PLATFORM == X_LINUX)
- switch (feature) {
- case com_sun_media_sound_Platform_FEATURE_MIDIIO:
- return com_sun_media_sound_Platform_LIB_ALSA;
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_ALSA;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- return com_sun_media_sound_Platform_LIB_ALSA;
- }
-#endif
-#if (X_PLATFORM == X_MACOSX)
- switch (feature) {
- case com_sun_media_sound_Platform_FEATURE_MIDIIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
- }
-#endif
-#if (X_PLATFORM == X_BSD)
- switch (feature) {
- case com_sun_media_sound_Platform_FEATURE_MIDIIO:
- return com_sun_media_sound_Platform_LIB_MAIN;
-#ifdef __FreeBSD__
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_ALSA;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- return com_sun_media_sound_Platform_LIB_ALSA;
-#else
- case com_sun_media_sound_Platform_FEATURE_PORTS:
- return com_sun_media_sound_Platform_LIB_MAIN;
- case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
- // XXXBSD: When native Direct Audio support is ported change
- // this back to returning com_sun_media_sound_Platform_LIB_MAIN
- return 0;
-#endif
- }
-#endif
- return 0;
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_SolarisOS_Utils.h"
+#include "DirectAudio.h"
+
+#if USE_DAUDIO == TRUE
+
+
+// The default buffer time
+#define DEFAULT_PERIOD_TIME_MILLIS 50
+
+///// implemented functions of DirectAudio.h
+
+INT32 DAUDIO_GetDirectAudioDeviceCount() {
+ return (INT32) getAudioDeviceCount();
+}
+
+
+INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex,
+ DirectAudioDeviceDescription* description) {
+ AudioDeviceDescription desc;
+
+ if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
+ description->maxSimulLines = desc.maxSimulLines;
+ strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1);
+ description->name[DAUDIO_STRING_LENGTH-1] = 0;
+ strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1);
+ description->vendor[DAUDIO_STRING_LENGTH-1] = 0;
+ strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1);
+ description->version[DAUDIO_STRING_LENGTH-1] = 0;
+ /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/
+ strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1);
+ description->description[DAUDIO_STRING_LENGTH-1] = 0;
+ return TRUE;
+ }
+ return FALSE;
+
+}
+
+#define MAX_SAMPLE_RATES 20
+
+void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
+ int fd = -1;
+ AudioDeviceDescription desc;
+ am_sample_rates_t *sr;
+ /* hardcoded bits and channels */
+ int bits[] = {8, 16};
+ int bitsCount = 2;
+ int channels[] = {1, 2};
+ int channelsCount = 2;
+ /* for querying sample rates */
+ int err;
+ int ch, b, s;
+
+ TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource);
+ if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+ fd = open(desc.pathctl, O_RDONLY);
+ }
+ if (fd < 0) {
+ ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
+ return;
+ }
+
+ /* get sample rates */
+ sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES));
+ if (sr == NULL) {
+ ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex);
+ close(fd);
+ return;
+ }
+
+ sr->num_samp_rates = MAX_SAMPLE_RATES;
+ sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD;
+ sr->samp_rates[0] = -2;
+ err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr);
+ if (err < 0) {
+ ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n",
+ (int)mixerIndex);
+ ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n",
+ (int) sr->num_samp_rates,
+ (int) sr->samp_rates[0]);
+ /* Some Solaris 8 drivers fail for get sample rates!
+ * Do as if we support all sample rates
+ */
+ sr->flags = MIXER_SR_LIMITS;
+ }
+ if ((sr->flags & MIXER_SR_LIMITS)
+ || (sr->num_samp_rates > MAX_SAMPLE_RATES)) {
+#ifdef USE_TRACE
+ if ((sr->flags & MIXER_SR_LIMITS)) {
+ TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n",
+ (int)mixerIndex);
+ }
+ if (sr->num_samp_rates > MAX_SAMPLE_RATES) {
+ TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n",
+ MAX_SAMPLE_RATES, (int)mixerIndex);
+ }
+#endif
+ /*
+ * Fake it to have only one sample rate: -1
+ */
+ sr->num_samp_rates = 1;
+ sr->samp_rates[0] = -1;
+ }
+ close(fd);
+
+ for (ch = 0; ch < channelsCount; ch++) {
+ for (b = 0; b < bitsCount; b++) {
+ for (s = 0; s < sr->num_samp_rates; s++) {
+ DAUDIO_AddAudioFormat(creator,
+ bits[b], /* significant bits */
+ 0, /* frameSize: let it be calculated */
+ channels[ch],
+ (float) ((int) sr->samp_rates[s]),
+ DAUDIO_PCM, /* encoding - let's only do PCM */
+ (bits[b] > 8)?TRUE:TRUE, /* isSigned */
+#ifdef _LITTLE_ENDIAN
+ FALSE /* little endian */
+#else
+ (bits[b] > 8)?TRUE:FALSE /* big endian */
+#endif
+ );
+ }
+ }
+ }
+ free(sr);
+}
+
+
+typedef struct {
+ int fd;
+ audio_info_t info;
+ int bufferSizeInBytes;
+ int frameSize; /* storage size in Bytes */
+ /* how many bytes were written or read */
+ INT32 transferedBytes;
+ /* if transferedBytes exceed 32-bit boundary,
+ * it will be reset and positionOffset will receive
+ * the offset
+ */
+ INT64 positionOffset;
+} SolPcmInfo;
+
+
+void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
+ int encoding, float sampleRate, int sampleSizeInBits,
+ int frameSize, int channels,
+ int isSigned, int isBigEndian, int bufferSizeInBytes) {
+ int err = 0;
+ int openMode;
+ AudioDeviceDescription desc;
+ SolPcmInfo* info;
+
+ TRACE0("> DAUDIO_Open\n");
+ if (encoding != DAUDIO_PCM) {
+ ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding);
+ return NULL;
+ }
+ if (channels <= 0) {
+ ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels);
+ return NULL;
+ }
+
+ info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo));
+ if (!info) {
+ ERROR0("Out of memory\n");
+ return NULL;
+ }
+ memset(info, 0, sizeof(SolPcmInfo));
+ info->frameSize = frameSize;
+ info->fd = -1;
+
+ if (isSource) {
+ openMode = O_WRONLY;
+ } else {
+ openMode = O_RDONLY;
+ }
+
+#ifndef __linux__
+ /* blackdown does not use NONBLOCK */
+ openMode |= O_NONBLOCK;
+#endif
+
+ if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+ info->fd = open(desc.path, openMode);
+ }
+ if (info->fd < 0) {
+ ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex);
+ free(info);
+ return NULL;
+ }
+ /* set to multiple open */
+ if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) {
+ TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path);
+ } else {
+ ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path);
+ }
+
+ AUDIO_INITINFO(&(info->info));
+ /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */
+ err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
+
+ /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */
+ AUDIO_INITINFO(&(info->info));
+
+ if (isSource) {
+ info->info.play.sample_rate = sampleRate;
+ info->info.play.precision = sampleSizeInBits;
+ info->info.play.channels = channels;
+ info->info.play.encoding = AUDIO_ENCODING_LINEAR;
+ info->info.play.buffer_size = bufferSizeInBytes;
+ info->info.play.pause = 1;
+ } else {
+ info->info.record.sample_rate = sampleRate;
+ info->info.record.precision = sampleSizeInBits;
+ info->info.record.channels = channels;
+ info->info.record.encoding = AUDIO_ENCODING_LINEAR;
+ info->info.record.buffer_size = bufferSizeInBytes;
+ info->info.record.pause = 1;
+ }
+ err = ioctl(info->fd, AUDIO_SETINFO, &(info->info));
+ if (err < 0) {
+ ERROR0("DAUDIO_Open: could not set info!\n");
+ DAUDIO_Close((void*) info, isSource);
+ return NULL;
+ }
+ DAUDIO_Flush((void*) info, isSource);
+
+ err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
+ if (err >= 0) {
+ if (isSource) {
+ info->bufferSizeInBytes = info->info.play.buffer_size;
+ } else {
+ info->bufferSizeInBytes = info->info.record.buffer_size;
+ }
+ TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n",
+ (int) bufferSizeInBytes,
+ (int) info->bufferSizeInBytes);
+ } else {
+ ERROR0("DAUDIO_Open: cannot get info!\n");
+ DAUDIO_Close((void*) info, isSource);
+ return NULL;
+ }
+ TRACE0("< DAUDIO_Open: Opened device successfully.\n");
+ return (void*) info;
+}
+
+
+int DAUDIO_Start(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int err, modified;
+ audio_info_t audioInfo;
+
+ TRACE0("> DAUDIO_Start\n");
+
+ AUDIO_INITINFO(&audioInfo);
+ err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+ if (err >= 0) {
+ // unpause
+ modified = FALSE;
+ if (isSource && audioInfo.play.pause) {
+ audioInfo.play.pause = 0;
+ modified = TRUE;
+ }
+ if (!isSource && audioInfo.record.pause) {
+ audioInfo.record.pause = 0;
+ modified = TRUE;
+ }
+ if (modified) {
+ err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+ }
+ }
+
+ TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error");
+ return (err >= 0)?TRUE:FALSE;
+}
+
+int DAUDIO_Stop(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int err, modified;
+ audio_info_t audioInfo;
+
+ TRACE0("> DAUDIO_Stop\n");
+
+ AUDIO_INITINFO(&audioInfo);
+ err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+ if (err >= 0) {
+ // pause
+ modified = FALSE;
+ if (isSource && !audioInfo.play.pause) {
+ audioInfo.play.pause = 1;
+ modified = TRUE;
+ }
+ if (!isSource && !audioInfo.record.pause) {
+ audioInfo.record.pause = 1;
+ modified = TRUE;
+ }
+ if (modified) {
+ err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+ }
+ }
+
+ TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error");
+ return (err >= 0)?TRUE:FALSE;
+}
+
+void DAUDIO_Close(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+
+ TRACE0("DAUDIO_Close\n");
+ if (info != NULL) {
+ if (info->fd >= 0) {
+ DAUDIO_Flush(id, isSource);
+ close(info->fd);
+ }
+ free(info);
+ }
+}
+
+#ifndef USE_TRACE
+/* close to 2^31 */
+#define POSITION_MAX 2000000000
+#else
+/* for testing */
+#define POSITION_MAX 1000000
+#endif
+
+void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) {
+ audio_info_t audioInfo;
+ audio_prinfo_t* prinfo;
+ int err;
+ int offset = -1;
+ int underrun = FALSE;
+ int devBytes = 0;
+
+ if (count > 0) {
+ info->transferedBytes += count;
+
+ if (isSource) {
+ prinfo = &(audioInfo.play);
+ } else {
+ prinfo = &(audioInfo.record);
+ }
+ AUDIO_INITINFO(&audioInfo);
+ err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+ if (err >= 0) {
+ underrun = prinfo->error;
+ devBytes = prinfo->samples * info->frameSize;
+ }
+ AUDIO_INITINFO(&audioInfo);
+ if (underrun) {
+ /* if an underrun occurred, reset */
+ ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n",
+ (devBytes - info->transferedBytes));
+ ERROR1(" devBytes from %d to 0, ", devBytes);
+ ERROR2(" positionOffset from %d to %d ",
+ (int) info->positionOffset,
+ (int) (info->positionOffset + info->transferedBytes));
+ ERROR1(" transferedBytes from %d to 0\n",
+ (int) info->transferedBytes);
+ prinfo->samples = 0;
+ info->positionOffset += info->transferedBytes;
+ info->transferedBytes = 0;
+ }
+ else if (info->transferedBytes > POSITION_MAX) {
+ /* we will reset transferedBytes and
+ * the samples field in prinfo
+ */
+ offset = devBytes;
+ prinfo->samples = 0;
+ }
+ /* reset error flag */
+ prinfo->error = 0;
+
+ err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+ if (err >= 0) {
+ if (offset > 0) {
+ /* upon exit of AUDIO_SETINFO, the samples parameter
+ * was set to the previous value. This is our
+ * offset.
+ */
+ TRACE1("Adjust samplePos: offset=%d, ", (int) offset);
+ TRACE2("transferedBytes=%d -> %d, ",
+ (int) info->transferedBytes,
+ (int) (info->transferedBytes - offset));
+ TRACE2("positionOffset=%d -> %d\n",
+ (int) (info->positionOffset),
+ (int) (((int) info->positionOffset) + offset));
+ info->transferedBytes -= offset;
+ info->positionOffset += offset;
+ }
+ } else {
+ ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n");
+ }
+ }
+}
+
+// returns -1 on error
+int DAUDIO_Write(void* id, char* data, int byteSize) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int ret = -1;
+
+ TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
+ if (info!=NULL) {
+ ret = write(info->fd, data, byteSize);
+ resetErrorFlagAndAdjustPosition(info, TRUE, ret);
+ /* sets ret to -1 if buffer full, no error! */
+ if (ret < 0) {
+ ret = 0;
+ }
+ }
+ TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
+ return ret;
+}
+
+// returns -1 on error
+int DAUDIO_Read(void* id, char* data, int byteSize) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int ret = -1;
+
+ TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
+ if (info != NULL) {
+ ret = read(info->fd, data, byteSize);
+ resetErrorFlagAndAdjustPosition(info, TRUE, ret);
+ /* sets ret to -1 if buffer full, no error! */
+ if (ret < 0) {
+ ret = 0;
+ }
+ }
+ TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
+ return ret;
+}
+
+
+int DAUDIO_GetBufferSize(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ if (info) {
+ return info->bufferSizeInBytes;
+ }
+ return 0;
+}
+
+int DAUDIO_StillDraining(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ audio_info_t audioInfo;
+ audio_prinfo_t* prinfo;
+ int ret = FALSE;
+
+ if (info!=NULL) {
+ if (isSource) {
+ prinfo = &(audioInfo.play);
+ } else {
+ prinfo = &(audioInfo.record);
+ }
+ /* check error flag */
+ AUDIO_INITINFO(&audioInfo);
+ ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+ ret = (prinfo->error != 0)?FALSE:TRUE;
+ }
+ return ret;
+}
+
+
+int getDevicePosition(SolPcmInfo* info, int isSource) {
+ audio_info_t audioInfo;
+ audio_prinfo_t* prinfo;
+ int err;
+
+ if (isSource) {
+ prinfo = &(audioInfo.play);
+ } else {
+ prinfo = &(audioInfo.record);
+ }
+ AUDIO_INITINFO(&audioInfo);
+ err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+ if (err >= 0) {
+ /*TRACE2("---> device paused: %d eof=%d\n",
+ prinfo->pause, prinfo->eof);
+ */
+ return (int) (prinfo->samples * info->frameSize);
+ }
+ ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n");
+ return -1;
+}
+
+int DAUDIO_Flush(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int err = -1;
+ int pos;
+
+ TRACE0("DAUDIO_Flush\n");
+ if (info) {
+ if (isSource) {
+ err = ioctl(info->fd, I_FLUSH, FLUSHW);
+ } else {
+ err = ioctl(info->fd, I_FLUSH, FLUSHR);
+ }
+ if (err >= 0) {
+ /* resets the transferedBytes parameter to
+ * the current samples count of the device
+ */
+ pos = getDevicePosition(info, isSource);
+ if (pos >= 0) {
+ info->transferedBytes = pos;
+ }
+ }
+ }
+ if (err < 0) {
+ ERROR0("ERROR in DAUDIO_Flush\n");
+ }
+ return (err < 0)?FALSE:TRUE;
+}
+
+int DAUDIO_GetAvailable(void* id, int isSource) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int ret = 0;
+ int pos;
+
+ if (info) {
+ /* unfortunately, the STREAMS architecture
+ * seems to not have a method for querying
+ * the available bytes to read/write!
+ * estimate it...
+ */
+ pos = getDevicePosition(info, isSource);
+ if (pos >= 0) {
+ if (isSource) {
+ /* we usually have written more bytes
+ * to the queue than the device position should be
+ */
+ ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos);
+ } else {
+ /* for record, the device stream should
+ * be usually ahead of our read actions
+ */
+ ret = pos - info->transferedBytes;
+ }
+ if (ret > info->bufferSizeInBytes) {
+ ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n",
+ (int) ret, (int) info->bufferSizeInBytes);
+ ERROR2(" devicePos=%d, transferedBytes=%d\n",
+ (int) pos, (int) info->transferedBytes);
+ ret = info->bufferSizeInBytes;
+ }
+ else if (ret < 0) {
+ ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n",
+ (int) ret);
+ ERROR2(" devicePos=%d, transferedBytes=%d\n",
+ (int) pos, (int) info->transferedBytes);
+ ret = 0;
+ }
+ }
+ }
+
+ TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
+ return ret;
+}
+
+INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int ret;
+ int pos;
+ INT64 result = javaBytePos;
+
+ if (info) {
+ pos = getDevicePosition(info, isSource);
+ if (pos >= 0) {
+ result = info->positionOffset + pos;
+ }
+ }
+
+ //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
+ return result;
+}
+
+
+void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+ SolPcmInfo* info = (SolPcmInfo*) id;
+ int ret;
+ int pos;
+
+ if (info) {
+ pos = getDevicePosition(info, isSource);
+ if (pos >= 0) {
+ info->positionOffset = javaBytePos - pos;
+ }
+ }
+}
+
+int DAUDIO_RequiresServicing(void* id, int isSource) {
+ // never need servicing on Solaris
+ return FALSE;
+}
+
+void DAUDIO_Service(void* id, int isSource) {
+ // never need servicing on Solaris
+}
+
+
+#endif // USE_DAUDIO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+//#define USE_TRACE
+
+#include "Ports.h"
+#include "PLATFORM_API_SolarisOS_Utils.h"
+
+#if USE_PORTS == TRUE
+
+#define MONITOR_GAIN_STRING "Monitor Gain"
+
+#define ALL_TARGET_PORT_COUNT 6
+
+// define the following to not use audio_prinfo_t.mod_ports
+#define SOLARIS7_COMPATIBLE
+
+// Solaris audio defines
+static int targetPorts[ALL_TARGET_PORT_COUNT] = {
+ AUDIO_SPEAKER,
+ AUDIO_HEADPHONE,
+ AUDIO_LINE_OUT,
+ AUDIO_AUX1_OUT,
+ AUDIO_AUX2_OUT,
+ AUDIO_SPDIF_OUT
+};
+
+static char* targetPortNames[ALL_TARGET_PORT_COUNT] = {
+ "Speaker",
+ "Headphone",
+ "Line Out",
+ "AUX1 Out",
+ "AUX2 Out",
+ "SPDIF Out"
+};
+
+// defined in Ports.h
+static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = {
+ PORT_DST_SPEAKER,
+ PORT_DST_HEADPHONE,
+ PORT_DST_LINE_OUT,
+ PORT_DST_UNKNOWN,
+ PORT_DST_UNKNOWN,
+ PORT_DST_UNKNOWN,
+};
+
+#define ALL_SOURCE_PORT_COUNT 7
+
+// Solaris audio defines
+static int sourcePorts[ALL_SOURCE_PORT_COUNT] = {
+ AUDIO_MICROPHONE,
+ AUDIO_LINE_IN,
+ AUDIO_CD,
+ AUDIO_AUX1_IN,
+ AUDIO_AUX2_IN,
+ AUDIO_SPDIF_IN,
+ AUDIO_CODEC_LOOPB_IN
+};
+
+static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = {
+ "Microphone In",
+ "Line In",
+ "Compact Disc In",
+ "AUX1 In",
+ "AUX2 In",
+ "SPDIF In",
+ "Internal Loopback"
+};
+
+// Ports.h defines
+static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = {
+ PORT_SRC_MICROPHONE,
+ PORT_SRC_LINE_IN,
+ PORT_SRC_COMPACT_DISC,
+ PORT_SRC_UNKNOWN,
+ PORT_SRC_UNKNOWN,
+ PORT_SRC_UNKNOWN,
+ PORT_SRC_UNKNOWN
+};
+
+struct tag_PortControlID;
+
+typedef struct tag_PortInfo {
+ int fd; // file descriptor of the pseudo device
+ audio_info_t audioInfo;
+ // ports
+ int targetPortCount;
+ int sourcePortCount;
+ // indexes to sourcePorts/targetPorts
+ // contains first target ports, then source ports
+ int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT];
+ // controls
+ int maxControlCount; // upper bound of number of controls
+ int usedControlIDs; // number of items already filled in controlIDs
+ struct tag_PortControlID* controlIDs; // the control IDs themselves
+} PortInfo;
+
+#define PORT_CONTROL_TYPE_PLAY 0x4000000
+#define PORT_CONTROL_TYPE_RECORD 0x8000000
+#define PORT_CONTROL_TYPE_SELECT_PORT 1
+#define PORT_CONTROL_TYPE_GAIN 2
+#define PORT_CONTROL_TYPE_BALANCE 3
+#define PORT_CONTROL_TYPE_MONITOR_GAIN 10
+#define PORT_CONTROL_TYPE_OUTPUT_MUTED 11
+#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD
+#define PORT_CONTROL_TYPE_MASK 0xFFFFFF
+
+
+typedef struct tag_PortControlID {
+ PortInfo* portInfo;
+ INT32 controlType; // PORT_CONTROL_TYPE_XX
+ uint_t port;
+} PortControlID;
+
+
+///// implemented functions of Ports.h
+
+INT32 PORT_GetPortMixerCount() {
+ return (INT32) getAudioDeviceCount();
+}
+
+
+INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
+ AudioDeviceDescription desc;
+
+ if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
+ strncpy(description->name, desc.name, PORT_STRING_LENGTH-1);
+ description->name[PORT_STRING_LENGTH-1] = 0;
+ strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1);
+ description->vendor[PORT_STRING_LENGTH-1] = 0;
+ strncpy(description->version, desc.version, PORT_STRING_LENGTH-1);
+ description->version[PORT_STRING_LENGTH-1] = 0;
+ /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/
+ strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1);
+ description->description[PORT_STRING_LENGTH-1] = 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+void* PORT_Open(INT32 mixerIndex) {
+ PortInfo* info = NULL;
+ int fd = -1;
+ AudioDeviceDescription desc;
+ int success = FALSE;
+
+ TRACE0("PORT_Open\n");
+ if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+ fd = open(desc.pathctl, O_RDWR);
+ }
+ if (fd < 0) {
+ ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
+ return NULL;
+ }
+
+ info = (PortInfo*) malloc(sizeof(PortInfo));
+ if (info != NULL) {
+ memset(info, 0, sizeof(PortInfo));
+ info->fd = fd;
+ success = TRUE;
+ }
+ if (!success) {
+ if (fd >= 0) {
+ close(fd);
+ }
+ PORT_Close((void*) info);
+ info = NULL;
+ }
+ return info;
+}
+
+void PORT_Close(void* id) {
+ TRACE0("PORT_Close\n");
+ if (id != NULL) {
+ PortInfo* info = (PortInfo*) id;
+ if (info->fd >= 0) {
+ close(info->fd);
+ info->fd = -1;
+ }
+ if (info->controlIDs) {
+ free(info->controlIDs);
+ info->controlIDs = NULL;
+ }
+ free(info);
+ }
+}
+
+
+
+INT32 PORT_GetPortCount(void* id) {
+ int ret = 0;
+ PortInfo* info = (PortInfo*) id;
+ if (info != NULL) {
+ if (!info->targetPortCount && !info->sourcePortCount) {
+ int i;
+ AUDIO_INITINFO(&info->audioInfo);
+ if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) {
+ for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) {
+ if (info->audioInfo.play.avail_ports & targetPorts[i]) {
+ info->ports[info->targetPortCount] = i;
+ info->targetPortCount++;
+ }
+#ifdef SOLARIS7_COMPATIBLE
+ TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i],
+ info->audioInfo.play.avail_ports & targetPorts[i]);
+#else
+ TRACE4("Target %d %s: avail=%d mod=%d\n", i, targetPortNames[i],
+ info->audioInfo.play.avail_ports & targetPorts[i],
+ info->audioInfo.play.mod_ports & targetPorts[i]);
+#endif
+ }
+ for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) {
+ if (info->audioInfo.record.avail_ports & sourcePorts[i]) {
+ info->ports[info->targetPortCount + info->sourcePortCount] = i;
+ info->sourcePortCount++;
+ }
+#ifdef SOLARIS7_COMPATIBLE
+ TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i],
+ info->audioInfo.record.avail_ports & sourcePorts[i]);
+#else
+ TRACE4("Source %d %s: avail=%d mod=%d\n", i, sourcePortNames[i],
+ info->audioInfo.record.avail_ports & sourcePorts[i],
+ info->audioInfo.record.mod_ports & sourcePorts[i]);
+#endif
+ }
+ }
+ }
+ ret = info->targetPortCount + info->sourcePortCount;
+ }
+ return ret;
+}
+
+int isSourcePort(PortInfo* info, INT32 portIndex) {
+ return (portIndex >= info->targetPortCount);
+}
+
+INT32 PORT_GetPortType(void* id, INT32 portIndex) {
+ PortInfo* info = (PortInfo*) id;
+ if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
+ if (isSourcePort(info, portIndex)) {
+ return sourcePortJavaSoundMapping[info->ports[portIndex]];
+ } else {
+ return targetPortJavaSoundMapping[info->ports[portIndex]];
+ }
+ }
+ return 0;
+}
+
+// pre-condition: portIndex must have been verified!
+char* getPortName(PortInfo* info, INT32 portIndex) {
+ char* ret = NULL;
+
+ if (isSourcePort(info, portIndex)) {
+ ret = sourcePortNames[info->ports[portIndex]];
+ } else {
+ ret = targetPortNames[info->ports[portIndex]];
+ }
+ return ret;
+}
+
+INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
+ PortInfo* info = (PortInfo*) id;
+ char* n;
+
+ if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
+ n = getPortName(info, portIndex);
+ if (n) {
+ strncpy(name, n, len-1);
+ name[len-1] = 0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex,
+ INT32 type, void** controlObjects, int* controlCount) {
+ PortControlID* controlID;
+ void* newControl = NULL;
+ int controlIndex;
+ char* jsType = NULL;
+ int isBoolean = FALSE;
+
+ TRACE0(">createPortControl\n");
+
+ // fill the ControlID structure and add this control
+ if (info->usedControlIDs >= info->maxControlCount) {
+ ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
+ return;
+ }
+ controlID = &(info->controlIDs[info->usedControlIDs]);
+ controlID->portInfo = info;
+ controlID->controlType = type;
+ controlIndex = info->ports[portIndex];
+ if (isSourcePort(info, portIndex)) {
+ controlID->port = sourcePorts[controlIndex];
+ } else {
+ controlID->port = targetPorts[controlIndex];
+ }
+ switch (type & PORT_CONTROL_TYPE_MASK) {
+ case PORT_CONTROL_TYPE_SELECT_PORT:
+ jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break;
+ case PORT_CONTROL_TYPE_GAIN:
+ jsType = CONTROL_TYPE_VOLUME; break;
+ case PORT_CONTROL_TYPE_BALANCE:
+ jsType = CONTROL_TYPE_BALANCE; break;
+ case PORT_CONTROL_TYPE_MONITOR_GAIN:
+ jsType = CONTROL_TYPE_VOLUME; break;
+ case PORT_CONTROL_TYPE_OUTPUT_MUTED:
+ jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break;
+ }
+ if (isBoolean) {
+ TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
+ newControl = (creator->newBooleanControl)(creator, controlID, jsType);
+ }
+ else if (jsType == CONTROL_TYPE_BALANCE) {
+ TRACE0(" PORT_CONTROL_TYPE_BALANCE\n");
+ newControl = (creator->newFloatControl)(creator, controlID, jsType,
+ -1.0f, 1.0f, 2.0f / 65.0f, "");
+ } else {
+ TRACE0(" PORT_CONTROL_TYPE_FLOAT\n");
+ newControl = (creator->newFloatControl)(creator, controlID, jsType,
+ 0.0f, 1.0f, 1.0f / 256.0f, "");
+ }
+ if (newControl) {
+ controlObjects[*controlCount] = newControl;
+ (*controlCount)++;
+ info->usedControlIDs++;
+ }
+ TRACE0("<createPortControl\n");
+}
+
+
+void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
+ void* compControl;
+
+ TRACE1(">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("<addCompoundControl\n");
+}
+
+void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
+ int i = 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("<addAllControl\n");
+}
+
+void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
+ PortInfo* info = (PortInfo*) id;
+ int portCount = PORT_GetPortCount(id);
+ void* controls[4];
+ int controlCount = 0;
+ INT32 type;
+ int selectable = 1;
+ memset(controls, 0, sizeof(controls));
+
+ TRACE4(">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 Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_SolarisOS_Utils.h"
+
+#define MAX_AUDIO_DEVICES 20
+
+// not thread safe...
+static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES];
+static int globalADCount = -1;
+static int globalADCacheTime = -1;
+/* how many seconds do we cache devices */
+#define AD_CACHE_TIME 30
+
+// return seconds
+long getTimeInSeconds() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec;
+}
+
+
+int getAudioDeviceCount() {
+ int count = MAX_AUDIO_DEVICES;
+
+ getAudioDevices(globalADPaths, &count);
+ return count;
+}
+
+/* returns TRUE if the path exists at all */
+int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) {
+ int i;
+ int found = 0;
+ int fileExists = 0;
+ // not thread safe...
+ static struct stat statBuf;
+
+ // get stats on the file
+ if (stat(path, &statBuf) == 0) {
+ // file exists.
+ fileExists = 1;
+ // If it is not yet in the adPath array, add it to the array
+ for (i = 0; i < *count; i++) {
+ if (adPath[i].st_ino == statBuf.st_ino
+ && adPath[i].st_dev == statBuf.st_dev) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ adPath[*count].st_ino = statBuf.st_ino;
+ adPath[*count].st_dev = statBuf.st_dev;
+ strncpy(adPath[*count].path, path, MAX_NAME_LENGTH);
+ adPath[*count].path[MAX_NAME_LENGTH - 1] = 0;
+ (*count)++;
+ TRACE1("Added audio device %s\n", path);
+ }
+ }
+ return fileExists;
+}
+
+
+void getAudioDevices(AudioDevicePath* adPath, int* count) {
+ int maxCount = *count;
+ char* audiodev;
+ char devsound[15];
+ int i;
+ long timeInSeconds = getTimeInSeconds();
+
+ if (globalADCount < 0
+ || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME
+ || (adPath != globalADPaths)) {
+ *count = 0;
+ // first device, if set, is AUDIODEV variable
+ audiodev = getenv("AUDIODEV");
+ if (audiodev != NULL && audiodev[0] != 0) {
+ addAudioDevice(audiodev, adPath, count);
+ }
+ // then try /dev/audio
+ addAudioDevice("/dev/audio", adPath, count);
+ // then go through all of the /dev/sound/? devices
+ for (i = 0; i < 100; i++) {
+ sprintf(devsound, "/dev/sound/%d", i);
+ if (!addAudioDevice(devsound, adPath, count)) {
+ break;
+ }
+ }
+ if (adPath == globalADPaths) {
+ /* commit cache */
+ globalADCount = *count;
+ /* set cache time */
+ globalADCacheTime = timeInSeconds;
+ }
+ } else {
+ /* return cache */
+ *count = globalADCount;
+ }
+ // that's it
+}
+
+int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) {
+ int count = MAX_AUDIO_DEVICES;
+ int ret = 0;
+
+ getAudioDevices(globalADPaths, &count);
+ if (index>=0 && index < count) {
+ ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames);
+ }
+ return ret;
+}
+
+int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) {
+ int fd;
+ int mixerMode;
+ int len;
+ audio_info_t info;
+ audio_device_t deviceInfo;
+
+ strncpy(adDesc->path, path, MAX_NAME_LENGTH);
+ adDesc->path[MAX_NAME_LENGTH] = 0;
+ strcpy(adDesc->pathctl, adDesc->path);
+ strcat(adDesc->pathctl, "ctl");
+ strcpy(adDesc->name, adDesc->path);
+ adDesc->vendor[0] = 0;
+ adDesc->version[0] = 0;
+ adDesc->description[0] = 0;
+ adDesc->maxSimulLines = 1;
+
+ // try to open the pseudo device and get more information
+ fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK);
+ if (fd >= 0) {
+ close(fd);
+ if (getNames) {
+ fd = open(adDesc->pathctl, O_RDONLY);
+ if (fd >= 0) {
+ if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) {
+ strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN);
+ adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0;
+ strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN);
+ adDesc->version[MAX_AUDIO_DEV_LEN] = 0;
+ /* add config string to the dev name
+ * creates a string like "/dev/audio (onboard1)"
+ */
+ len = strlen(adDesc->name) + 1;
+ if (MAX_NAME_LENGTH - len > 3) {
+ strcat(adDesc->name, " (");
+ strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len);
+ strcat(adDesc->name, ")");
+ }
+ adDesc->name[MAX_NAME_LENGTH-1] = 0;
+ }
+ if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) {
+ if (mixerMode == AM_MIXER_MODE) {
+ TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path);
+ adDesc->maxSimulLines = -1;
+ }
+ } else {
+ ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path);
+ }
+ close(fd);
+ } else {
+ ERROR1("could not open %s!\n", adDesc->pathctl);
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h Fri Mar 23 09:51:02 2018 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <Utilities.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+/* does not work on Solaris 2.7 */
+#include <sys/audio.h>
+#include <sys/mixer.h>
+#include <sys/types.h>
+#ifndef __linux__
+#include <stropts.h>
+#endif
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//#define USE_ERROR
-//#define USE_TRACE
-
-#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
-
-static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) {
-#ifdef USE_ERROR
- va_list args;
- va_start(args, fmt);
- printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err));
- if (strlen(fmt) > 0) {
- vprintf(fmt, args);
- }
- va_end(args);
-#endif
-}
-
-static int alsa_inited = 0;
-static int alsa_enumerate_pcm_subdevices = FALSE; // default: no
-static int alsa_enumerate_midi_subdevices = FALSE; // default: no
-
-void initAlsaSupport() {
- char* enumerate;
- if (!alsa_inited) {
- alsa_inited = TRUE;
- snd_lib_error_set_handler(&alsaDebugOutput);
-
- enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES);
- if (enumerate != NULL && strlen(enumerate) > 0
- && (enumerate[0] != 'f') // false
- && (enumerate[0] != 'F') // False
- && (enumerate[0] != 'n') // no
- && (enumerate[0] != 'N')) { // NO
- alsa_enumerate_pcm_subdevices = TRUE;
- }
-#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES
- alsa_enumerate_midi_subdevices = TRUE;
-#endif
- }
-}
-
-
-/* if true (non-zero), ALSA sub devices should be listed as separate devices
- */
-int needEnumerateSubdevices(int isMidi) {
- initAlsaSupport();
- return isMidi ? alsa_enumerate_midi_subdevices
- : alsa_enumerate_pcm_subdevices;
-}
-
-
-/*
- * deviceID contains packed card, device and subdevice numbers
- * each number takes 10 bits
- * "default" device has id == ALSA_DEFAULT_DEVICE_ID
- */
-UINT32 encodeDeviceID(int card, int device, int subdevice) {
- return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10)
- | (subdevice & 0x3FF)) + 1;
-}
-
-
-void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
- int isMidi) {
- deviceID--;
- *card = (deviceID >> 20) & 0x3FF;
- *device = (deviceID >> 10) & 0x3FF;
- if (needEnumerateSubdevices(isMidi)) {
- *subdevice = deviceID & 0x3FF;
- } else {
- *subdevice = -1; // ALSA will choose any subdevices
- }
-}
-
-
-void getDeviceString(char* buffer, int card, int device, int subdevice,
- int usePlugHw, int isMidi) {
- if (needEnumerateSubdevices(isMidi)) {
- sprintf(buffer, "%s:%d,%d,%d",
- usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
- card, device, subdevice);
- } else {
- sprintf(buffer, "%s:%d,%d",
- usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
- card, device);
- }
-}
-
-
-void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
- int usePlugHw, int isMidi) {
- int card, device, subdevice;
-
- if (deviceID == ALSA_DEFAULT_DEVICE_ID) {
- strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME);
- } else {
- decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi);
- getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi);
- }
-}
-
-
-static int hasGottenALSAVersion = FALSE;
-#define ALSAVersionString_LENGTH 200
-static char ALSAVersionString[ALSAVersionString_LENGTH];
-
-void getALSAVersion(char* buffer, int len) {
- if (!hasGottenALSAVersion) {
- // get alsa version from proc interface
- FILE* file;
- int curr, len, totalLen, inVersionString;
- file = fopen(ALSA_VERSION_PROC_FILE, "r");
- ALSAVersionString[0] = 0;
- if (file) {
- if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) {
- // parse for version number
- totalLen = strlen(ALSAVersionString);
- inVersionString = FALSE;
- len = 0;
- curr = 0;
- while (curr < totalLen) {
- if (!inVersionString) {
- // is this char the beginning of a version string ?
- if (ALSAVersionString[curr] >= '0'
- && ALSAVersionString[curr] <= '9') {
- inVersionString = TRUE;
- }
- }
- if (inVersionString) {
- // the version string ends with white space
- if (ALSAVersionString[curr] <= 32) {
- break;
- }
- if (curr != len) {
- // copy this char to the beginning of the string
- ALSAVersionString[len] = ALSAVersionString[curr];
- }
- len++;
- }
- curr++;
- }
- // remove trailing dots
- while ((len > 0) && (ALSAVersionString[len - 1] == '.')) {
- len--;
- }
- // null terminate
- ALSAVersionString[len] = 0;
- }
- fclose(file);
- hasGottenALSAVersion = TRUE;
- }
- }
- strncpy(buffer, ALSAVersionString, len);
-}
-
-
-/* end */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiIn.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#if USE_PLATFORM_MIDI_IN == TRUE
-
-
-#include <alsa/asoundlib.h>
-#include "PlatformMidi.h"
-#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h"
-#if defined(i586)
-#include <sys/utsname.h>
-#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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiOut.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#if USE_PLATFORM_MIDI_OUT == TRUE
-
-#include <alsa/asoundlib.h>
-#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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h"
-#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
-#include <string.h>
-#include <sys/time.h>
-
-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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCM.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,941 +0,0 @@
-/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_BsdOS_ALSA_PCMUtils.h"
-#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
-#include "DirectAudio.h"
-
-#if USE_DAUDIO == TRUE
-
-// GetPosition method 1: based on how many bytes are passed to the kernel driver
-// + does not need much processor resources
-// - not very exact, "jumps"
-// GetPosition method 2: ask kernel about actual position of playback.
-// - very exact
-// - switch to kernel layer for each call
-// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA
-// quick tests on a Pentium 200MMX showed max. 1.5% processor usage
-// for playing back a CD-quality file and printing 20x per second a line
-// on the console with the current time. So I guess performance is not such a
-// factor here.
-//#define GET_POSITION_METHOD1
-#define GET_POSITION_METHOD2
-
-
-// The default time for a period in microseconds.
-// For very small buffers, only 2 periods are used.
-#define DEFAULT_PERIOD_TIME 20000 /* 20ms */
-
-///// implemented functions of DirectAudio.h
-
-INT32 DAUDIO_GetDirectAudioDeviceCount() {
- return (INT32) getAudioDeviceCount();
-}
-
-
-INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) {
- ALSA_AudioDeviceDescription adesc;
-
- adesc.index = (int) mixerIndex;
- adesc.strLen = DAUDIO_STRING_LENGTH;
-
- adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines));
- adesc.deviceID = &(description->deviceID);
- adesc.name = description->name;
- adesc.vendor = description->vendor;
- adesc.description = description->description;
- adesc.version = description->version;
-
- return getAudioDeviceDescriptionByIndex(&adesc);
-}
-
-#define MAX_BIT_INDEX 6
-// returns
-// 6: for anything above 24-bit
-// 5: for 4 bytes sample size, 24-bit
-// 4: for 3 bytes sample size, 24-bit
-// 3: for 3 bytes sample size, 20-bit
-// 2: for 2 bytes sample size, 16-bit
-// 1: for 1 byte sample size, 8-bit
-// 0: for anything else
-int getBitIndex(int sampleSizeInBytes, int significantBits) {
- if (significantBits > 24) return 6;
- if (sampleSizeInBytes == 4 && significantBits == 24) return 5;
- if (sampleSizeInBytes == 3) {
- if (significantBits == 24) return 4;
- if (significantBits == 20) return 3;
- }
- if (sampleSizeInBytes == 2 && significantBits == 16) return 2;
- if (sampleSizeInBytes == 1 && significantBits == 8) return 1;
- return 0;
-}
-
-int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) {
- switch(bitIndex) {
- case 1: return 1;
- case 2: return 2;
- case 3: /* fall through */
- case 4: return 3;
- case 5: return 4;
- }
- return sampleSizeInBytes;
-}
-
-int getSignificantBits(int bitIndex, int significantBits) {
- switch(bitIndex) {
- case 1: return 8;
- case 2: return 16;
- case 3: return 20;
- case 4: /* fall through */
- case 5: return 24;
- }
- return significantBits;
-}
-
-void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
- snd_pcm_t* handle;
- snd_pcm_format_mask_t* formatMask;
- snd_pcm_format_t format;
- snd_pcm_hw_params_t* hwParams;
- int handledBits[MAX_BIT_INDEX+1];
-
- int ret;
- int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc;
- int origSampleSizeInBytes, origSignificantBits;
- unsigned int channels, minChannels, maxChannels;
- int rate, bitIndex;
-
- for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE;
- if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) {
- return;
- }
- ret = snd_pcm_format_mask_malloc(&formatMask);
- if (ret != 0) {
- ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret);
- } else {
- ret = snd_pcm_hw_params_malloc(&hwParams);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- ret = snd_pcm_hw_params_any(handle, hwParams);
- /* snd_pcm_hw_params_any can return a positive value on success too */
- if (ret < 0) {
- ERROR1("snd_pcm_hw_params_any returned error %d\n", ret);
- } else {
- /* for the logic following this code, set ret to 0 to indicate success */
- ret = 0;
- }
- }
- snd_pcm_hw_params_get_format_mask(hwParams, formatMask);
- if (ret == 0) {
- ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret);
- }
- }
- if (ret == 0) {
- ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret);
- }
- }
-
- // since we queried the hw: device, for many soundcards, it will only
- // report the maximum number of channels (which is the only way to talk
- // to the hw: device). Since we will, however, open the plughw: device
- // when opening the Source/TargetDataLine, we can safely assume that
- // also the channels 1..maxChannels are available.
-#ifdef ALSA_PCM_USE_PLUGHW
- minChannels = 1;
-#endif
- if (ret == 0) {
- // plughw: supports any sample rate
- rate = -1;
- for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
- if (snd_pcm_format_mask_test(formatMask, format)) {
- // format exists
- if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes,
- &origSignificantBits,
- &isSigned, &isBigEndian, &enc)) {
- // now if we use plughw:, we can use any bit size below the
- // natively supported ones. Some ALSA drivers only support the maximum
- // bit size, so we add any sample rates below the reported one.
- // E.g. this iteration reports support for 16-bit.
- // getBitIndex will return 2, so it will add entries for
- // 16-bit (bitIndex=2) and in the next do-while loop iteration,
- // it will decrease bitIndex and will therefore add 8-bit support.
- bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits);
- do {
- if (bitIndex == 0
- || bitIndex == MAX_BIT_INDEX
- || !handledBits[bitIndex]) {
- handledBits[bitIndex] = TRUE;
- sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes);
- significantBits = getSignificantBits(bitIndex, origSignificantBits);
- if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) {
- // avoid too many channels explicitly listed
- // just add -1, min, and max
- DAUDIO_AddAudioFormat(creator, significantBits,
- -1, -1, rate,
- enc, isSigned, isBigEndian);
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * minChannels,
- minChannels, rate,
- enc, isSigned, isBigEndian);
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * maxChannels,
- maxChannels, rate,
- enc, isSigned, isBigEndian);
- } else {
- for (channels = minChannels; channels <= maxChannels; channels++) {
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * channels,
- channels, rate,
- enc, isSigned, isBigEndian);
- }
- }
- }
-#ifndef ALSA_PCM_USE_PLUGHW
- // without plugin, do not add fake formats
- break;
-#endif
- } while (--bitIndex > 0);
- } else {
- TRACE1("could not get format from alsa for format %d\n", format);
- }
- } else {
- //TRACE1("Format %d not supported\n", format);
- }
- } // for loop
- snd_pcm_hw_params_free(hwParams);
- }
- snd_pcm_format_mask_free(formatMask);
- }
- snd_pcm_close(handle);
-}
-
-/** Workaround for cr 7033899, 7030629:
- * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty
- * (just opened, underruned or already flushed).
- * Sometimes it causes PCM falls to -EBADFD error,
- * sometimes causes bufferSize change.
- * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used.
- */
-/* ******* ALSA PCM INFO ******************** */
-typedef struct tag_AlsaPcmInfo {
- snd_pcm_t* handle;
- snd_pcm_hw_params_t* hwParams;
- snd_pcm_sw_params_t* swParams;
- int bufferSizeInBytes;
- int frameSize; // storage size in Bytes
- unsigned int periods;
- snd_pcm_uframes_t periodSize;
- short int isRunning; // see comment above
- short int isFlushed; // see comment above
-#ifdef GET_POSITION_METHOD2
- // to be used exclusively by getBytePosition!
- snd_pcm_status_t* positionStatus;
-#endif
-} AlsaPcmInfo;
-
-
-int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) {
- int ret;
- int threshold;
-
- if (useThreshold) {
- // start device whenever anything is written to the buffer
- threshold = 1;
- } else {
- // never start the device automatically
- threshold = 2000000000; /* near UINT_MAX */
- }
- ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold);
- if (ret < 0) {
- ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-int setStartThreshold(AlsaPcmInfo* info, int useThreshold) {
- int ret = 0;
-
- if (!setStartThresholdNoCommit(info, useThreshold)) {
- ret = -1;
- }
- if (ret == 0) {
- // commit it
- ret = snd_pcm_sw_params(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
- }
- }
- return (ret == 0)?TRUE:FALSE;
-}
-
-
-// returns TRUE if successful
-int setHWParams(AlsaPcmInfo* info,
- float sampleRate,
- int channels,
- int bufferSizeInFrames,
- snd_pcm_format_t format) {
- unsigned int rrate, periodTime, periods;
- int ret, dir;
- snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;
-
- /* choose all parameters */
- ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
- if (ret < 0) {
- ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the interleaved read/write format */
- ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (ret < 0) {
- ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the sample format */
- ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
- if (ret < 0) {
- ERROR1("Sample format not available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the count of channels */
- ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
- if (ret < 0) {
- ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
- return FALSE;
- }
- /* set the stream rate */
- rrate = (int) (sampleRate + 0.5f);
- dir = 0;
- ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
- if (ret < 0) {
- ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
- return FALSE;
- }
- if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
- ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
- return FALSE;
- }
- /* set the buffer time */
- ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
- if (ret < 0) {
- ERROR2("Unable to set buffer size to %d frames: %s\n",
- (int) alsaBufferSizeInFrames, snd_strerror(ret));
- return FALSE;
- }
- bufferSizeInFrames = (int) alsaBufferSizeInFrames;
- /* set the period time */
- if (bufferSizeInFrames > 1024) {
- dir = 0;
- periodTime = DEFAULT_PERIOD_TIME;
- ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
- if (ret < 0) {
- ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
- return FALSE;
- }
- } else {
- /* set the period count for very small buffer sizes to 2 */
- dir = 0;
- periods = 2;
- ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
- if (ret < 0) {
- ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
- return FALSE;
- }
- }
- /* write the parameters to device */
- ret = snd_pcm_hw_params(info->handle, info->hwParams);
- if (ret < 0) {
- ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-// returns 1 if successful
-int setSWParams(AlsaPcmInfo* info) {
- int ret;
-
- /* get the current swparams */
- ret = snd_pcm_sw_params_current(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* never start the transfer automatically */
- if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
- return FALSE;
- }
-
- /* allow the transfer when at least period_size samples can be processed */
- ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
- if (ret < 0) {
- ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* write the parameters to the playback device */
- ret = snd_pcm_sw_params(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-static snd_output_t* ALSA_OUTPUT = NULL;
-
-void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
- int encoding, float sampleRate, int sampleSizeInBits,
- int frameSize, int channels,
- int isSigned, int isBigEndian, int bufferSizeInBytes) {
- snd_pcm_format_mask_t* formatMask;
- snd_pcm_format_t format;
- int dir;
- int ret = 0;
- AlsaPcmInfo* info = NULL;
- /* snd_pcm_uframes_t is 64 bit on 64-bit systems */
- snd_pcm_uframes_t alsaBufferSizeInFrames = 0;
-
-
- TRACE0("> DAUDIO_Open\n");
-#ifdef USE_TRACE
- // for using ALSA debug dump methods
- if (ALSA_OUTPUT == NULL) {
- snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0);
- }
-#endif
- if (channels <= 0) {
- ERROR1("ERROR: Invalid number of channels=%d!\n", channels);
- return NULL;
- }
- info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo));
- if (!info) {
- ERROR0("Out of memory\n");
- return NULL;
- }
- memset(info, 0, sizeof(AlsaPcmInfo));
- // initial values are: stopped, flushed
- info->isRunning = 0;
- info->isFlushed = 1;
-
- ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
- if (ret == 0) {
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- ret = snd_pcm_hw_params_malloc(&(info->hwParams));
- if (ret != 0) {
- ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- ret = -1;
- if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits,
- isSigned, isBigEndian, encoding)) {
- if (setHWParams(info,
- sampleRate,
- channels,
- bufferSizeInBytes / frameSize,
- format)) {
- info->frameSize = frameSize;
- ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret));
- }
- snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir);
- snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames);
- info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize;
- TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n",
- (int) info->periodSize, info->periods, info->bufferSizeInBytes);
- }
- }
- }
- if (ret == 0) {
- // set software parameters
- ret = snd_pcm_sw_params_malloc(&(info->swParams));
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- if (!setSWParams(info)) {
- ret = -1;
- }
- }
- }
- if (ret == 0) {
- // prepare device
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
- }
- }
-
-#ifdef GET_POSITION_METHOD2
- if (ret == 0) {
- ret = snd_pcm_status_malloc(&(info->positionStatus));
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret));
- }
- }
-#endif
- }
- if (ret != 0) {
- DAUDIO_Close((void*) info, isSource);
- info = NULL;
- } else {
- // set to non-blocking mode
- snd_pcm_nonblock(info->handle, 1);
- TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n",
- (void*) info->handle);
- }
- return (void*) info;
-}
-
-#ifdef USE_TRACE
-void printState(snd_pcm_state_t state) {
- if (state == SND_PCM_STATE_OPEN) {
- TRACE0("State: SND_PCM_STATE_OPEN\n");
- }
- else if (state == SND_PCM_STATE_SETUP) {
- TRACE0("State: SND_PCM_STATE_SETUP\n");
- }
- else if (state == SND_PCM_STATE_PREPARED) {
- TRACE0("State: SND_PCM_STATE_PREPARED\n");
- }
- else if (state == SND_PCM_STATE_RUNNING) {
- TRACE0("State: SND_PCM_STATE_RUNNING\n");
- }
- else if (state == SND_PCM_STATE_XRUN) {
- TRACE0("State: SND_PCM_STATE_XRUN\n");
- }
- else if (state == SND_PCM_STATE_DRAINING) {
- TRACE0("State: SND_PCM_STATE_DRAINING\n");
- }
- else if (state == SND_PCM_STATE_PAUSED) {
- TRACE0("State: SND_PCM_STATE_PAUSED\n");
- }
- else if (state == SND_PCM_STATE_SUSPENDED) {
- TRACE0("State: SND_PCM_STATE_SUSPENDED\n");
- }
-}
-#endif
-
-int DAUDIO_Start(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
- snd_pcm_state_t state;
-
- TRACE0("> DAUDIO_Start\n");
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- // set start mode so that it always starts as soon as data is there
- setStartThreshold(info, TRUE /* use threshold */);
- state = snd_pcm_state(info->handle);
- if (state == SND_PCM_STATE_PAUSED) {
- // in case it was stopped previously
- TRACE0(" Un-pausing...\n");
- ret = snd_pcm_pause(info->handle, FALSE);
- if (ret != 0) {
- ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret));
- }
- }
- if (state == SND_PCM_STATE_SUSPENDED) {
- TRACE0(" Resuming...\n");
- ret = snd_pcm_resume(info->handle);
- if (ret < 0) {
- if ((ret != -EAGAIN) && (ret != -ENOSYS)) {
- ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret));
- }
- }
- }
- if (state == SND_PCM_STATE_SETUP) {
- TRACE0("need to call prepare again...\n");
- // prepare device
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
- }
- }
- // in case there is still data in the buffers
- ret = snd_pcm_start(info->handle);
- if (ret != 0) {
- if (ret != -EPIPE) {
- ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret));
- }
- }
- // set to non-blocking mode
- ret = snd_pcm_nonblock(info->handle, 1);
- if (ret != 0) {
- ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret));
- }
- state = snd_pcm_state(info->handle);
-#ifdef USE_TRACE
- printState(state);
-#endif
- ret = (state == SND_PCM_STATE_PREPARED)
- || (state == SND_PCM_STATE_RUNNING)
- || (state == SND_PCM_STATE_XRUN)
- || (state == SND_PCM_STATE_SUSPENDED);
- if (ret) {
- info->isRunning = 1;
- // source line should keep isFlushed value until Write() is called;
- // for target data line reset it right now.
- if (!isSource) {
- info->isFlushed = 0;
- }
- }
- TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
- return ret?TRUE:FALSE;
-}
-
-int DAUDIO_Stop(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
-
- TRACE0("> DAUDIO_Stop\n");
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun
- ret = snd_pcm_pause(info->handle, 1);
- // set to non-blocking mode
- snd_pcm_nonblock(info->handle, 1);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
- return FALSE;
- }
- info->isRunning = 0;
- TRACE0("< DAUDIO_Stop success\n");
- return TRUE;
-}
-
-void DAUDIO_Close(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
-
- TRACE0("DAUDIO_Close\n");
- if (info != NULL) {
- if (info->handle != NULL) {
- snd_pcm_close(info->handle);
- }
- if (info->hwParams) {
- snd_pcm_hw_params_free(info->hwParams);
- }
- if (info->swParams) {
- snd_pcm_sw_params_free(info->swParams);
- }
-#ifdef GET_POSITION_METHOD2
- if (info->positionStatus) {
- snd_pcm_status_free(info->positionStatus);
- }
-#endif
- free(info);
- }
-}
-
-/*
- * Underrun and suspend recovery
- * returns
- * 0: exit native and return 0
- * 1: try again to write/read
- * -1: error - exit native with return value -1
- */
-int xrun_recovery(AlsaPcmInfo* info, int err) {
- int ret;
-
- if (err == -EPIPE) { /* underrun / overflow */
- TRACE0("xrun_recovery: underrun/overflow.\n");
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
- return -1;
- }
- return 1;
- } else if (err == -ESTRPIPE) {
- TRACE0("xrun_recovery: suspended.\n");
- ret = snd_pcm_resume(info->handle);
- if (ret < 0) {
- if (ret == -EAGAIN) {
- return 0; /* wait until the suspend flag is released */
- }
- return -1;
- }
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
- return -1;
- }
- return 1;
- } else if (err == -EAGAIN) {
- TRACE0("xrun_recovery: EAGAIN try again flag.\n");
- return 0;
- }
-
- TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
- return -1;
-}
-
-// returns -1 on error
-int DAUDIO_Write(void* id, char* data, int byteSize) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret, count;
- snd_pcm_sframes_t frameSize, writtenFrames;
-
- TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
-
- /* sanity */
- if (byteSize <= 0 || info->frameSize <= 0) {
- ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n",
- (int) byteSize, (int) info->frameSize);
- TRACE0("< DAUDIO_Write returning -1\n");
- return -1;
- }
-
- count = 2; // maximum number of trials to recover from underrun
- //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
- frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
- do {
- writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize);
-
- if (writtenFrames < 0) {
- ret = xrun_recovery(info, (int) writtenFrames);
- if (ret <= 0) {
- TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret);
- return ret;
- }
- if (count-- <= 0) {
- ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n");
- return -1;
- }
- } else {
- break;
- }
- } while (TRUE);
- //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames);
-
- if (writtenFrames > 0) {
- // reset "flushed" flag
- info->isFlushed = 0;
- }
-
- ret = (int) (writtenFrames * info->frameSize);
- TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
- return ret;
-}
-
-// returns -1 on error
-int DAUDIO_Read(void* id, char* data, int byteSize) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret, count;
- snd_pcm_sframes_t frameSize, readFrames;
-
- TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
- /*TRACE3(" info=%p, data=%p, byteSize=%d\n",
- (void*) info, (void*) data, (int) byteSize);
- TRACE2(" info->frameSize=%d, info->handle=%p\n",
- (int) info->frameSize, (void*) info->handle);
- */
- /* sanity */
- if (byteSize <= 0 || info->frameSize <= 0) {
- ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n",
- (int) byteSize, (int) info->frameSize);
- TRACE0("< DAUDIO_Read returning -1\n");
- return -1;
- }
- if (!info->isRunning && info->isFlushed) {
- // PCM has nothing to read
- return 0;
- }
-
- count = 2; // maximum number of trials to recover from error
- //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
- frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
- do {
- readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize);
- if (readFrames < 0) {
- ret = xrun_recovery(info, (int) readFrames);
- if (ret <= 0) {
- TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret);
- return ret;
- }
- if (count-- <= 0) {
- ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n");
- return -1;
- }
- } else {
- break;
- }
- } while (TRUE);
- //ret = snd_pcm_frames_to_bytes(info->handle, readFrames);
- ret = (int) (readFrames * info->frameSize);
- TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
- return ret;
-}
-
-
-int DAUDIO_GetBufferSize(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
-
- return info->bufferSizeInBytes;
-}
-
-int DAUDIO_StillDraining(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- snd_pcm_state_t state;
-
- state = snd_pcm_state(info->handle);
- //printState(state);
- //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE");
- return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE;
-}
-
-
-int DAUDIO_Flush(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
-
- TRACE0("DAUDIO_Flush\n");
-
- if (info->isFlushed) {
- // nothing to drop
- return 1;
- }
-
- ret = snd_pcm_drop(info->handle);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
- return FALSE;
- }
-
- info->isFlushed = 1;
- if (info->isRunning) {
- ret = DAUDIO_Start(id, isSource);
- }
- return ret;
-}
-
-int DAUDIO_GetAvailable(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- snd_pcm_sframes_t availableInFrames;
- snd_pcm_state_t state;
- int ret;
-
- state = snd_pcm_state(info->handle);
- if (info->isFlushed || state == SND_PCM_STATE_XRUN) {
- // if in xrun state then we have the entire buffer available,
- // not 0 as alsa reports
- ret = info->bufferSizeInBytes;
- } else {
- availableInFrames = snd_pcm_avail_update(info->handle);
- if (availableInFrames < 0) {
- ret = 0;
- } else {
- //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames);
- ret = (int) (availableInFrames * info->frameSize);
- }
- }
- TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
- return ret;
-}
-
-INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) {
- // estimate the current position with the buffer size and
- // the available bytes to read or write in the buffer.
- // not an elegant solution - bytePos will stop on xruns,
- // and in race conditions it may jump backwards
- // Advantage is that it is indeed based on the samples that go through
- // the system (rather than time-based methods)
- if (isSource) {
- // javaBytePos is the position that is reached when the current
- // buffer is played completely
- return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes);
- } else {
- // javaBytePos is the position that was when the current buffer was empty
- return (INT64) (javaBytePos + availInBytes);
- }
-}
-
-INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
- INT64 result = javaBytePos;
- snd_pcm_state_t state;
- state = snd_pcm_state(info->handle);
-
- if (!info->isFlushed && state != SND_PCM_STATE_XRUN) {
-#ifdef GET_POSITION_METHOD2
- snd_timestamp_t* ts;
- snd_pcm_uframes_t framesAvail;
-
- // note: slight race condition if this is called simultaneously from 2 threads
- ret = snd_pcm_status(info->handle, info->positionStatus);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret));
- result = javaBytePos;
- } else {
- // calculate from time value, or from available bytes
- framesAvail = snd_pcm_status_get_avail(info->positionStatus);
- result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
- }
-#endif
-#ifdef GET_POSITION_METHOD3
- snd_pcm_uframes_t framesAvail;
- ret = snd_pcm_avail(info->handle, &framesAvail);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret));
- result = javaBytePos;
- } else {
- result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
- }
-#endif
-#ifdef GET_POSITION_METHOD1
- result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource));
-#endif
- }
- //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
- return result;
-}
-
-
-
-void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- /* save to ignore, since GetBytePosition
- * takes the javaBytePos param into account
- */
-}
-
-int DAUDIO_RequiresServicing(void* id, int isSource) {
- // never need servicing on Bsd
- return FALSE;
-}
-
-void DAUDIO_Service(void* id, int isSource) {
- // never need servicing on Bsd
-}
-
-
-#endif // USE_DAUDIO
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,292 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//#define USE_ERROR
-//#define USE_TRACE
-
-#include "PLATFORM_API_BsdOS_ALSA_PCMUtils.h"
-#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
-
-
-
-// callback for iteration through devices
-// returns TRUE if iteration should continue
-// NOTE: cardinfo may be NULL (for "default" device)
-typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo,
- snd_ctl_card_info_t* cardinfo, void *userData);
-
-// for each ALSA device, call iterator. userData is passed to the iterator
-// returns total number of iterations
-int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) {
- int count = 0;
- int subdeviceCount;
- int card, dev, subDev;
- char devname[16];
- int err;
- snd_ctl_t *handle;
- snd_pcm_t *pcm;
- snd_pcm_info_t* pcminfo;
- snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL;
- UINT32 deviceID;
- int doContinue = TRUE;
-
- snd_pcm_info_malloc(&pcminfo);
- snd_ctl_card_info_malloc(&cardinfo);
-
- // 1st try "default" device
- err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
- if (err < 0) {
- // try with the other direction
- err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
- SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
- }
- if (err < 0) {
- ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err));
- } else {
- err = snd_pcm_info(pcm, pcminfo);
- snd_pcm_close(pcm);
- if (err < 0) {
- ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n",
- snd_strerror(err));
- } else {
- // try to get card info
- card = snd_pcm_info_get_card(pcminfo);
- if (card >= 0) {
- sprintf(devname, ALSA_HARDWARE_CARD, card);
- if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) {
- if (snd_ctl_card_info(handle, cardinfo) >= 0) {
- defcardinfo = cardinfo;
- }
- snd_ctl_close(handle);
- }
- }
- // call callback function for the device
- if (iterator != NULL) {
- doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo,
- defcardinfo, userData);
- }
- count++;
- }
- }
-
- // iterate cards
- card = -1;
- while (doContinue) {
- if (snd_card_next(&card) < 0) {
- break;
- }
- if (card < 0) {
- break;
- }
- sprintf(devname, ALSA_HARDWARE_CARD, card);
- TRACE1("Opening alsa device \"%s\"...\n", devname);
- err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK);
- if (err < 0) {
- ERROR2("ERROR: snd_ctl_open, card=%d: %s\n",
- card, snd_strerror(err));
- } else {
- err = snd_ctl_card_info(handle, cardinfo);
- if (err < 0) {
- ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n",
- card, snd_strerror(err));
- } else {
- dev = -1;
- while (doContinue) {
- if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
- ERROR0("snd_ctl_pcm_next_device\n");
- }
- if (dev < 0) {
- break;
- }
- snd_pcm_info_set_device(pcminfo, dev);
- snd_pcm_info_set_subdevice(pcminfo, 0);
- snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
- err = snd_ctl_pcm_info(handle, pcminfo);
- if (err == -ENOENT) {
- // try with the other direction
- snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
- err = snd_ctl_pcm_info(handle, pcminfo);
- }
- if (err < 0) {
- if (err != -ENOENT) {
- ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s",
- card, snd_strerror(err));
- }
- } else {
- subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ?
- snd_pcm_info_get_subdevices_count(pcminfo) : 1;
- if (iterator!=NULL) {
- for (subDev = 0; subDev < subdeviceCount; subDev++) {
- deviceID = encodeDeviceID(card, dev, subDev);
- doContinue = (*iterator)(deviceID, pcminfo,
- cardinfo, userData);
- count++;
- if (!doContinue) {
- break;
- }
- }
- } else {
- count += subdeviceCount;
- }
- }
- } // of while(doContinue)
- }
- snd_ctl_close(handle);
- }
- }
- snd_ctl_card_info_free(cardinfo);
- snd_pcm_info_free(pcminfo);
- return count;
-}
-
-int getAudioDeviceCount() {
- initAlsaSupport();
- return iteratePCMDevices(NULL, NULL);
-}
-
-int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo,
- snd_ctl_card_info_t* cardinfo, void* userData) {
- char buffer[300];
- ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData;
-#ifdef ALSA_PCM_USE_PLUGHW
- int usePlugHw = 1;
-#else
- int usePlugHw = 0;
-#endif
-
- initAlsaSupport();
- if (desc->index == 0) {
- // we found the device with correct index
- *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ?
- 1 : snd_pcm_info_get_subdevices_count(pcminfo);
- *desc->deviceID = deviceID;
- buffer[0]=' '; buffer[1]='[';
- // buffer[300] is enough to store the actual device string w/o overrun
- getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM);
- strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
- strncpy(desc->name,
- (cardinfo != NULL)
- ? snd_ctl_card_info_get_id(cardinfo)
- : snd_pcm_info_get_id(pcminfo),
- desc->strLen - strlen(buffer));
- strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
- strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen);
- strncpy(desc->description,
- (cardinfo != NULL)
- ? snd_ctl_card_info_get_name(cardinfo)
- : snd_pcm_info_get_name(pcminfo),
- desc->strLen);
- strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
- strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description));
- strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
- strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description));
- getALSAVersion(desc->version, desc->strLen);
- TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version);
- return FALSE; // do not continue iteration
- }
- desc->index--;
- return TRUE;
-}
-
-// returns 0 if successful
-int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) {
- char buffer[200];
- int ret;
-
- initAlsaSupport();
- getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM);
-
- TRACE1("Opening ALSA device %s\n", buffer);
- ret = snd_pcm_open(handle, buffer,
- isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE,
- SND_PCM_NONBLOCK);
- if (ret != 0) {
- ERROR1("snd_pcm_open returned error code %d \n", ret);
- *handle = NULL;
- }
- return ret;
-}
-
-
-int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) {
- initAlsaSupport();
- TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index);
- iteratePCMDevices(&deviceInfoIterator, desc);
- return (desc->index == 0)?TRUE:FALSE;
-}
-
-// returns 1 if successful
-// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h)
-int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat,
- int* sampleSizeInBytes, int* significantBits,
- int* isSigned, int* isBigEndian, int* enc) {
-
- *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8;
- *significantBits = snd_pcm_format_width(alsaFormat);
-
- // defaults
- *enc = 0; // PCM
- *isSigned = (snd_pcm_format_signed(alsaFormat) > 0);
- *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0);
-
- // non-PCM formats
- if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law
- *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes;
- }
- else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law
- *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes;
- }
- else if (snd_pcm_format_linear(alsaFormat) < 1) {
- return 0;
- }
- return (*sampleSizeInBytes > 0);
-}
-
-// returns 1 if successful
-int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat,
- int sampleSizeInBytes, int significantBits,
- int isSigned, int isBigEndian, int enc) {
- *alsaFormat = SND_PCM_FORMAT_UNKNOWN;
-
- if (enc == 0) {
- *alsaFormat = snd_pcm_build_linear_format(significantBits,
- sampleSizeInBytes * 8,
- isSigned?0:1,
- isBigEndian?1:0);
- }
- else if ((sampleSizeInBytes == 1) && (significantBits == 8)) {
- if (enc == 1) { // ULAW
- *alsaFormat = SND_PCM_FORMAT_MU_LAW;
- }
- else if (enc == 2) { // ALAW
- *alsaFormat = SND_PCM_FORMAT_A_LAW;
- }
- }
- return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1;
-}
-
-
-/* end */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// define this with a later version of ALSA than 0.9.0rc3
-// (starting from 1.0.0 it became default behaviour)
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,724 +0,0 @@
-/*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-//#define USE_TRACE
-
-#include "Ports.h"
-#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
-#include <alsa/asoundlib.h>
-
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//#define USE_ERROR
-//#define USE_TRACE
-
-#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
-
-static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) {
-#ifdef USE_ERROR
- va_list args;
- va_start(args, fmt);
- printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err));
- if (strlen(fmt) > 0) {
- vprintf(fmt, args);
- }
- va_end(args);
-#endif
-}
-
-static int alsa_inited = 0;
-static int alsa_enumerate_pcm_subdevices = FALSE; // default: no
-static int alsa_enumerate_midi_subdevices = FALSE; // default: no
-
-/*
- * Declare library specific JNI_Onload entry if static build
- */
-DEF_STATIC_JNI_OnLoad
-
-void initAlsaSupport() {
- char* enumerate;
- if (!alsa_inited) {
- alsa_inited = TRUE;
- snd_lib_error_set_handler(&alsaDebugOutput);
-
- enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES);
- if (enumerate != NULL && strlen(enumerate) > 0
- && (enumerate[0] != 'f') // false
- && (enumerate[0] != 'F') // False
- && (enumerate[0] != 'n') // no
- && (enumerate[0] != 'N')) { // NO
- alsa_enumerate_pcm_subdevices = TRUE;
- }
-#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES
- alsa_enumerate_midi_subdevices = TRUE;
-#endif
- }
-}
-
-
-/* if true (non-zero), ALSA sub devices should be listed as separate devices
- */
-int needEnumerateSubdevices(int isMidi) {
- initAlsaSupport();
- return isMidi ? alsa_enumerate_midi_subdevices
- : alsa_enumerate_pcm_subdevices;
-}
-
-
-/*
- * deviceID contains packed card, device and subdevice numbers
- * each number takes 10 bits
- * "default" device has id == ALSA_DEFAULT_DEVICE_ID
- */
-UINT32 encodeDeviceID(int card, int device, int subdevice) {
- return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10)
- | (subdevice & 0x3FF)) + 1;
-}
-
-
-void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
- int isMidi) {
- deviceID--;
- *card = (deviceID >> 20) & 0x3FF;
- *device = (deviceID >> 10) & 0x3FF;
- if (needEnumerateSubdevices(isMidi)) {
- *subdevice = deviceID & 0x3FF;
- } else {
- *subdevice = -1; // ALSA will choose any subdevices
- }
-}
-
-
-void getDeviceString(char* buffer, int card, int device, int subdevice,
- int usePlugHw, int isMidi) {
- if (needEnumerateSubdevices(isMidi)) {
- sprintf(buffer, "%s:%d,%d,%d",
- usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
- card, device, subdevice);
- } else {
- sprintf(buffer, "%s:%d,%d",
- usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
- card, device);
- }
-}
-
-
-void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
- int usePlugHw, int isMidi) {
- int card, device, subdevice;
-
- if (deviceID == ALSA_DEFAULT_DEVICE_ID) {
- strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME);
- } else {
- decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi);
- getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi);
- }
-}
-
-
-static int hasGottenALSAVersion = FALSE;
-#define ALSAVersionString_LENGTH 200
-static char ALSAVersionString[ALSAVersionString_LENGTH];
-
-void getALSAVersion(char* buffer, int len) {
- if (!hasGottenALSAVersion) {
- // get alsa version from proc interface
- FILE* file;
- int curr, len, totalLen, inVersionString;
- file = fopen(ALSA_VERSION_PROC_FILE, "r");
- ALSAVersionString[0] = 0;
- if (file) {
- if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) {
- // parse for version number
- totalLen = strlen(ALSAVersionString);
- inVersionString = FALSE;
- len = 0;
- curr = 0;
- while (curr < totalLen) {
- if (!inVersionString) {
- // is this char the beginning of a version string ?
- if (ALSAVersionString[curr] >= '0'
- && ALSAVersionString[curr] <= '9') {
- inVersionString = TRUE;
- }
- }
- if (inVersionString) {
- // the version string ends with white space
- if (ALSAVersionString[curr] <= 32) {
- break;
- }
- if (curr != len) {
- // copy this char to the beginning of the string
- ALSAVersionString[len] = ALSAVersionString[curr];
- }
- len++;
- }
- curr++;
- }
- // remove trailing dots
- while ((len > 0) && (ALSAVersionString[len - 1] == '.')) {
- len--;
- }
- // null terminate
- ALSAVersionString[len] = 0;
- }
- fclose(file);
- hasGottenALSAVersion = TRUE;
- }
- }
- strncpy(buffer, ALSAVersionString, len);
-}
-
-
-/* end */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#if USE_PLATFORM_MIDI_IN == TRUE
-
-
-#include <alsa/asoundlib.h>
-#include "PlatformMidi.h"
-#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h"
-#if defined(i586)
-#include <sys/utsname.h>
-#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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#if USE_PLATFORM_MIDI_OUT == TRUE
-
-#include <alsa/asoundlib.h>
-#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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h"
-#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
-#include <string.h>
-#include <sys/time.h>
-
-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 */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,941 +0,0 @@
-/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_LinuxOS_ALSA_PCMUtils.h"
-#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
-#include "DirectAudio.h"
-
-#if USE_DAUDIO == TRUE
-
-// GetPosition method 1: based on how many bytes are passed to the kernel driver
-// + does not need much processor resources
-// - not very exact, "jumps"
-// GetPosition method 2: ask kernel about actual position of playback.
-// - very exact
-// - switch to kernel layer for each call
-// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA
-// quick tests on a Pentium 200MMX showed max. 1.5% processor usage
-// for playing back a CD-quality file and printing 20x per second a line
-// on the console with the current time. So I guess performance is not such a
-// factor here.
-//#define GET_POSITION_METHOD1
-#define GET_POSITION_METHOD2
-
-
-// The default time for a period in microseconds.
-// For very small buffers, only 2 periods are used.
-#define DEFAULT_PERIOD_TIME 20000 /* 20ms */
-
-///// implemented functions of DirectAudio.h
-
-INT32 DAUDIO_GetDirectAudioDeviceCount() {
- return (INT32) getAudioDeviceCount();
-}
-
-
-INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) {
- ALSA_AudioDeviceDescription adesc;
-
- adesc.index = (int) mixerIndex;
- adesc.strLen = DAUDIO_STRING_LENGTH;
-
- adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines));
- adesc.deviceID = &(description->deviceID);
- adesc.name = description->name;
- adesc.vendor = description->vendor;
- adesc.description = description->description;
- adesc.version = description->version;
-
- return getAudioDeviceDescriptionByIndex(&adesc);
-}
-
-#define MAX_BIT_INDEX 6
-// returns
-// 6: for anything above 24-bit
-// 5: for 4 bytes sample size, 24-bit
-// 4: for 3 bytes sample size, 24-bit
-// 3: for 3 bytes sample size, 20-bit
-// 2: for 2 bytes sample size, 16-bit
-// 1: for 1 byte sample size, 8-bit
-// 0: for anything else
-int getBitIndex(int sampleSizeInBytes, int significantBits) {
- if (significantBits > 24) return 6;
- if (sampleSizeInBytes == 4 && significantBits == 24) return 5;
- if (sampleSizeInBytes == 3) {
- if (significantBits == 24) return 4;
- if (significantBits == 20) return 3;
- }
- if (sampleSizeInBytes == 2 && significantBits == 16) return 2;
- if (sampleSizeInBytes == 1 && significantBits == 8) return 1;
- return 0;
-}
-
-int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) {
- switch(bitIndex) {
- case 1: return 1;
- case 2: return 2;
- case 3: /* fall through */
- case 4: return 3;
- case 5: return 4;
- }
- return sampleSizeInBytes;
-}
-
-int getSignificantBits(int bitIndex, int significantBits) {
- switch(bitIndex) {
- case 1: return 8;
- case 2: return 16;
- case 3: return 20;
- case 4: /* fall through */
- case 5: return 24;
- }
- return significantBits;
-}
-
-void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
- snd_pcm_t* handle;
- snd_pcm_format_mask_t* formatMask;
- snd_pcm_format_t format;
- snd_pcm_hw_params_t* hwParams;
- int handledBits[MAX_BIT_INDEX+1];
-
- int ret;
- int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc;
- int origSampleSizeInBytes, origSignificantBits;
- unsigned int channels, minChannels, maxChannels;
- int rate, bitIndex;
-
- for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE;
- if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) {
- return;
- }
- ret = snd_pcm_format_mask_malloc(&formatMask);
- if (ret != 0) {
- ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret);
- } else {
- ret = snd_pcm_hw_params_malloc(&hwParams);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- ret = snd_pcm_hw_params_any(handle, hwParams);
- /* snd_pcm_hw_params_any can return a positive value on success too */
- if (ret < 0) {
- ERROR1("snd_pcm_hw_params_any returned error %d\n", ret);
- } else {
- /* for the logic following this code, set ret to 0 to indicate success */
- ret = 0;
- }
- }
- snd_pcm_hw_params_get_format_mask(hwParams, formatMask);
- if (ret == 0) {
- ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret);
- }
- }
- if (ret == 0) {
- ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels);
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret);
- }
- }
-
- // since we queried the hw: device, for many soundcards, it will only
- // report the maximum number of channels (which is the only way to talk
- // to the hw: device). Since we will, however, open the plughw: device
- // when opening the Source/TargetDataLine, we can safely assume that
- // also the channels 1..maxChannels are available.
-#ifdef ALSA_PCM_USE_PLUGHW
- minChannels = 1;
-#endif
- if (ret == 0) {
- // plughw: supports any sample rate
- rate = -1;
- for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
- if (snd_pcm_format_mask_test(formatMask, format)) {
- // format exists
- if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes,
- &origSignificantBits,
- &isSigned, &isBigEndian, &enc)) {
- // now if we use plughw:, we can use any bit size below the
- // natively supported ones. Some ALSA drivers only support the maximum
- // bit size, so we add any sample rates below the reported one.
- // E.g. this iteration reports support for 16-bit.
- // getBitIndex will return 2, so it will add entries for
- // 16-bit (bitIndex=2) and in the next do-while loop iteration,
- // it will decrease bitIndex and will therefore add 8-bit support.
- bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits);
- do {
- if (bitIndex == 0
- || bitIndex == MAX_BIT_INDEX
- || !handledBits[bitIndex]) {
- handledBits[bitIndex] = TRUE;
- sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes);
- significantBits = getSignificantBits(bitIndex, origSignificantBits);
- if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) {
- // avoid too many channels explicitly listed
- // just add -1, min, and max
- DAUDIO_AddAudioFormat(creator, significantBits,
- -1, -1, rate,
- enc, isSigned, isBigEndian);
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * minChannels,
- minChannels, rate,
- enc, isSigned, isBigEndian);
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * maxChannels,
- maxChannels, rate,
- enc, isSigned, isBigEndian);
- } else {
- for (channels = minChannels; channels <= maxChannels; channels++) {
- DAUDIO_AddAudioFormat(creator, significantBits,
- sampleSizeInBytes * channels,
- channels, rate,
- enc, isSigned, isBigEndian);
- }
- }
- }
-#ifndef ALSA_PCM_USE_PLUGHW
- // without plugin, do not add fake formats
- break;
-#endif
- } while (--bitIndex > 0);
- } else {
- TRACE1("could not get format from alsa for format %d\n", format);
- }
- } else {
- //TRACE1("Format %d not supported\n", format);
- }
- } // for loop
- snd_pcm_hw_params_free(hwParams);
- }
- snd_pcm_format_mask_free(formatMask);
- }
- snd_pcm_close(handle);
-}
-
-/** Workaround for cr 7033899, 7030629:
- * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty
- * (just opened, underruned or already flushed).
- * Sometimes it causes PCM falls to -EBADFD error,
- * sometimes causes bufferSize change.
- * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used.
- */
-/* ******* ALSA PCM INFO ******************** */
-typedef struct tag_AlsaPcmInfo {
- snd_pcm_t* handle;
- snd_pcm_hw_params_t* hwParams;
- snd_pcm_sw_params_t* swParams;
- int bufferSizeInBytes;
- int frameSize; // storage size in Bytes
- unsigned int periods;
- snd_pcm_uframes_t periodSize;
- short int isRunning; // see comment above
- short int isFlushed; // see comment above
-#ifdef GET_POSITION_METHOD2
- // to be used exclusively by getBytePosition!
- snd_pcm_status_t* positionStatus;
-#endif
-} AlsaPcmInfo;
-
-
-int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) {
- int ret;
- int threshold;
-
- if (useThreshold) {
- // start device whenever anything is written to the buffer
- threshold = 1;
- } else {
- // never start the device automatically
- threshold = 2000000000; /* near UINT_MAX */
- }
- ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold);
- if (ret < 0) {
- ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-int setStartThreshold(AlsaPcmInfo* info, int useThreshold) {
- int ret = 0;
-
- if (!setStartThresholdNoCommit(info, useThreshold)) {
- ret = -1;
- }
- if (ret == 0) {
- // commit it
- ret = snd_pcm_sw_params(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
- }
- }
- return (ret == 0)?TRUE:FALSE;
-}
-
-
-// returns TRUE if successful
-int setHWParams(AlsaPcmInfo* info,
- float sampleRate,
- int channels,
- int bufferSizeInFrames,
- snd_pcm_format_t format) {
- unsigned int rrate, periodTime, periods;
- int ret, dir;
- snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;
-
- /* choose all parameters */
- ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
- if (ret < 0) {
- ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the interleaved read/write format */
- ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (ret < 0) {
- ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the sample format */
- ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
- if (ret < 0) {
- ERROR1("Sample format not available: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* set the count of channels */
- ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
- if (ret < 0) {
- ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
- return FALSE;
- }
- /* set the stream rate */
- rrate = (int) (sampleRate + 0.5f);
- dir = 0;
- ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
- if (ret < 0) {
- ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
- return FALSE;
- }
- if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
- ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
- return FALSE;
- }
- /* set the buffer time */
- ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
- if (ret < 0) {
- ERROR2("Unable to set buffer size to %d frames: %s\n",
- (int) alsaBufferSizeInFrames, snd_strerror(ret));
- return FALSE;
- }
- bufferSizeInFrames = (int) alsaBufferSizeInFrames;
- /* set the period time */
- if (bufferSizeInFrames > 1024) {
- dir = 0;
- periodTime = DEFAULT_PERIOD_TIME;
- ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
- if (ret < 0) {
- ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
- return FALSE;
- }
- } else {
- /* set the period count for very small buffer sizes to 2 */
- dir = 0;
- periods = 2;
- ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
- if (ret < 0) {
- ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
- return FALSE;
- }
- }
- /* write the parameters to device */
- ret = snd_pcm_hw_params(info->handle, info->hwParams);
- if (ret < 0) {
- ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-// returns 1 if successful
-int setSWParams(AlsaPcmInfo* info) {
- int ret;
-
- /* get the current swparams */
- ret = snd_pcm_sw_params_current(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* never start the transfer automatically */
- if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
- return FALSE;
- }
-
- /* allow the transfer when at least period_size samples can be processed */
- ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
- if (ret < 0) {
- ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
- return FALSE;
- }
- /* write the parameters to the playback device */
- ret = snd_pcm_sw_params(info->handle, info->swParams);
- if (ret < 0) {
- ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
- return FALSE;
- }
- return TRUE;
-}
-
-static snd_output_t* ALSA_OUTPUT = NULL;
-
-void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
- int encoding, float sampleRate, int sampleSizeInBits,
- int frameSize, int channels,
- int isSigned, int isBigEndian, int bufferSizeInBytes) {
- snd_pcm_format_mask_t* formatMask;
- snd_pcm_format_t format;
- int dir;
- int ret = 0;
- AlsaPcmInfo* info = NULL;
- /* snd_pcm_uframes_t is 64 bit on 64-bit systems */
- snd_pcm_uframes_t alsaBufferSizeInFrames = 0;
-
-
- TRACE0("> DAUDIO_Open\n");
-#ifdef USE_TRACE
- // for using ALSA debug dump methods
- if (ALSA_OUTPUT == NULL) {
- snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0);
- }
-#endif
- if (channels <= 0) {
- ERROR1("ERROR: Invalid number of channels=%d!\n", channels);
- return NULL;
- }
- info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo));
- if (!info) {
- ERROR0("Out of memory\n");
- return NULL;
- }
- memset(info, 0, sizeof(AlsaPcmInfo));
- // initial values are: stopped, flushed
- info->isRunning = 0;
- info->isFlushed = 1;
-
- ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
- if (ret == 0) {
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- ret = snd_pcm_hw_params_malloc(&(info->hwParams));
- if (ret != 0) {
- ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- ret = -1;
- if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits,
- isSigned, isBigEndian, encoding)) {
- if (setHWParams(info,
- sampleRate,
- channels,
- bufferSizeInBytes / frameSize,
- format)) {
- info->frameSize = frameSize;
- ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret));
- }
- snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir);
- snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames);
- info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize;
- TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n",
- (int) info->periodSize, info->periods, info->bufferSizeInBytes);
- }
- }
- }
- if (ret == 0) {
- // set software parameters
- ret = snd_pcm_sw_params_malloc(&(info->swParams));
- if (ret != 0) {
- ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
- } else {
- if (!setSWParams(info)) {
- ret = -1;
- }
- }
- }
- if (ret == 0) {
- // prepare device
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
- }
- }
-
-#ifdef GET_POSITION_METHOD2
- if (ret == 0) {
- ret = snd_pcm_status_malloc(&(info->positionStatus));
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret));
- }
- }
-#endif
- }
- if (ret != 0) {
- DAUDIO_Close((void*) info, isSource);
- info = NULL;
- } else {
- // set to non-blocking mode
- snd_pcm_nonblock(info->handle, 1);
- TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n",
- (void*) info->handle);
- }
- return (void*) info;
-}
-
-#ifdef USE_TRACE
-void printState(snd_pcm_state_t state) {
- if (state == SND_PCM_STATE_OPEN) {
- TRACE0("State: SND_PCM_STATE_OPEN\n");
- }
- else if (state == SND_PCM_STATE_SETUP) {
- TRACE0("State: SND_PCM_STATE_SETUP\n");
- }
- else if (state == SND_PCM_STATE_PREPARED) {
- TRACE0("State: SND_PCM_STATE_PREPARED\n");
- }
- else if (state == SND_PCM_STATE_RUNNING) {
- TRACE0("State: SND_PCM_STATE_RUNNING\n");
- }
- else if (state == SND_PCM_STATE_XRUN) {
- TRACE0("State: SND_PCM_STATE_XRUN\n");
- }
- else if (state == SND_PCM_STATE_DRAINING) {
- TRACE0("State: SND_PCM_STATE_DRAINING\n");
- }
- else if (state == SND_PCM_STATE_PAUSED) {
- TRACE0("State: SND_PCM_STATE_PAUSED\n");
- }
- else if (state == SND_PCM_STATE_SUSPENDED) {
- TRACE0("State: SND_PCM_STATE_SUSPENDED\n");
- }
-}
-#endif
-
-int DAUDIO_Start(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
- snd_pcm_state_t state;
-
- TRACE0("> DAUDIO_Start\n");
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- // set start mode so that it always starts as soon as data is there
- setStartThreshold(info, TRUE /* use threshold */);
- state = snd_pcm_state(info->handle);
- if (state == SND_PCM_STATE_PAUSED) {
- // in case it was stopped previously
- TRACE0(" Un-pausing...\n");
- ret = snd_pcm_pause(info->handle, FALSE);
- if (ret != 0) {
- ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret));
- }
- }
- if (state == SND_PCM_STATE_SUSPENDED) {
- TRACE0(" Resuming...\n");
- ret = snd_pcm_resume(info->handle);
- if (ret < 0) {
- if ((ret != -EAGAIN) && (ret != -ENOSYS)) {
- ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret));
- }
- }
- }
- if (state == SND_PCM_STATE_SETUP) {
- TRACE0("need to call prepare again...\n");
- // prepare device
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
- }
- }
- // in case there is still data in the buffers
- ret = snd_pcm_start(info->handle);
- if (ret != 0) {
- if (ret != -EPIPE) {
- ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret));
- }
- }
- // set to non-blocking mode
- ret = snd_pcm_nonblock(info->handle, 1);
- if (ret != 0) {
- ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret));
- }
- state = snd_pcm_state(info->handle);
-#ifdef USE_TRACE
- printState(state);
-#endif
- ret = (state == SND_PCM_STATE_PREPARED)
- || (state == SND_PCM_STATE_RUNNING)
- || (state == SND_PCM_STATE_XRUN)
- || (state == SND_PCM_STATE_SUSPENDED);
- if (ret) {
- info->isRunning = 1;
- // source line should keep isFlushed value until Write() is called;
- // for target data line reset it right now.
- if (!isSource) {
- info->isFlushed = 0;
- }
- }
- TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
- return ret?TRUE:FALSE;
-}
-
-int DAUDIO_Stop(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
-
- TRACE0("> DAUDIO_Stop\n");
- // set to blocking mode
- snd_pcm_nonblock(info->handle, 0);
- setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun
- ret = snd_pcm_pause(info->handle, 1);
- // set to non-blocking mode
- snd_pcm_nonblock(info->handle, 1);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
- return FALSE;
- }
- info->isRunning = 0;
- TRACE0("< DAUDIO_Stop success\n");
- return TRUE;
-}
-
-void DAUDIO_Close(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
-
- TRACE0("DAUDIO_Close\n");
- if (info != NULL) {
- if (info->handle != NULL) {
- snd_pcm_close(info->handle);
- }
- if (info->hwParams) {
- snd_pcm_hw_params_free(info->hwParams);
- }
- if (info->swParams) {
- snd_pcm_sw_params_free(info->swParams);
- }
-#ifdef GET_POSITION_METHOD2
- if (info->positionStatus) {
- snd_pcm_status_free(info->positionStatus);
- }
-#endif
- free(info);
- }
-}
-
-/*
- * Underrun and suspend recovery
- * returns
- * 0: exit native and return 0
- * 1: try again to write/read
- * -1: error - exit native with return value -1
- */
-int xrun_recovery(AlsaPcmInfo* info, int err) {
- int ret;
-
- if (err == -EPIPE) { /* underrun / overflow */
- TRACE0("xrun_recovery: underrun/overflow.\n");
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
- return -1;
- }
- return 1;
- } else if (err == -ESTRPIPE) {
- TRACE0("xrun_recovery: suspended.\n");
- ret = snd_pcm_resume(info->handle);
- if (ret < 0) {
- if (ret == -EAGAIN) {
- return 0; /* wait until the suspend flag is released */
- }
- return -1;
- }
- ret = snd_pcm_prepare(info->handle);
- if (ret < 0) {
- ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
- return -1;
- }
- return 1;
- } else if (err == -EAGAIN) {
- TRACE0("xrun_recovery: EAGAIN try again flag.\n");
- return 0;
- }
-
- TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
- return -1;
-}
-
-// returns -1 on error
-int DAUDIO_Write(void* id, char* data, int byteSize) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret, count;
- snd_pcm_sframes_t frameSize, writtenFrames;
-
- TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
-
- /* sanity */
- if (byteSize <= 0 || info->frameSize <= 0) {
- ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n",
- (int) byteSize, (int) info->frameSize);
- TRACE0("< DAUDIO_Write returning -1\n");
- return -1;
- }
-
- count = 2; // maximum number of trials to recover from underrun
- //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
- frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
- do {
- writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize);
-
- if (writtenFrames < 0) {
- ret = xrun_recovery(info, (int) writtenFrames);
- if (ret <= 0) {
- TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret);
- return ret;
- }
- if (count-- <= 0) {
- ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n");
- return -1;
- }
- } else {
- break;
- }
- } while (TRUE);
- //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames);
-
- if (writtenFrames > 0) {
- // reset "flushed" flag
- info->isFlushed = 0;
- }
-
- ret = (int) (writtenFrames * info->frameSize);
- TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
- return ret;
-}
-
-// returns -1 on error
-int DAUDIO_Read(void* id, char* data, int byteSize) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret, count;
- snd_pcm_sframes_t frameSize, readFrames;
-
- TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
- /*TRACE3(" info=%p, data=%p, byteSize=%d\n",
- (void*) info, (void*) data, (int) byteSize);
- TRACE2(" info->frameSize=%d, info->handle=%p\n",
- (int) info->frameSize, (void*) info->handle);
- */
- /* sanity */
- if (byteSize <= 0 || info->frameSize <= 0) {
- ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n",
- (int) byteSize, (int) info->frameSize);
- TRACE0("< DAUDIO_Read returning -1\n");
- return -1;
- }
- if (!info->isRunning && info->isFlushed) {
- // PCM has nothing to read
- return 0;
- }
-
- count = 2; // maximum number of trials to recover from error
- //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
- frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
- do {
- readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize);
- if (readFrames < 0) {
- ret = xrun_recovery(info, (int) readFrames);
- if (ret <= 0) {
- TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret);
- return ret;
- }
- if (count-- <= 0) {
- ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n");
- return -1;
- }
- } else {
- break;
- }
- } while (TRUE);
- //ret = snd_pcm_frames_to_bytes(info->handle, readFrames);
- ret = (int) (readFrames * info->frameSize);
- TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
- return ret;
-}
-
-
-int DAUDIO_GetBufferSize(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
-
- return info->bufferSizeInBytes;
-}
-
-int DAUDIO_StillDraining(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- snd_pcm_state_t state;
-
- state = snd_pcm_state(info->handle);
- //printState(state);
- //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE");
- return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE;
-}
-
-
-int DAUDIO_Flush(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
-
- TRACE0("DAUDIO_Flush\n");
-
- if (info->isFlushed) {
- // nothing to drop
- return 1;
- }
-
- ret = snd_pcm_drop(info->handle);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
- return FALSE;
- }
-
- info->isFlushed = 1;
- if (info->isRunning) {
- ret = DAUDIO_Start(id, isSource);
- }
- return ret;
-}
-
-int DAUDIO_GetAvailable(void* id, int isSource) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- snd_pcm_sframes_t availableInFrames;
- snd_pcm_state_t state;
- int ret;
-
- state = snd_pcm_state(info->handle);
- if (info->isFlushed || state == SND_PCM_STATE_XRUN) {
- // if in xrun state then we have the entire buffer available,
- // not 0 as alsa reports
- ret = info->bufferSizeInBytes;
- } else {
- availableInFrames = snd_pcm_avail_update(info->handle);
- if (availableInFrames < 0) {
- ret = 0;
- } else {
- //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames);
- ret = (int) (availableInFrames * info->frameSize);
- }
- }
- TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
- return ret;
-}
-
-INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) {
- // estimate the current position with the buffer size and
- // the available bytes to read or write in the buffer.
- // not an elegant solution - bytePos will stop on xruns,
- // and in race conditions it may jump backwards
- // Advantage is that it is indeed based on the samples that go through
- // the system (rather than time-based methods)
- if (isSource) {
- // javaBytePos is the position that is reached when the current
- // buffer is played completely
- return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes);
- } else {
- // javaBytePos is the position that was when the current buffer was empty
- return (INT64) (javaBytePos + availInBytes);
- }
-}
-
-INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- AlsaPcmInfo* info = (AlsaPcmInfo*) id;
- int ret;
- INT64 result = javaBytePos;
- snd_pcm_state_t state;
- state = snd_pcm_state(info->handle);
-
- if (!info->isFlushed && state != SND_PCM_STATE_XRUN) {
-#ifdef GET_POSITION_METHOD2
- snd_timestamp_t* ts;
- snd_pcm_uframes_t framesAvail;
-
- // note: slight race condition if this is called simultaneously from 2 threads
- ret = snd_pcm_status(info->handle, info->positionStatus);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret));
- result = javaBytePos;
- } else {
- // calculate from time value, or from available bytes
- framesAvail = snd_pcm_status_get_avail(info->positionStatus);
- result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
- }
-#endif
-#ifdef GET_POSITION_METHOD3
- snd_pcm_uframes_t framesAvail;
- ret = snd_pcm_avail(info->handle, &framesAvail);
- if (ret != 0) {
- ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret));
- result = javaBytePos;
- } else {
- result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
- }
-#endif
-#ifdef GET_POSITION_METHOD1
- result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource));
-#endif
- }
- //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
- return result;
-}
-
-
-
-void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- /* save to ignore, since GetBytePosition
- * takes the javaBytePos param into account
- */
-}
-
-int DAUDIO_RequiresServicing(void* id, int isSource) {
- // never need servicing on Linux
- return FALSE;
-}
-
-void DAUDIO_Service(void* id, int isSource) {
- // never need servicing on Linux
-}
-
-
-#endif // USE_DAUDIO
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,292 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//#define USE_ERROR
-//#define USE_TRACE
-
-#include "PLATFORM_API_LinuxOS_ALSA_PCMUtils.h"
-#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
-
-
-
-// callback for iteration through devices
-// returns TRUE if iteration should continue
-// NOTE: cardinfo may be NULL (for "default" device)
-typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo,
- snd_ctl_card_info_t* cardinfo, void *userData);
-
-// for each ALSA device, call iterator. userData is passed to the iterator
-// returns total number of iterations
-int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) {
- int count = 0;
- int subdeviceCount;
- int card, dev, subDev;
- char devname[16];
- int err;
- snd_ctl_t *handle;
- snd_pcm_t *pcm;
- snd_pcm_info_t* pcminfo;
- snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL;
- UINT32 deviceID;
- int doContinue = TRUE;
-
- snd_pcm_info_malloc(&pcminfo);
- snd_ctl_card_info_malloc(&cardinfo);
-
- // 1st try "default" device
- err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
- if (err < 0) {
- // try with the other direction
- err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
- SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
- }
- if (err < 0) {
- ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err));
- } else {
- err = snd_pcm_info(pcm, pcminfo);
- snd_pcm_close(pcm);
- if (err < 0) {
- ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n",
- snd_strerror(err));
- } else {
- // try to get card info
- card = snd_pcm_info_get_card(pcminfo);
- if (card >= 0) {
- sprintf(devname, ALSA_HARDWARE_CARD, card);
- if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) {
- if (snd_ctl_card_info(handle, cardinfo) >= 0) {
- defcardinfo = cardinfo;
- }
- snd_ctl_close(handle);
- }
- }
- // call callback function for the device
- if (iterator != NULL) {
- doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo,
- defcardinfo, userData);
- }
- count++;
- }
- }
-
- // iterate cards
- card = -1;
- while (doContinue) {
- if (snd_card_next(&card) < 0) {
- break;
- }
- if (card < 0) {
- break;
- }
- sprintf(devname, ALSA_HARDWARE_CARD, card);
- TRACE1("Opening alsa device \"%s\"...\n", devname);
- err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK);
- if (err < 0) {
- ERROR2("ERROR: snd_ctl_open, card=%d: %s\n",
- card, snd_strerror(err));
- } else {
- err = snd_ctl_card_info(handle, cardinfo);
- if (err < 0) {
- ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n",
- card, snd_strerror(err));
- } else {
- dev = -1;
- while (doContinue) {
- if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
- ERROR0("snd_ctl_pcm_next_device\n");
- }
- if (dev < 0) {
- break;
- }
- snd_pcm_info_set_device(pcminfo, dev);
- snd_pcm_info_set_subdevice(pcminfo, 0);
- snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
- err = snd_ctl_pcm_info(handle, pcminfo);
- if (err == -ENOENT) {
- // try with the other direction
- snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
- err = snd_ctl_pcm_info(handle, pcminfo);
- }
- if (err < 0) {
- if (err != -ENOENT) {
- ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s",
- card, snd_strerror(err));
- }
- } else {
- subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ?
- snd_pcm_info_get_subdevices_count(pcminfo) : 1;
- if (iterator!=NULL) {
- for (subDev = 0; subDev < subdeviceCount; subDev++) {
- deviceID = encodeDeviceID(card, dev, subDev);
- doContinue = (*iterator)(deviceID, pcminfo,
- cardinfo, userData);
- count++;
- if (!doContinue) {
- break;
- }
- }
- } else {
- count += subdeviceCount;
- }
- }
- } // of while(doContinue)
- }
- snd_ctl_close(handle);
- }
- }
- snd_ctl_card_info_free(cardinfo);
- snd_pcm_info_free(pcminfo);
- return count;
-}
-
-int getAudioDeviceCount() {
- initAlsaSupport();
- return iteratePCMDevices(NULL, NULL);
-}
-
-int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo,
- snd_ctl_card_info_t* cardinfo, void* userData) {
- char buffer[300];
- ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData;
-#ifdef ALSA_PCM_USE_PLUGHW
- int usePlugHw = 1;
-#else
- int usePlugHw = 0;
-#endif
-
- initAlsaSupport();
- if (desc->index == 0) {
- // we found the device with correct index
- *(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ?
- 1 : snd_pcm_info_get_subdevices_count(pcminfo);
- *desc->deviceID = deviceID;
- buffer[0]=' '; buffer[1]='[';
- // buffer[300] is enough to store the actual device string w/o overrun
- getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM);
- strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
- strncpy(desc->name,
- (cardinfo != NULL)
- ? snd_ctl_card_info_get_id(cardinfo)
- : snd_pcm_info_get_id(pcminfo),
- desc->strLen - strlen(buffer));
- strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
- strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen);
- strncpy(desc->description,
- (cardinfo != NULL)
- ? snd_ctl_card_info_get_name(cardinfo)
- : snd_pcm_info_get_name(pcminfo),
- desc->strLen);
- strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
- strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description));
- strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
- strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description));
- getALSAVersion(desc->version, desc->strLen);
- TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version);
- return FALSE; // do not continue iteration
- }
- desc->index--;
- return TRUE;
-}
-
-// returns 0 if successful
-int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) {
- char buffer[200];
- int ret;
-
- initAlsaSupport();
- getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM);
-
- TRACE1("Opening ALSA device %s\n", buffer);
- ret = snd_pcm_open(handle, buffer,
- isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE,
- SND_PCM_NONBLOCK);
- if (ret != 0) {
- ERROR1("snd_pcm_open returned error code %d \n", ret);
- *handle = NULL;
- }
- return ret;
-}
-
-
-int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) {
- initAlsaSupport();
- TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index);
- iteratePCMDevices(&deviceInfoIterator, desc);
- return (desc->index == 0)?TRUE:FALSE;
-}
-
-// returns 1 if successful
-// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h)
-int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat,
- int* sampleSizeInBytes, int* significantBits,
- int* isSigned, int* isBigEndian, int* enc) {
-
- *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8;
- *significantBits = snd_pcm_format_width(alsaFormat);
-
- // defaults
- *enc = 0; // PCM
- *isSigned = (snd_pcm_format_signed(alsaFormat) > 0);
- *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0);
-
- // non-PCM formats
- if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law
- *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes;
- }
- else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law
- *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes;
- }
- else if (snd_pcm_format_linear(alsaFormat) < 1) {
- return 0;
- }
- return (*sampleSizeInBytes > 0);
-}
-
-// returns 1 if successful
-int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat,
- int sampleSizeInBytes, int significantBits,
- int isSigned, int isBigEndian, int enc) {
- *alsaFormat = SND_PCM_FORMAT_UNKNOWN;
-
- if (enc == 0) {
- *alsaFormat = snd_pcm_build_linear_format(significantBits,
- sampleSizeInBytes * 8,
- isSigned?0:1,
- isBigEndian?1:0);
- }
- else if ((sampleSizeInBytes == 1) && (significantBits == 8)) {
- if (enc == 1) { // ULAW
- *alsaFormat = SND_PCM_FORMAT_MU_LAW;
- }
- else if (enc == 2) { // ALAW
- *alsaFormat = SND_PCM_FORMAT_A_LAW;
- }
- }
- return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1;
-}
-
-
-/* end */
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// define this with a later version of ALSA than 0.9.0rc3
-// (starting from 1.0.0 it became default behaviour)
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#include <alsa/asoundlib.h>
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,724 +0,0 @@
-/*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-//#define USE_TRACE
-
-#include "Ports.h"
-#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"
-#include <alsa/asoundlib.h>
-
-#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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_PCM.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,626 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_SolarisOS_Utils.h"
-#include "DirectAudio.h"
-
-#if USE_DAUDIO == TRUE
-
-
-// The default buffer time
-#define DEFAULT_PERIOD_TIME_MILLIS 50
-
-///// implemented functions of DirectAudio.h
-
-INT32 DAUDIO_GetDirectAudioDeviceCount() {
- return (INT32) getAudioDeviceCount();
-}
-
-
-INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex,
- DirectAudioDeviceDescription* description) {
- AudioDeviceDescription desc;
-
- if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
- description->maxSimulLines = desc.maxSimulLines;
- strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1);
- description->name[DAUDIO_STRING_LENGTH-1] = 0;
- strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1);
- description->vendor[DAUDIO_STRING_LENGTH-1] = 0;
- strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1);
- description->version[DAUDIO_STRING_LENGTH-1] = 0;
- /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/
- strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1);
- description->description[DAUDIO_STRING_LENGTH-1] = 0;
- return TRUE;
- }
- return FALSE;
-
-}
-
-#define MAX_SAMPLE_RATES 20
-
-void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
- int fd = -1;
- AudioDeviceDescription desc;
- am_sample_rates_t *sr;
- /* hardcoded bits and channels */
- int bits[] = {8, 16};
- int bitsCount = 2;
- int channels[] = {1, 2};
- int channelsCount = 2;
- /* for querying sample rates */
- int err;
- int ch, b, s;
-
- TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource);
- if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
- fd = open(desc.pathctl, O_RDONLY);
- }
- if (fd < 0) {
- ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
- return;
- }
-
- /* get sample rates */
- sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES));
- if (sr == NULL) {
- ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex);
- close(fd);
- return;
- }
-
- sr->num_samp_rates = MAX_SAMPLE_RATES;
- sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD;
- sr->samp_rates[0] = -2;
- err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr);
- if (err < 0) {
- ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n",
- (int)mixerIndex);
- ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n",
- (int) sr->num_samp_rates,
- (int) sr->samp_rates[0]);
- /* Some Solaris 8 drivers fail for get sample rates!
- * Do as if we support all sample rates
- */
- sr->flags = MIXER_SR_LIMITS;
- }
- if ((sr->flags & MIXER_SR_LIMITS)
- || (sr->num_samp_rates > MAX_SAMPLE_RATES)) {
-#ifdef USE_TRACE
- if ((sr->flags & MIXER_SR_LIMITS)) {
- TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n",
- (int)mixerIndex);
- }
- if (sr->num_samp_rates > MAX_SAMPLE_RATES) {
- TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n",
- MAX_SAMPLE_RATES, (int)mixerIndex);
- }
-#endif
- /*
- * Fake it to have only one sample rate: -1
- */
- sr->num_samp_rates = 1;
- sr->samp_rates[0] = -1;
- }
- close(fd);
-
- for (ch = 0; ch < channelsCount; ch++) {
- for (b = 0; b < bitsCount; b++) {
- for (s = 0; s < sr->num_samp_rates; s++) {
- DAUDIO_AddAudioFormat(creator,
- bits[b], /* significant bits */
- 0, /* frameSize: let it be calculated */
- channels[ch],
- (float) ((int) sr->samp_rates[s]),
- DAUDIO_PCM, /* encoding - let's only do PCM */
- (bits[b] > 8)?TRUE:TRUE, /* isSigned */
-#ifdef _LITTLE_ENDIAN
- FALSE /* little endian */
-#else
- (bits[b] > 8)?TRUE:FALSE /* big endian */
-#endif
- );
- }
- }
- }
- free(sr);
-}
-
-
-typedef struct {
- int fd;
- audio_info_t info;
- int bufferSizeInBytes;
- int frameSize; /* storage size in Bytes */
- /* how many bytes were written or read */
- INT32 transferedBytes;
- /* if transferedBytes exceed 32-bit boundary,
- * it will be reset and positionOffset will receive
- * the offset
- */
- INT64 positionOffset;
-} SolPcmInfo;
-
-
-void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
- int encoding, float sampleRate, int sampleSizeInBits,
- int frameSize, int channels,
- int isSigned, int isBigEndian, int bufferSizeInBytes) {
- int err = 0;
- int openMode;
- AudioDeviceDescription desc;
- SolPcmInfo* info;
-
- TRACE0("> DAUDIO_Open\n");
- if (encoding != DAUDIO_PCM) {
- ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding);
- return NULL;
- }
- if (channels <= 0) {
- ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels);
- return NULL;
- }
-
- info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo));
- if (!info) {
- ERROR0("Out of memory\n");
- return NULL;
- }
- memset(info, 0, sizeof(SolPcmInfo));
- info->frameSize = frameSize;
- info->fd = -1;
-
- if (isSource) {
- openMode = O_WRONLY;
- } else {
- openMode = O_RDONLY;
- }
-
-#ifndef __linux__
- /* blackdown does not use NONBLOCK */
- openMode |= O_NONBLOCK;
-#endif
-
- if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
- info->fd = open(desc.path, openMode);
- }
- if (info->fd < 0) {
- ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex);
- free(info);
- return NULL;
- }
- /* set to multiple open */
- if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) {
- TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path);
- } else {
- ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path);
- }
-
- AUDIO_INITINFO(&(info->info));
- /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */
- err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
-
- /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */
- AUDIO_INITINFO(&(info->info));
-
- if (isSource) {
- info->info.play.sample_rate = sampleRate;
- info->info.play.precision = sampleSizeInBits;
- info->info.play.channels = channels;
- info->info.play.encoding = AUDIO_ENCODING_LINEAR;
- info->info.play.buffer_size = bufferSizeInBytes;
- info->info.play.pause = 1;
- } else {
- info->info.record.sample_rate = sampleRate;
- info->info.record.precision = sampleSizeInBits;
- info->info.record.channels = channels;
- info->info.record.encoding = AUDIO_ENCODING_LINEAR;
- info->info.record.buffer_size = bufferSizeInBytes;
- info->info.record.pause = 1;
- }
- err = ioctl(info->fd, AUDIO_SETINFO, &(info->info));
- if (err < 0) {
- ERROR0("DAUDIO_Open: could not set info!\n");
- DAUDIO_Close((void*) info, isSource);
- return NULL;
- }
- DAUDIO_Flush((void*) info, isSource);
-
- err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
- if (err >= 0) {
- if (isSource) {
- info->bufferSizeInBytes = info->info.play.buffer_size;
- } else {
- info->bufferSizeInBytes = info->info.record.buffer_size;
- }
- TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n",
- (int) bufferSizeInBytes,
- (int) info->bufferSizeInBytes);
- } else {
- ERROR0("DAUDIO_Open: cannot get info!\n");
- DAUDIO_Close((void*) info, isSource);
- return NULL;
- }
- TRACE0("< DAUDIO_Open: Opened device successfully.\n");
- return (void*) info;
-}
-
-
-int DAUDIO_Start(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int err, modified;
- audio_info_t audioInfo;
-
- TRACE0("> DAUDIO_Start\n");
-
- AUDIO_INITINFO(&audioInfo);
- err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
- if (err >= 0) {
- // unpause
- modified = FALSE;
- if (isSource && audioInfo.play.pause) {
- audioInfo.play.pause = 0;
- modified = TRUE;
- }
- if (!isSource && audioInfo.record.pause) {
- audioInfo.record.pause = 0;
- modified = TRUE;
- }
- if (modified) {
- err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
- }
- }
-
- TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error");
- return (err >= 0)?TRUE:FALSE;
-}
-
-int DAUDIO_Stop(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int err, modified;
- audio_info_t audioInfo;
-
- TRACE0("> DAUDIO_Stop\n");
-
- AUDIO_INITINFO(&audioInfo);
- err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
- if (err >= 0) {
- // pause
- modified = FALSE;
- if (isSource && !audioInfo.play.pause) {
- audioInfo.play.pause = 1;
- modified = TRUE;
- }
- if (!isSource && !audioInfo.record.pause) {
- audioInfo.record.pause = 1;
- modified = TRUE;
- }
- if (modified) {
- err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
- }
- }
-
- TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error");
- return (err >= 0)?TRUE:FALSE;
-}
-
-void DAUDIO_Close(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
-
- TRACE0("DAUDIO_Close\n");
- if (info != NULL) {
- if (info->fd >= 0) {
- DAUDIO_Flush(id, isSource);
- close(info->fd);
- }
- free(info);
- }
-}
-
-#ifndef USE_TRACE
-/* close to 2^31 */
-#define POSITION_MAX 2000000000
-#else
-/* for testing */
-#define POSITION_MAX 1000000
-#endif
-
-void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) {
- audio_info_t audioInfo;
- audio_prinfo_t* prinfo;
- int err;
- int offset = -1;
- int underrun = FALSE;
- int devBytes = 0;
-
- if (count > 0) {
- info->transferedBytes += count;
-
- if (isSource) {
- prinfo = &(audioInfo.play);
- } else {
- prinfo = &(audioInfo.record);
- }
- AUDIO_INITINFO(&audioInfo);
- err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
- if (err >= 0) {
- underrun = prinfo->error;
- devBytes = prinfo->samples * info->frameSize;
- }
- AUDIO_INITINFO(&audioInfo);
- if (underrun) {
- /* if an underrun occurred, reset */
- ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n",
- (devBytes - info->transferedBytes));
- ERROR1(" devBytes from %d to 0, ", devBytes);
- ERROR2(" positionOffset from %d to %d ",
- (int) info->positionOffset,
- (int) (info->positionOffset + info->transferedBytes));
- ERROR1(" transferedBytes from %d to 0\n",
- (int) info->transferedBytes);
- prinfo->samples = 0;
- info->positionOffset += info->transferedBytes;
- info->transferedBytes = 0;
- }
- else if (info->transferedBytes > POSITION_MAX) {
- /* we will reset transferedBytes and
- * the samples field in prinfo
- */
- offset = devBytes;
- prinfo->samples = 0;
- }
- /* reset error flag */
- prinfo->error = 0;
-
- err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
- if (err >= 0) {
- if (offset > 0) {
- /* upon exit of AUDIO_SETINFO, the samples parameter
- * was set to the previous value. This is our
- * offset.
- */
- TRACE1("Adjust samplePos: offset=%d, ", (int) offset);
- TRACE2("transferedBytes=%d -> %d, ",
- (int) info->transferedBytes,
- (int) (info->transferedBytes - offset));
- TRACE2("positionOffset=%d -> %d\n",
- (int) (info->positionOffset),
- (int) (((int) info->positionOffset) + offset));
- info->transferedBytes -= offset;
- info->positionOffset += offset;
- }
- } else {
- ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n");
- }
- }
-}
-
-// returns -1 on error
-int DAUDIO_Write(void* id, char* data, int byteSize) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int ret = -1;
-
- TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
- if (info!=NULL) {
- ret = write(info->fd, data, byteSize);
- resetErrorFlagAndAdjustPosition(info, TRUE, ret);
- /* sets ret to -1 if buffer full, no error! */
- if (ret < 0) {
- ret = 0;
- }
- }
- TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
- return ret;
-}
-
-// returns -1 on error
-int DAUDIO_Read(void* id, char* data, int byteSize) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int ret = -1;
-
- TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
- if (info != NULL) {
- ret = read(info->fd, data, byteSize);
- resetErrorFlagAndAdjustPosition(info, TRUE, ret);
- /* sets ret to -1 if buffer full, no error! */
- if (ret < 0) {
- ret = 0;
- }
- }
- TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
- return ret;
-}
-
-
-int DAUDIO_GetBufferSize(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- if (info) {
- return info->bufferSizeInBytes;
- }
- return 0;
-}
-
-int DAUDIO_StillDraining(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- audio_info_t audioInfo;
- audio_prinfo_t* prinfo;
- int ret = FALSE;
-
- if (info!=NULL) {
- if (isSource) {
- prinfo = &(audioInfo.play);
- } else {
- prinfo = &(audioInfo.record);
- }
- /* check error flag */
- AUDIO_INITINFO(&audioInfo);
- ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
- ret = (prinfo->error != 0)?FALSE:TRUE;
- }
- return ret;
-}
-
-
-int getDevicePosition(SolPcmInfo* info, int isSource) {
- audio_info_t audioInfo;
- audio_prinfo_t* prinfo;
- int err;
-
- if (isSource) {
- prinfo = &(audioInfo.play);
- } else {
- prinfo = &(audioInfo.record);
- }
- AUDIO_INITINFO(&audioInfo);
- err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
- if (err >= 0) {
- /*TRACE2("---> device paused: %d eof=%d\n",
- prinfo->pause, prinfo->eof);
- */
- return (int) (prinfo->samples * info->frameSize);
- }
- ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n");
- return -1;
-}
-
-int DAUDIO_Flush(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int err = -1;
- int pos;
-
- TRACE0("DAUDIO_Flush\n");
- if (info) {
- if (isSource) {
- err = ioctl(info->fd, I_FLUSH, FLUSHW);
- } else {
- err = ioctl(info->fd, I_FLUSH, FLUSHR);
- }
- if (err >= 0) {
- /* resets the transferedBytes parameter to
- * the current samples count of the device
- */
- pos = getDevicePosition(info, isSource);
- if (pos >= 0) {
- info->transferedBytes = pos;
- }
- }
- }
- if (err < 0) {
- ERROR0("ERROR in DAUDIO_Flush\n");
- }
- return (err < 0)?FALSE:TRUE;
-}
-
-int DAUDIO_GetAvailable(void* id, int isSource) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int ret = 0;
- int pos;
-
- if (info) {
- /* unfortunately, the STREAMS architecture
- * seems to not have a method for querying
- * the available bytes to read/write!
- * estimate it...
- */
- pos = getDevicePosition(info, isSource);
- if (pos >= 0) {
- if (isSource) {
- /* we usually have written more bytes
- * to the queue than the device position should be
- */
- ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos);
- } else {
- /* for record, the device stream should
- * be usually ahead of our read actions
- */
- ret = pos - info->transferedBytes;
- }
- if (ret > info->bufferSizeInBytes) {
- ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n",
- (int) ret, (int) info->bufferSizeInBytes);
- ERROR2(" devicePos=%d, transferedBytes=%d\n",
- (int) pos, (int) info->transferedBytes);
- ret = info->bufferSizeInBytes;
- }
- else if (ret < 0) {
- ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n",
- (int) ret);
- ERROR2(" devicePos=%d, transferedBytes=%d\n",
- (int) pos, (int) info->transferedBytes);
- ret = 0;
- }
- }
- }
-
- TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
- return ret;
-}
-
-INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int ret;
- int pos;
- INT64 result = javaBytePos;
-
- if (info) {
- pos = getDevicePosition(info, isSource);
- if (pos >= 0) {
- result = info->positionOffset + pos;
- }
- }
-
- //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
- return result;
-}
-
-
-void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
- SolPcmInfo* info = (SolPcmInfo*) id;
- int ret;
- int pos;
-
- if (info) {
- pos = getDevicePosition(info, isSource);
- if (pos >= 0) {
- info->positionOffset = javaBytePos - pos;
- }
- }
-}
-
-int DAUDIO_RequiresServicing(void* id, int isSource) {
- // never need servicing on Solaris
- return FALSE;
-}
-
-void DAUDIO_Service(void* id, int isSource) {
- // never need servicing on Solaris
-}
-
-
-#endif // USE_DAUDIO
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,600 +0,0 @@
-/*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-//#define USE_TRACE
-
-#include "Ports.h"
-#include "PLATFORM_API_SolarisOS_Utils.h"
-
-#if USE_PORTS == TRUE
-
-#define MONITOR_GAIN_STRING "Monitor Gain"
-
-#define ALL_TARGET_PORT_COUNT 6
-
-// define the following to not use audio_prinfo_t.mod_ports
-#define SOLARIS7_COMPATIBLE
-
-// Solaris audio defines
-static int targetPorts[ALL_TARGET_PORT_COUNT] = {
- AUDIO_SPEAKER,
- AUDIO_HEADPHONE,
- AUDIO_LINE_OUT,
- AUDIO_AUX1_OUT,
- AUDIO_AUX2_OUT,
- AUDIO_SPDIF_OUT
-};
-
-static char* targetPortNames[ALL_TARGET_PORT_COUNT] = {
- "Speaker",
- "Headphone",
- "Line Out",
- "AUX1 Out",
- "AUX2 Out",
- "SPDIF Out"
-};
-
-// defined in Ports.h
-static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = {
- PORT_DST_SPEAKER,
- PORT_DST_HEADPHONE,
- PORT_DST_LINE_OUT,
- PORT_DST_UNKNOWN,
- PORT_DST_UNKNOWN,
- PORT_DST_UNKNOWN,
-};
-
-#define ALL_SOURCE_PORT_COUNT 7
-
-// Solaris audio defines
-static int sourcePorts[ALL_SOURCE_PORT_COUNT] = {
- AUDIO_MICROPHONE,
- AUDIO_LINE_IN,
- AUDIO_CD,
- AUDIO_AUX1_IN,
- AUDIO_AUX2_IN,
- AUDIO_SPDIF_IN,
- AUDIO_CODEC_LOOPB_IN
-};
-
-static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = {
- "Microphone In",
- "Line In",
- "Compact Disc In",
- "AUX1 In",
- "AUX2 In",
- "SPDIF In",
- "Internal Loopback"
-};
-
-// Ports.h defines
-static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = {
- PORT_SRC_MICROPHONE,
- PORT_SRC_LINE_IN,
- PORT_SRC_COMPACT_DISC,
- PORT_SRC_UNKNOWN,
- PORT_SRC_UNKNOWN,
- PORT_SRC_UNKNOWN,
- PORT_SRC_UNKNOWN
-};
-
-struct tag_PortControlID;
-
-typedef struct tag_PortInfo {
- int fd; // file descriptor of the pseudo device
- audio_info_t audioInfo;
- // ports
- int targetPortCount;
- int sourcePortCount;
- // indexes to sourcePorts/targetPorts
- // contains first target ports, then source ports
- int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT];
- // controls
- int maxControlCount; // upper bound of number of controls
- int usedControlIDs; // number of items already filled in controlIDs
- struct tag_PortControlID* controlIDs; // the control IDs themselves
-} PortInfo;
-
-#define PORT_CONTROL_TYPE_PLAY 0x4000000
-#define PORT_CONTROL_TYPE_RECORD 0x8000000
-#define PORT_CONTROL_TYPE_SELECT_PORT 1
-#define PORT_CONTROL_TYPE_GAIN 2
-#define PORT_CONTROL_TYPE_BALANCE 3
-#define PORT_CONTROL_TYPE_MONITOR_GAIN 10
-#define PORT_CONTROL_TYPE_OUTPUT_MUTED 11
-#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD
-#define PORT_CONTROL_TYPE_MASK 0xFFFFFF
-
-
-typedef struct tag_PortControlID {
- PortInfo* portInfo;
- INT32 controlType; // PORT_CONTROL_TYPE_XX
- uint_t port;
-} PortControlID;
-
-
-///// implemented functions of Ports.h
-
-INT32 PORT_GetPortMixerCount() {
- return (INT32) getAudioDeviceCount();
-}
-
-
-INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
- AudioDeviceDescription desc;
-
- if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
- strncpy(description->name, desc.name, PORT_STRING_LENGTH-1);
- description->name[PORT_STRING_LENGTH-1] = 0;
- strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1);
- description->vendor[PORT_STRING_LENGTH-1] = 0;
- strncpy(description->version, desc.version, PORT_STRING_LENGTH-1);
- description->version[PORT_STRING_LENGTH-1] = 0;
- /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/
- strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1);
- description->description[PORT_STRING_LENGTH-1] = 0;
- return TRUE;
- }
- return FALSE;
-}
-
-
-void* PORT_Open(INT32 mixerIndex) {
- PortInfo* info = NULL;
- int fd = -1;
- AudioDeviceDescription desc;
- int success = FALSE;
-
- TRACE0("PORT_Open\n");
- if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
- fd = open(desc.pathctl, O_RDWR);
- }
- if (fd < 0) {
- ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
- return NULL;
- }
-
- info = (PortInfo*) malloc(sizeof(PortInfo));
- if (info != NULL) {
- memset(info, 0, sizeof(PortInfo));
- info->fd = fd;
- success = TRUE;
- }
- if (!success) {
- if (fd >= 0) {
- close(fd);
- }
- PORT_Close((void*) info);
- info = NULL;
- }
- return info;
-}
-
-void PORT_Close(void* id) {
- TRACE0("PORT_Close\n");
- if (id != NULL) {
- PortInfo* info = (PortInfo*) id;
- if (info->fd >= 0) {
- close(info->fd);
- info->fd = -1;
- }
- if (info->controlIDs) {
- free(info->controlIDs);
- info->controlIDs = NULL;
- }
- free(info);
- }
-}
-
-
-
-INT32 PORT_GetPortCount(void* id) {
- int ret = 0;
- PortInfo* info = (PortInfo*) id;
- if (info != NULL) {
- if (!info->targetPortCount && !info->sourcePortCount) {
- int i;
- AUDIO_INITINFO(&info->audioInfo);
- if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) {
- for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) {
- if (info->audioInfo.play.avail_ports & targetPorts[i]) {
- info->ports[info->targetPortCount] = i;
- info->targetPortCount++;
- }
-#ifdef SOLARIS7_COMPATIBLE
- TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i],
- info->audioInfo.play.avail_ports & targetPorts[i]);
-#else
- TRACE4("Target %d %s: avail=%d mod=%d\n", i, targetPortNames[i],
- info->audioInfo.play.avail_ports & targetPorts[i],
- info->audioInfo.play.mod_ports & targetPorts[i]);
-#endif
- }
- for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) {
- if (info->audioInfo.record.avail_ports & sourcePorts[i]) {
- info->ports[info->targetPortCount + info->sourcePortCount] = i;
- info->sourcePortCount++;
- }
-#ifdef SOLARIS7_COMPATIBLE
- TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i],
- info->audioInfo.record.avail_ports & sourcePorts[i]);
-#else
- TRACE4("Source %d %s: avail=%d mod=%d\n", i, sourcePortNames[i],
- info->audioInfo.record.avail_ports & sourcePorts[i],
- info->audioInfo.record.mod_ports & sourcePorts[i]);
-#endif
- }
- }
- }
- ret = info->targetPortCount + info->sourcePortCount;
- }
- return ret;
-}
-
-int isSourcePort(PortInfo* info, INT32 portIndex) {
- return (portIndex >= info->targetPortCount);
-}
-
-INT32 PORT_GetPortType(void* id, INT32 portIndex) {
- PortInfo* info = (PortInfo*) id;
- if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
- if (isSourcePort(info, portIndex)) {
- return sourcePortJavaSoundMapping[info->ports[portIndex]];
- } else {
- return targetPortJavaSoundMapping[info->ports[portIndex]];
- }
- }
- return 0;
-}
-
-// pre-condition: portIndex must have been verified!
-char* getPortName(PortInfo* info, INT32 portIndex) {
- char* ret = NULL;
-
- if (isSourcePort(info, portIndex)) {
- ret = sourcePortNames[info->ports[portIndex]];
- } else {
- ret = targetPortNames[info->ports[portIndex]];
- }
- return ret;
-}
-
-INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
- PortInfo* info = (PortInfo*) id;
- char* n;
-
- if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
- n = getPortName(info, portIndex);
- if (n) {
- strncpy(name, n, len-1);
- name[len-1] = 0;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex,
- INT32 type, void** controlObjects, int* controlCount) {
- PortControlID* controlID;
- void* newControl = NULL;
- int controlIndex;
- char* jsType = NULL;
- int isBoolean = FALSE;
-
- TRACE0(">createPortControl\n");
-
- // fill the ControlID structure and add this control
- if (info->usedControlIDs >= info->maxControlCount) {
- ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
- return;
- }
- controlID = &(info->controlIDs[info->usedControlIDs]);
- controlID->portInfo = info;
- controlID->controlType = type;
- controlIndex = info->ports[portIndex];
- if (isSourcePort(info, portIndex)) {
- controlID->port = sourcePorts[controlIndex];
- } else {
- controlID->port = targetPorts[controlIndex];
- }
- switch (type & PORT_CONTROL_TYPE_MASK) {
- case PORT_CONTROL_TYPE_SELECT_PORT:
- jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break;
- case PORT_CONTROL_TYPE_GAIN:
- jsType = CONTROL_TYPE_VOLUME; break;
- case PORT_CONTROL_TYPE_BALANCE:
- jsType = CONTROL_TYPE_BALANCE; break;
- case PORT_CONTROL_TYPE_MONITOR_GAIN:
- jsType = CONTROL_TYPE_VOLUME; break;
- case PORT_CONTROL_TYPE_OUTPUT_MUTED:
- jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break;
- }
- if (isBoolean) {
- TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
- newControl = (creator->newBooleanControl)(creator, controlID, jsType);
- }
- else if (jsType == CONTROL_TYPE_BALANCE) {
- TRACE0(" PORT_CONTROL_TYPE_BALANCE\n");
- newControl = (creator->newFloatControl)(creator, controlID, jsType,
- -1.0f, 1.0f, 2.0f / 65.0f, "");
- } else {
- TRACE0(" PORT_CONTROL_TYPE_FLOAT\n");
- newControl = (creator->newFloatControl)(creator, controlID, jsType,
- 0.0f, 1.0f, 1.0f / 256.0f, "");
- }
- if (newControl) {
- controlObjects[*controlCount] = newControl;
- (*controlCount)++;
- info->usedControlIDs++;
- }
- TRACE0("<createPortControl\n");
-}
-
-
-void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
- void* compControl;
-
- TRACE1(">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("<addCompoundControl\n");
-}
-
-void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
- int i = 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("<addAllControl\n");
-}
-
-void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
- PortInfo* info = (PortInfo*) id;
- int portCount = PORT_GetPortCount(id);
- void* controls[4];
- int controlCount = 0;
- INT32 type;
- int selectable = 1;
- memset(controls, 0, sizeof(controls));
-
- TRACE4(">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
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.c Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define USE_ERROR
-#define USE_TRACE
-
-#include "PLATFORM_API_SolarisOS_Utils.h"
-
-#define MAX_AUDIO_DEVICES 20
-
-// not thread safe...
-static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES];
-static int globalADCount = -1;
-static int globalADCacheTime = -1;
-/* how many seconds do we cache devices */
-#define AD_CACHE_TIME 30
-
-// return seconds
-long getTimeInSeconds() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec;
-}
-
-
-int getAudioDeviceCount() {
- int count = MAX_AUDIO_DEVICES;
-
- getAudioDevices(globalADPaths, &count);
- return count;
-}
-
-/* returns TRUE if the path exists at all */
-int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) {
- int i;
- int found = 0;
- int fileExists = 0;
- // not thread safe...
- static struct stat statBuf;
-
- // get stats on the file
- if (stat(path, &statBuf) == 0) {
- // file exists.
- fileExists = 1;
- // If it is not yet in the adPath array, add it to the array
- for (i = 0; i < *count; i++) {
- if (adPath[i].st_ino == statBuf.st_ino
- && adPath[i].st_dev == statBuf.st_dev) {
- found = 1;
- break;
- }
- }
- if (!found) {
- adPath[*count].st_ino = statBuf.st_ino;
- adPath[*count].st_dev = statBuf.st_dev;
- strncpy(adPath[*count].path, path, MAX_NAME_LENGTH);
- adPath[*count].path[MAX_NAME_LENGTH - 1] = 0;
- (*count)++;
- TRACE1("Added audio device %s\n", path);
- }
- }
- return fileExists;
-}
-
-
-void getAudioDevices(AudioDevicePath* adPath, int* count) {
- int maxCount = *count;
- char* audiodev;
- char devsound[15];
- int i;
- long timeInSeconds = getTimeInSeconds();
-
- if (globalADCount < 0
- || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME
- || (adPath != globalADPaths)) {
- *count = 0;
- // first device, if set, is AUDIODEV variable
- audiodev = getenv("AUDIODEV");
- if (audiodev != NULL && audiodev[0] != 0) {
- addAudioDevice(audiodev, adPath, count);
- }
- // then try /dev/audio
- addAudioDevice("/dev/audio", adPath, count);
- // then go through all of the /dev/sound/? devices
- for (i = 0; i < 100; i++) {
- sprintf(devsound, "/dev/sound/%d", i);
- if (!addAudioDevice(devsound, adPath, count)) {
- break;
- }
- }
- if (adPath == globalADPaths) {
- /* commit cache */
- globalADCount = *count;
- /* set cache time */
- globalADCacheTime = timeInSeconds;
- }
- } else {
- /* return cache */
- *count = globalADCount;
- }
- // that's it
-}
-
-int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) {
- int count = MAX_AUDIO_DEVICES;
- int ret = 0;
-
- getAudioDevices(globalADPaths, &count);
- if (index>=0 && index < count) {
- ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames);
- }
- return ret;
-}
-
-int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) {
- int fd;
- int mixerMode;
- int len;
- audio_info_t info;
- audio_device_t deviceInfo;
-
- strncpy(adDesc->path, path, MAX_NAME_LENGTH);
- adDesc->path[MAX_NAME_LENGTH] = 0;
- strcpy(adDesc->pathctl, adDesc->path);
- strcat(adDesc->pathctl, "ctl");
- strcpy(adDesc->name, adDesc->path);
- adDesc->vendor[0] = 0;
- adDesc->version[0] = 0;
- adDesc->description[0] = 0;
- adDesc->maxSimulLines = 1;
-
- // try to open the pseudo device and get more information
- fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK);
- if (fd >= 0) {
- close(fd);
- if (getNames) {
- fd = open(adDesc->pathctl, O_RDONLY);
- if (fd >= 0) {
- if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) {
- strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN);
- adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0;
- strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN);
- adDesc->version[MAX_AUDIO_DEV_LEN] = 0;
- /* add config string to the dev name
- * creates a string like "/dev/audio (onboard1)"
- */
- len = strlen(adDesc->name) + 1;
- if (MAX_NAME_LENGTH - len > 3) {
- strcat(adDesc->name, " (");
- strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len);
- strcat(adDesc->name, ")");
- }
- adDesc->name[MAX_NAME_LENGTH-1] = 0;
- }
- if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) {
- if (mixerMode == AM_MIXER_MODE) {
- TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path);
- adDesc->maxSimulLines = -1;
- }
- } else {
- ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path);
- }
- close(fd);
- } else {
- ERROR1("could not open %s!\n", adDesc->pathctl);
- }
- }
- return 1;
- }
- return 0;
-}
--- a/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Utils.h Fri Mar 23 09:26:59 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <Utilities.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-/* does not work on Solaris 2.7 */
-#include <sys/audio.h>
-#include <sys/mixer.h>
-#include <sys/types.h>
-#ifndef __linux__
-#include <stropts.h>
-#endif
-#include <sys/conf.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#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