/*
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* TODO:
* - move all the conversion code into an own file
*/
//#define USE_TRACE
//#define USE_ERROR
#include <jni.h>
#include <jni_util.h>
// for malloc
#ifdef _ALLBSD_SOURCE
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include "SoundDefs.h"
#include "DirectAudio.h"
#include "Utilities.h"
#include "com_sun_media_sound_DirectAudioDevice.h"
typedef struct {
void* handle;
int encoding;
int sampleSizeInBits;
int frameSize;
int channels;
int isSigned;
int isBigEndian;
UINT8* conversionBuffer;
int conversionBufferSize;
} DAUDIO_Info;
//////////////////////////////////////////// MAP Conversion stuff /////////////////////////////////
/* 16 bit signed sample, native endianness, stored in 32-bits */
typedef INT32 MAP_Sample;
static INLINE UINT16 MAP_SWAP16_impl(UINT16 a) {
return (a>>8) | (a<<8);
}
static INLINE UINT32 MAP_SWAP32_impl(UINT32 a) {
return (a>>24)
| ((a>>8) & 0xFF00)
| ((a<<8) & 0xFF0000)
| (a<<24);
}
static INLINE UINT32 MAP_SWAP16BIT(UINT32 sh) {
return (UINT32) ((sh & 0xFF) << 8) | ((sh & 0xFF00) >> 8);
}
static INLINE INT32 MAP_ClipAndConvertToShort(MAP_Sample sample) {
if (sample < -32768) {
return -32768;
}
else if (sample > 32767) {
return 32767;
}
return (INT32) sample;
}
static INLINE INT32 MAP_ClipAndConvertToShort_Swapped(MAP_Sample sample) {
if (sample < -32768) {
return 0x0080;
}
else if (sample > 32767) {
return 0xFF7F;
}
return (INT32) (INT16) MAP_SWAP16BIT(sample);
}
static INLINE INT8 MAP_ClipAndConvertToByte(MAP_Sample sample) {
if (sample < -32768) {
return -128;
}
else if (sample > 32767) {
return 127;
}
return (INT8) (sample >> 8);
}
static INLINE UINT8 MAP_ClipAndConvertToUByte(MAP_Sample sample) {
if (sample < -32768) {
return 0;
}
else if (sample > 32767) {
return 255;
}
return (UINT8) ((sample >> 8) + 128);
}
/* conversion from/to 16 bit signed little endian to native endian samples */
#ifdef _LITTLE_ENDIAN
#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh))
#define MAP_SAMPLE2LE_SHORT(sample) (sample)
#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample)
#else
#define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh))
#define MAP_SAMPLE2LE_SHORT(sample) (INT16) MAP_SWAP16BIT(sample)
#define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample)
#endif
/* conversion from/to 16 bit signed big endian to native endian samples */
#ifndef _LITTLE_ENDIAN
#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh))
#define MAP_SAMPLE2BE_SHORT(sample) (sample)
#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample)
#else
#define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh))
#define MAP_SAMPLE2BE_SHORT(sample) ((INT16) MAP_SWAP16BIT(sample))
#define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample)
#endif
/* conversion from/to 8 bit samples */
#define MAP_INT82SAMPLE(by) ((MAP_Sample) (((INT32) ((INT8) (by))) << 8))
#define MAP_UINT82SAMPLE(by) ((MAP_Sample) (((INT32) ((UINT8) (by) - 128)) << 8))
#define MAP_SAMPLE2UINT8(sample) ((UINT8) ((((MAP_Sample) (sample)) >> 8) + 128))
#define MAP_SAMPLE2INT8(sample) ((INT8) (((MAP_Sample) (sample)) >> 8))
#define MAP_SAMPLE2UINT8_CLIP(sample) MAP_ClipAndConvertToUByte(sample)
#define MAP_SAMPLE2INT8_CLIP(sample) MAP_ClipAndConvertToByte(sample)
/* macros for endian conversion */
#ifdef _LITTLE_ENDIAN
#define MAP_NATIVE2LE16(a) (a)
#define MAP_NATIVE2BE16(a) MAP_SWAP16_impl(a)
#define MAP_NATIVE2LE32(a) (a)
#define MAP_NATIVE2BE32(a) MAP_SWAP32_impl(a)
#else
#define MAP_NATIVE2LE16(a) MAP_SWAP16_impl(a)
#define MAP_NATIVE2BE16(a) (a)
#define MAP_NATIVE2LE32(a) MAP_SWAP32_impl(a)
#define MAP_NATIVE2BE32(a) (a)
#endif
#define MAP_LE2NATIVE16(a) MAP_NATIVE2LE16(a)
#define MAP_BE2NATIVE16(a) MAP_NATIVE2BE16(a)
#define MAP_LE2NATIVE32(a) MAP_NATIVE2LE32(a)
#define MAP_BE2NATIVE32(a) MAP_NATIVE2BE32(a)
////////////////////////////// Utility function /////////////////////////////////
/*
* conversion of this buffer:
* conversion size=1 -> each byte is converted from signed to unsigned or vice versa
* conversion size=2,3,4: the order of bytes in a sample is reversed (endianness)
* for sign conversion of a 24-bit sample stored in 32bits, 4 should be passed
* as conversionSize
*/
void handleSignEndianConversion(INT8* data, INT8* output, int byteSize, int conversionSize) {
TRACE1("conversion with size %d\n", conversionSize);
switch (conversionSize) {
case 1: {
while (byteSize > 0) {
*output = *data + (char) 128; // use wrap-around
byteSize--;
data++;
output++;
}
break;
}
case 2: {
INT8 h;
byteSize = byteSize / 2;
while (byteSize > 0) {
h = *data;
data++;
*output = *data;
output++;
*output = h;
byteSize--;
data++; output++;
}
break;
}
case 3: {
INT8 h;
byteSize = byteSize / 3;
while (byteSize > 0) {
h = *data;
*output = data[2];
data++; output++;
*output = *data;
data++; output++;
*output = h;
data++; output++;
byteSize--;
}
break;
}
case 4: {
INT8 h1, h2;
byteSize = byteSize / 4;
while (byteSize > 0) {
h1 = data[0];
h2 = data[1];
*output = data[3]; output++;
*output = data[2]; output++;
*output = h2; output++;
*output = h1; output++;
data += 4;
byteSize--;
}
break;
}
default:
ERROR1("DirectAudioDevice.c: wrong conversionSize %d!\n", conversionSize);
}
}
/* aply the gain to one sample */
#define CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FACTOR) \
/* convert to MAP_Sample native type */ \
sample = TO_SAMPLE(*INPUT); \
/* apply gain */ \
sample = (MAP_Sample) (sample * FACTOR); \
/* convert to output type */ \
(*OUTPUT) = FROM_SAMPLE(sample); \
INPUT++; OUTPUT++
/* macro for conversion of a mono block */
#define LOOP_M(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \
if (leftGain > 1.0) { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE_CLIP, leftGain); \
} \
} else { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE, leftGain); \
} \
} \
break
/* macro for conversion of a stereo block */
#define LOOP_S(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \
if (leftGain > 1.0) { \
if (rightGain > 1.0) { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE_CLIP, leftGain); \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE_CLIP, rightGain); \
} \
} else { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE_CLIP, leftGain); \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE, rightGain); \
} \
} \
} else { \
if (rightGain > 1.0) { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE, leftGain); \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE_CLIP, rightGain); \
} \
} else { \
for ( ; len > 0; --len) { \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE, leftGain); \
CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, \
FROM_SAMPLE, rightGain); \
} \
} \
} \
break
#define FORMAT2CODE(channels, bits, inSigned, outSigned, inBigEndian, outBigEndian) \
(channels << 20) \
| (bits << 4) \
| ((inSigned & 1) << 3) \
| ((outSigned & 1) << 2) \
| ((inBigEndian & 1) << 1) \
| (outBigEndian & 1)
#define FORMAT2CODE8(channels, inSigned, outSigned) \
FORMAT2CODE(channels, 8, inSigned, outSigned, 0, 0)
#define FORMAT2CODE16(channels, inBigEndian, outBigEndian) \
FORMAT2CODE(channels, 16, 1, 1, inBigEndian, outBigEndian)
void handleGainAndConversion(DAUDIO_Info* info, UINT8* input, UINT8* output,
int len, float leftGain, float rightGain,
int conversionSize) {
INT8* input8 = (INT8*) input;
INT8* output8 = (INT8*) output;
INT16* input16 = (INT16*) input;
INT16* output16 = (INT16*) output;
MAP_Sample sample;
int inIsSigned = info->isSigned;
int inIsBigEndian = info->isBigEndian;
if (conversionSize == 1) {
/* 8-bit conversion: change sign */
inIsSigned = !inIsSigned;
}
else if (conversionSize > 1) {
/* > 8-bit conversion: change endianness */
inIsBigEndian = !inIsBigEndian;
}
if (info->frameSize <= 0) {
ERROR1("DirectAudiODevice: invalid framesize=%d\n", info->frameSize);
return;
}
len /= info->frameSize;
TRACE3("handleGainAndConversion: len=%d frames, leftGain=%f, rightGain=%f, ",
len, leftGain, rightGain);
TRACE3("channels=%d, sampleSizeInBits=%d, frameSize=%d, ",
(int) info->channels, (int) info->sampleSizeInBits, (int) info->frameSize);
TRACE4("signed:%d -> %d, endian: %d -> %d",
(int) inIsSigned, (int) info->isSigned,
(int) inIsBigEndian, (int) info->isBigEndian);
TRACE1("convSize=%d\n", conversionSize);
switch (FORMAT2CODE(info->channels,
info->sampleSizeInBits,
inIsSigned,
info->isSigned,
inIsBigEndian,
info->isBigEndian)) {
/* 8-bit mono */
case FORMAT2CODE8(1, 0, 0):
LOOP_M(input8, output8, MAP_UINT82SAMPLE,
MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
case FORMAT2CODE8(1, 0, 1):
LOOP_M(input8, output8, MAP_UINT82SAMPLE,
MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
case FORMAT2CODE8(1, 1, 0):
LOOP_M(input8, output8, MAP_INT82SAMPLE,
MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
case FORMAT2CODE8(1, 1, 1):
LOOP_M(input8, output8, MAP_INT82SAMPLE,
MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
/* 8-bit stereo */
case FORMAT2CODE8(2, 0, 0):
LOOP_S(input8, output8, MAP_UINT82SAMPLE,
MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
case FORMAT2CODE8(2, 0, 1):
LOOP_S(input8, output8, MAP_UINT82SAMPLE,
MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
case FORMAT2CODE8(2, 1, 0):
LOOP_S(input8, output8, MAP_INT82SAMPLE,
MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
case FORMAT2CODE8(2, 1, 1):
LOOP_S(input8, output8, MAP_INT82SAMPLE,
MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
/* 16-bit mono (only signed is accepted) */
case FORMAT2CODE16(1, 0, 0):
LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE,
MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
case FORMAT2CODE16(1, 0, 1):
LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE,
MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
case FORMAT2CODE16(1, 1, 0):
LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE,
MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
case FORMAT2CODE16(1, 1, 1):
LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE,
MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
/* 16-bit stereo (only signed is accepted) */
case FORMAT2CODE16(2, 0, 0):
LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE,
MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
case FORMAT2CODE16(2, 0, 1):
LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE,
MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
case FORMAT2CODE16(2, 1, 0):
LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE,
MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
case FORMAT2CODE16(2, 1, 1):
LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE,
MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
default:
ERROR3("DirectAudioDevice: Cannot convert from native format: "
"bits=%d, inSigned=%d outSigned=%d, ",
(int) info->sampleSizeInBits,
(int) inIsSigned, (int) info->isSigned);
ERROR2("inBigEndian=%d, outBigEndian=%d\n",
(int) inIsBigEndian, (int) info->isBigEndian);
}
}
float ABS_VALUE(float a) {
return (a < 0)?-a:a;
}
//////////////////////////////////////////// DirectAudioDevice ////////////////////////////////////////////
/* ************************************** native control creation support ********************* */
// contains all the needed references so that the platform dependent code can call JNI wrapper functions
typedef struct tag_AddFormatCreator {
// general JNI variables
JNIEnv *env;
// the vector to be filled with the formats
jobject vector;
// the class containing the addFormat method
jclass directAudioDeviceClass;
// the method to be called to add the format
jmethodID addFormat; // signature (Ljava/util/Vector;IIFIBB)V
} AddFormatCreator;
void DAUDIO_AddAudioFormat(void* creatorV, int significantBits, int frameSizeInBytes,
int channels, float sampleRate,
int encoding, int isSigned,
int bigEndian) {
AddFormatCreator* creator = (AddFormatCreator*) creatorV;
if (frameSizeInBytes <= 0) {
if (channels > 0) {
frameSizeInBytes = ((significantBits + 7) / 8) * channels;
} else {
frameSizeInBytes = -1;
}
}
TRACE4("AddAudioFormat with sigBits=%d bits, frameSize=%d bytes, channels=%d, sampleRate=%d ",
significantBits, frameSizeInBytes, channels, (int) sampleRate);
TRACE3("enc=%d, signed=%d, bigEndian=%d\n", encoding, isSigned, bigEndian);
(*creator->env)->CallStaticVoidMethod(creator->env, creator->directAudioDeviceClass,
creator->addFormat, creator->vector, significantBits, frameSizeInBytes,
channels, sampleRate, encoding, isSigned, bigEndian);
}
////////////////////////////////////// JNI /////////////////////////////////////////////////////////////////////
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nGetFormats
* Signature: (IIZLjava/util/Vector;)V
*/
JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetFormats
(JNIEnv *env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, jobject formats) {
#if USE_DAUDIO == TRUE
AddFormatCreator creator;
creator.env = env;
creator.vector = formats;
creator.directAudioDeviceClass = clazz;
creator.addFormat = (*env)->GetStaticMethodID(env, clazz, "addFormat",
"(Ljava/util/Vector;IIIFIZZ)V");
if (creator.addFormat == NULL) {
ERROR0("Could not get method ID for addFormat!\n");
} else {
DAUDIO_GetFormats((INT32) mixerIndex, (INT32) deviceID, (int) isSource, &creator);
}
#endif
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nOpen
* Signature: (IIZIFIIZZI)J
*/
JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nOpen
(JNIEnv* env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource,
jint encoding, jfloat sampleRate, jint sampleSizeInBits, jint frameSize, jint channels,
jboolean isSigned, jboolean isBigendian, jint bufferSizeInBytes) {
DAUDIO_Info* info = NULL;
#if USE_DAUDIO == TRUE
info = (DAUDIO_Info*) malloc(sizeof(DAUDIO_Info));
if (info == NULL) {
ERROR0("DirectAudioDevice_nOpen: Out of memory!\n");
} else {
info->handle =DAUDIO_Open((int) mixerIndex, (INT32) deviceID, (int) isSource,
(int) encoding, (float) sampleRate, (int) sampleSizeInBits,
(int) frameSize, (int) channels,
(int) isSigned, (int) isBigendian, (int) bufferSizeInBytes);
if (!info->handle) {
free(info);
info = NULL;
} else {
info->encoding = encoding;
info->sampleSizeInBits = sampleSizeInBits;
info->frameSize = frameSize;
info->channels = channels;
info->isSigned = isSigned;
info->isBigEndian = isBigendian && (sampleSizeInBits > 8);
/* will be populated on demand */
info->conversionBuffer = NULL;
info->conversionBufferSize = 0;
}
}
#endif
return (jlong) (UINT_PTR) info;
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nStart
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStart
(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
#if USE_DAUDIO == TRUE
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
if (info && info->handle) {
DAUDIO_Start(info->handle, (int) isSource);
}
#endif
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nStop
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStop
(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
#if USE_DAUDIO == TRUE
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
if (info && info->handle) {
DAUDIO_Stop(info->handle, (int) isSource);
}
#endif
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nClose
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nClose
(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
#if USE_DAUDIO == TRUE
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
if (info && info->handle) {
DAUDIO_Close(info->handle, (int) isSource);
if (info->conversionBuffer) {
free(info->conversionBuffer);
}
free(info);
}
#endif
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nWrite
* Signature: (J[BII)I
*/
JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nWrite
(JNIEnv *env, jclass clazz, jlong id, jbyteArray jData,
jint offset, jint len, jint conversionSize, jfloat leftGain, jfloat rightGain) {
int ret = -1;
#if USE_DAUDIO == TRUE
UINT8* data;
UINT8* dataOffset;
UINT8* convertedData;
jboolean didCopy;
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
/* a little sanity */
if (offset < 0 || len < 0) {
ERROR2("nWrite: wrong parameters: offset=%d, len=%d\n", offset, len);
return ret;
}
if (len == 0) return 0;
if (info && info->handle) {
data = (UINT8*) ((*env)->GetByteArrayElements(env, jData, &didCopy));
CHECK_NULL_RETURN(data, ret);
dataOffset = data;
dataOffset += (int) offset;
convertedData = dataOffset;
if (conversionSize > 0 || leftGain != 1.0f || rightGain != 1.0f) {
/* make sure we have a buffer for the intermediate data */
if (didCopy == JNI_FALSE) {
/* let's do our own copy */
if (info->conversionBuffer
&& info->conversionBufferSize < len) {
free(info->conversionBuffer);
info->conversionBuffer = NULL;
info->conversionBufferSize = 0;
}
if (!info->conversionBuffer) {
info->conversionBuffer = (UINT8*) malloc(len);
if (!info->conversionBuffer) {
// do not commit the native array
(*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT);
return -1;
}
info->conversionBufferSize = len;
}
convertedData = info->conversionBuffer;
}
if (((ABS_VALUE(leftGain - 1.0f) < 0.01)
&& (ABS_VALUE(rightGain - 1.0f) < 0.01))
|| info->encoding!=DAUDIO_PCM
|| ((info->channels * info->sampleSizeInBits / 8) != info->frameSize)
|| (info->sampleSizeInBits != 8 && info->sampleSizeInBits != 16)) {
handleSignEndianConversion((INT8*) dataOffset, (INT8*) convertedData, (int) len,
(int) conversionSize);
} else {
handleGainAndConversion(info, dataOffset, convertedData,
(int) len, (float) leftGain, (float) rightGain,
(int) conversionSize);
}
}
ret = DAUDIO_Write(info->handle, (INT8*) convertedData, (int) len);
// do not commit the native array
(*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT);
}
#endif
return (jint) ret;
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nRead
* Signature: (J[BII)I
*/
JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRead
(JNIEnv* env, jclass clazz, jlong id, jbyteArray jData, jint offset, jint len, jint conversionSize) {
int ret = -1;
#if USE_DAUDIO == TRUE
char* data;
char* dataOffset;
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
/* a little sanity */
if (offset < 0 || len < 0) {
ERROR2("nRead: wrong parameters: offset=%d, len=%d\n", offset, len);
return ret;
}
if (info && info->handle) {
data = (char*) ((*env)->GetByteArrayElements(env, jData, NULL));
CHECK_NULL_RETURN(data, ret);
dataOffset = data;
dataOffset += (int) offset;
ret = DAUDIO_Read(info->handle, dataOffset, (int) len);
if (conversionSize > 0) {
handleSignEndianConversion(dataOffset, dataOffset, (int) len, (int) conversionSize);
}
// commit the native array
(*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, 0);
}
#endif
return (jint) ret;
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nGetBufferSize
* Signature: (JZ)I
*/
JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize
(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
int ret = -1;
#if USE_DAUDIO == TRUE
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
if (info && info->handle) {
ret = DAUDIO_GetBufferSize(info->handle, (int) isSource);
}
#endif
return (jint) ret;
}
/*
* Class: com_sun_media_sound_DirectAudioDevice
* Method: nIsStillDraining
* Signature: (JZ)Z
*/
JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining
(JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
int ret = FALSE;
#if USE_DAUDIO == TRUE
DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
/**代码未完, 请加载全部代码(NowJava.com).**/