| /* |
| * 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; |
| if (info && info->handle) { |
| ret = DAUDIO_StillDraining(info->handle, (int) isSource)?TRUE:FALSE; |
| } |
| #endif |
| return (jboolean) ret; |
| } |
| |
| |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nFlush |
| * Signature: (JZ)V |
| */ |
| JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nFlush |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| DAUDIO_Flush(info->handle, (int) isSource); |
| } |
| #endif |
| } |
| |
| |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nAvailable |
| * Signature: (JZ)I |
| */ |
| JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nAvailable |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { |
| int ret = -1; |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| ret = DAUDIO_GetAvailable(info->handle, (int) isSource); |
| } |
| #endif |
| return (jint) ret; |
| } |
| |
| |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nGetBytePosition |
| * Signature: (JZJ)J |
| */ |
| JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong javaBytePos) { |
| INT64 ret = (INT64) javaBytePos; |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| ret = DAUDIO_GetBytePosition(info->handle, (int) isSource, (INT64) javaBytePos); |
| } |
| #endif |
| return (jlong) ret; |
| } |
| |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nSetBytePosition |
| * Signature: (JZJ)V |
| */ |
| JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong pos) { |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| DAUDIO_SetBytePosition(info->handle, (int) isSource, (INT64) pos); |
| } |
| #endif |
| } |
| |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nRequiresServicing |
| * Signature: (JZ)B |
| */ |
| JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { |
| int ret = FALSE; |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| ret = DAUDIO_RequiresServicing(info->handle, (int) isSource); |
| } |
| #endif |
| return (jboolean) ret; |
| } |
| /* |
| * Class: com_sun_media_sound_DirectAudioDevice |
| * Method: nService |
| * Signature: (JZ)V |
| */ |
| JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nService |
| (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) { |
| #if USE_DAUDIO == TRUE |
| DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id; |
| if (info && info->handle) { |
| DAUDIO_Service(info->handle, (int) isSource); |
| } |
| #endif |
| } |