1 /*
   2  * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /* TODO:
  27  * - move all the conversion code into an own file
  28  */
  29 
  30 #define USE_TRACE
  31 #define USE_ERROR
  32 
  33 
  34 #include <jni.h>
  35 // for malloc
  36 #include <malloc.h>
  37 #include "SoundDefs.h"
  38 #include "DirectAudio.h"
  39 #include "Utilities.h"
  40 #include "com_sun_media_sound_DirectAudioDevice.h"
  41 
  42 
  43 typedef struct {
  44     void* handle;
  45     int encoding;
  46     int sampleSizeInBits;
  47     int frameSize;
  48     int channels;
  49     int isSigned;
  50     int isBigEndian;
  51     UINT8* conversionBuffer;
  52     int conversionBufferSize;
  53 } DAUDIO_Info;
  54 
  55 
  56 //////////////////////////////////////////// MAP Conversion stuff /////////////////////////////////
  57 
  58 /* 16 bit signed sample, native endianness, stored in 32-bits */
  59 typedef INT32 MAP_Sample;
  60 
  61 INLINE UINT16 MAP_SWAP16_impl(UINT16 a) {
  62     return (a>>8) | (a<<8);
  63 }
  64 
  65 INLINE UINT32 MAP_SWAP32_impl(UINT32 a) {
  66     return (a>>24)
  67         | ((a>>8) & 0xFF00)
  68         | ((a<<8) & 0xFF0000)
  69         | (a<<24);
  70 }
  71 
  72 INLINE UINT32 MAP_SWAP16BIT(UINT32 sh) {
  73     return (UINT32) ((sh & 0xFF) << 8) | ((sh & 0xFF00) >> 8);
  74 }
  75 
  76 INLINE INT32 MAP_ClipAndConvertToShort(MAP_Sample sample) {
  77     if (sample < -32768) {
  78         return -32768;
  79     }
  80     else if (sample > 32767) {
  81         return 32767;
  82     }
  83     return (INT32) sample;
  84 }
  85 
  86 
  87 INLINE INT32 MAP_ClipAndConvertToShort_Swapped(MAP_Sample sample) {
  88     if (sample < -32768) {
  89         return 0x0080;
  90     }
  91     else if (sample > 32767) {
  92         return 0xFF7F;
  93     }
  94     return (INT32) (INT16) MAP_SWAP16BIT(sample);
  95 }
  96 
  97 INLINE INT8 MAP_ClipAndConvertToByte(MAP_Sample sample) {
  98     if (sample < -32768) {
  99         return -128;
 100     }
 101     else if (sample > 32767) {
 102         return 127;
 103     }
 104     return (INT8) (sample >> 8);
 105 }
 106 
 107 
 108 INLINE UINT8 MAP_ClipAndConvertToUByte(MAP_Sample sample) {
 109     if (sample < -32768) {
 110         return 0;
 111     }
 112     else if (sample > 32767) {
 113         return 255;
 114     }
 115     return (UINT8) ((sample >> 8) + 128);
 116 }
 117 
 118 /* conversion from/to 16 bit signed little endian to native endian samples */
 119 #ifdef _LITTLE_ENDIAN
 120 #define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh))
 121 #define MAP_SAMPLE2LE_SHORT(sample) (sample)
 122 #define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample)
 123 #else
 124 #define MAP_LE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh))
 125 #define MAP_SAMPLE2LE_SHORT(sample) (INT16) MAP_SWAP16BIT(sample)
 126 #define MAP_SAMPLE2LE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample)
 127 #endif
 128 
 129 /* conversion from/to 16 bit signed big endian to native endian samples */
 130 #ifndef _LITTLE_ENDIAN
 131 #define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (sh))
 132 #define MAP_SAMPLE2BE_SHORT(sample) (sample)
 133 #define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort(sample)
 134 #else
 135 #define MAP_BE_SHORT2SAMPLE(sh) ((MAP_Sample) (INT16) MAP_SWAP16BIT(sh))
 136 #define MAP_SAMPLE2BE_SHORT(sample) ((INT16) MAP_SWAP16BIT(sample))
 137 #define MAP_SAMPLE2BE_SHORT_CLIP(sample) MAP_ClipAndConvertToShort_Swapped(sample)
 138 #endif
 139 
 140 /* conversion from/to 8 bit samples */
 141 #define MAP_INT82SAMPLE(by) ((MAP_Sample) (((INT32) ((INT8) (by))) << 8))
 142 #define MAP_UINT82SAMPLE(by) ((MAP_Sample) (((INT32) ((UINT8) (by) - 128)) << 8))
 143 #define MAP_SAMPLE2UINT8(sample) ((UINT8) ((((MAP_Sample) (sample)) >> 8) + 128))
 144 #define MAP_SAMPLE2INT8(sample) ((INT8) (((MAP_Sample) (sample)) >> 8))
 145 #define MAP_SAMPLE2UINT8_CLIP(sample) MAP_ClipAndConvertToUByte(sample)
 146 #define MAP_SAMPLE2INT8_CLIP(sample) MAP_ClipAndConvertToByte(sample)
 147 
 148 /* macros for endian conversion */
 149 #ifdef _LITTLE_ENDIAN
 150 #define MAP_NATIVE2LE16(a) (a)
 151 #define MAP_NATIVE2BE16(a) MAP_SWAP16_impl(a)
 152 #define MAP_NATIVE2LE32(a) (a)
 153 #define MAP_NATIVE2BE32(a) MAP_SWAP32_impl(a)
 154 #else
 155 #define MAP_NATIVE2LE16(a) MAP_SWAP16_impl(a)
 156 #define MAP_NATIVE2BE16(a) (a)
 157 #define MAP_NATIVE2LE32(a) MAP_SWAP32_impl(a)
 158 #define MAP_NATIVE2BE32(a) (a)
 159 #endif
 160 #define MAP_LE2NATIVE16(a) MAP_NATIVE2LE16(a)
 161 #define MAP_BE2NATIVE16(a) MAP_NATIVE2BE16(a)
 162 #define MAP_LE2NATIVE32(a) MAP_NATIVE2LE32(a)
 163 #define MAP_BE2NATIVE32(a) MAP_NATIVE2BE32(a)
 164 
 165 
 166 ////////////////////////////// Utility function /////////////////////////////////
 167 
 168 /*
 169  * conversion of this buffer:
 170  * conversion size=1 -> each byte is converted from signed to unsigned or vice versa
 171  * conversion size=2,3,4: the order of bytes in a sample is reversed (endianness)
 172  * for sign conversion of a 24-bit sample stored in 32bits, 4 should be passed
 173  * as conversionSize
 174  */
 175 void handleSignEndianConversion(INT8* data, INT8* output, int byteSize, int conversionSize) {
 176     TRACE1("conversion with size %d\n", conversionSize);
 177     switch (conversionSize) {
 178     case 1: {
 179         while (byteSize > 0) {
 180             *output = *data + (char) 128; // use wrap-around
 181             byteSize--;
 182             data++;
 183             output++;
 184         }
 185         break;
 186     }
 187     case 2: {
 188         INT8 h;
 189         byteSize = byteSize / 2;
 190         while (byteSize > 0) {
 191             h = *data;
 192             data++;
 193             *output = *data;
 194             output++;
 195             *output = h;
 196             byteSize--;
 197             data++; output++;
 198         }
 199         break;
 200     }
 201     case 3: {
 202         INT8 h;
 203         byteSize = byteSize / 3;
 204         while (byteSize > 0) {
 205             h = *data;
 206             *output = data[2];
 207             data++; output++;
 208             *output = *data;
 209             data++; output++;
 210             *output = h;
 211             data++; output++;
 212             byteSize--;
 213         }
 214         break;
 215     }
 216     case 4: {
 217         INT8 h1, h2;
 218         byteSize = byteSize / 4;
 219         while (byteSize > 0) {
 220             h1 = data[0];
 221             h2 = data[1];
 222             *output = data[3]; output++;
 223             *output = data[2]; output++;
 224             *output = h2; output++;
 225             *output = h1; output++;
 226             data += 4;
 227             byteSize--;
 228         }
 229         break;
 230     }
 231     default:
 232         ERROR1("DirectAudioDevice.c: wrong conversionSize %d!\n", conversionSize);
 233     }
 234 }
 235 
 236 /* aply the gain to one sample */
 237 #define CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FACTOR) \
 238     /* convert to MAP_Sample native type */     \
 239     sample = TO_SAMPLE(*INPUT);                 \
 240     /* apply gain */                            \
 241     sample = (MAP_Sample) (sample * FACTOR);    \
 242     /* convert to output type */                \
 243     (*OUTPUT) = FROM_SAMPLE(sample);            \
 244     INPUT++; OUTPUT++
 245 
 246 
 247 /* macro for conversion of a mono block */
 248 #define LOOP_M(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \
 249     if (leftGain > 1.0) {                                               \
 250         for ( ; len > 0; --len) {                                       \
 251             CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                    \
 252                            FROM_SAMPLE_CLIP, leftGain);                 \
 253         }                                                               \
 254     } else {                                                            \
 255         for ( ; len > 0; --len) {                                       \
 256             CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                    \
 257                            FROM_SAMPLE, leftGain);                      \
 258         }                                                               \
 259     }                                                                   \
 260     break
 261 
 262 /* macro for conversion of a stereo block */
 263 #define LOOP_S(INPUT, OUTPUT, TO_SAMPLE, FROM_SAMPLE, FROM_SAMPLE_CLIP) \
 264     if (leftGain > 1.0) {                                               \
 265         if (rightGain > 1.0) {                                          \
 266             for ( ; len > 0; --len) {                                   \
 267                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 268                                FROM_SAMPLE_CLIP, leftGain);             \
 269                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 270                                FROM_SAMPLE_CLIP, rightGain);            \
 271             }                                                           \
 272         } else {                                                        \
 273             for ( ; len > 0; --len) {                                   \
 274                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 275                                FROM_SAMPLE_CLIP, leftGain);             \
 276                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 277                                FROM_SAMPLE, rightGain);                 \
 278             }                                                           \
 279         }                                                               \
 280     } else {                                                            \
 281         if (rightGain > 1.0) {                                          \
 282             for ( ; len > 0; --len) {                                   \
 283                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 284                                FROM_SAMPLE, leftGain);                  \
 285                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 286                                FROM_SAMPLE_CLIP, rightGain);            \
 287             }                                                           \
 288         } else {                                                        \
 289             for ( ; len > 0; --len) {                                   \
 290                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 291                                FROM_SAMPLE, leftGain);                  \
 292                 CONVERT_SAMPLE(INPUT, OUTPUT, TO_SAMPLE,                \
 293                                FROM_SAMPLE, rightGain);                 \
 294             }                                                           \
 295         }                                                               \
 296     }                                                                   \
 297     break
 298 
 299 #define FORMAT2CODE(channels, bits, inSigned, outSigned, inBigEndian, outBigEndian) \
 300       (channels << 20)                                                  \
 301     | (bits << 4)                                                       \
 302     | ((inSigned & 1) << 3)                                             \
 303     | ((outSigned & 1) << 2)                                            \
 304     | ((inBigEndian & 1) << 1)                                          \
 305     | (outBigEndian & 1)
 306 
 307 #define FORMAT2CODE8(channels, inSigned, outSigned)           \
 308     FORMAT2CODE(channels, 8, inSigned, outSigned, 0, 0)
 309 
 310 #define FORMAT2CODE16(channels, inBigEndian, outBigEndian)    \
 311     FORMAT2CODE(channels, 16, 1, 1, inBigEndian, outBigEndian)
 312 
 313 
 314 void handleGainAndConversion(DAUDIO_Info* info, UINT8* input, UINT8* output,
 315                              int len, float leftGain, float rightGain,
 316                              int conversionSize) {
 317     INT8* input8 = (INT8*) input;
 318     INT8* output8 = (INT8*) output;
 319     INT16* input16 = (INT16*) input;
 320     INT16* output16 = (INT16*) output;
 321     MAP_Sample sample;
 322 
 323     int inIsSigned = info->isSigned;
 324     int inIsBigEndian = info->isBigEndian;
 325     if (conversionSize == 1) {
 326         /* 8-bit conversion: change sign */
 327         inIsSigned = !inIsSigned;
 328     }
 329     else if (conversionSize > 1) {
 330         /* > 8-bit conversion: change endianness */
 331         inIsBigEndian = !inIsBigEndian;
 332     }
 333     if (info->frameSize <= 0) {
 334         ERROR1("DirectAudiODevice: invalid framesize=%d\n", info->frameSize);
 335         return;
 336     }
 337     len /= info->frameSize;
 338     TRACE3("handleGainAndConversion: len=%d frames, leftGain=%f, rightGain=%f, ",
 339            len, leftGain, rightGain);
 340     TRACE3("channels=%d, sampleSizeInBits=%d, frameSize=%d, ",
 341            (int) info->channels, (int) info->sampleSizeInBits, (int) info->frameSize);
 342     TRACE4("signed:%d -> %d, endian: %d -> %d",
 343            (int) inIsSigned, (int) info->isSigned,
 344            (int) inIsBigEndian, (int) info->isBigEndian);
 345     TRACE1("convSize=%d\n", conversionSize);
 346 
 347     switch (FORMAT2CODE(info->channels,
 348                         info->sampleSizeInBits,
 349                         inIsSigned,
 350                         info->isSigned,
 351                         inIsBigEndian,
 352                         info->isBigEndian)) {
 353         /* 8-bit mono */
 354     case FORMAT2CODE8(1, 0, 0):
 355         LOOP_M(input8, output8, MAP_UINT82SAMPLE,
 356                MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
 357     case FORMAT2CODE8(1, 0, 1):
 358         LOOP_M(input8, output8, MAP_UINT82SAMPLE,
 359                MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
 360     case FORMAT2CODE8(1, 1, 0):
 361         LOOP_M(input8, output8, MAP_INT82SAMPLE,
 362                MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
 363     case FORMAT2CODE8(1, 1, 1):
 364         LOOP_M(input8, output8, MAP_INT82SAMPLE,
 365                MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
 366 
 367     /* 8-bit stereo */
 368     case FORMAT2CODE8(2, 0, 0):
 369         LOOP_S(input8, output8, MAP_UINT82SAMPLE,
 370                MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
 371     case FORMAT2CODE8(2, 0, 1):
 372         LOOP_S(input8, output8, MAP_UINT82SAMPLE,
 373                MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
 374     case FORMAT2CODE8(2, 1, 0):
 375         LOOP_S(input8, output8, MAP_INT82SAMPLE,
 376                MAP_SAMPLE2UINT8, MAP_SAMPLE2UINT8_CLIP);
 377     case FORMAT2CODE8(2, 1, 1):
 378         LOOP_S(input8, output8, MAP_INT82SAMPLE,
 379                MAP_SAMPLE2INT8, MAP_SAMPLE2INT8_CLIP);
 380 
 381     /* 16-bit mono (only signed is accepted) */
 382     case FORMAT2CODE16(1, 0, 0):
 383         LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE,
 384                MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
 385     case FORMAT2CODE16(1, 0, 1):
 386         LOOP_M(input16, output16, MAP_LE_SHORT2SAMPLE,
 387                MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
 388     case FORMAT2CODE16(1, 1, 0):
 389         LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE,
 390                MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
 391     case FORMAT2CODE16(1, 1, 1):
 392         LOOP_M(input16, output16, MAP_BE_SHORT2SAMPLE,
 393                MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
 394 
 395     /* 16-bit stereo (only signed is accepted) */
 396     case FORMAT2CODE16(2, 0, 0):
 397         LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE,
 398                MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
 399     case FORMAT2CODE16(2, 0, 1):
 400         LOOP_S(input16, output16, MAP_LE_SHORT2SAMPLE,
 401                MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
 402     case FORMAT2CODE16(2, 1, 0):
 403         LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE,
 404                MAP_SAMPLE2LE_SHORT, MAP_SAMPLE2LE_SHORT_CLIP);
 405     case FORMAT2CODE16(2, 1, 1):
 406         LOOP_S(input16, output16, MAP_BE_SHORT2SAMPLE,
 407                MAP_SAMPLE2BE_SHORT, MAP_SAMPLE2BE_SHORT_CLIP);
 408 
 409     default:
 410         ERROR3("DirectAudioDevice: Cannot convert from native format: "
 411                "bits=%d, inSigned=%d  outSigned=%d, ",
 412                (int) info->sampleSizeInBits,
 413                (int) inIsSigned, (int) info->isSigned);
 414         ERROR2("inBigEndian=%d, outBigEndian=%d\n",
 415                (int) inIsBigEndian, (int) info->isBigEndian);
 416     }
 417 }
 418 
 419 float ABS_VALUE(float a) {
 420     return (a < 0)?-a:a;
 421 }
 422 
 423 
 424 //////////////////////////////////////////// DirectAudioDevice ////////////////////////////////////////////
 425 
 426 /* ************************************** native control creation support ********************* */
 427 
 428 // contains all the needed references so that the platform dependent code can call JNI wrapper functions
 429 typedef struct tag_AddFormatCreator {
 430     // general JNI variables
 431     JNIEnv *env;
 432     // the vector to be filled with the formats
 433     jobject vector;
 434     // the class containing the addFormat method
 435     jclass directAudioDeviceClass;
 436     // the method to be called to add the format
 437     jmethodID addFormat; // signature (Ljava/util/Vector;IIFIBB)V
 438 } AddFormatCreator;
 439 
 440 void DAUDIO_AddAudioFormat(void* creatorV, int significantBits, int frameSizeInBytes,
 441                            int channels, float sampleRate,
 442                            int encoding, int isSigned,
 443                            int bigEndian) {
 444     AddFormatCreator* creator = (AddFormatCreator*) creatorV;
 445     if (frameSizeInBytes <= 0) {
 446         if (channels > 0) {
 447             frameSizeInBytes = ((significantBits + 7) / 8) * channels;
 448         } else {
 449             frameSizeInBytes = -1;
 450         }
 451     }
 452     TRACE4("AddAudioFormat with sigBits=%d bits, frameSize=%d bytes, channels=%d, sampleRate=%d ",
 453            significantBits, frameSizeInBytes, channels, (int) sampleRate);
 454     TRACE3("enc=%d, signed=%d, bigEndian=%d\n", encoding, isSigned, bigEndian);
 455     (*creator->env)->CallStaticVoidMethod(creator->env, creator->directAudioDeviceClass,
 456                                           creator->addFormat, creator->vector, significantBits, frameSizeInBytes,
 457                                           channels, sampleRate, encoding, isSigned, bigEndian);
 458 }
 459 
 460 ////////////////////////////////////// JNI /////////////////////////////////////////////////////////////////////
 461 
 462 /*
 463  * Class:     com_sun_media_sound_DirectAudioDevice
 464  * Method:    nGetFormats
 465  * Signature: (IIZLjava/util/Vector;)V
 466  */
 467 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetFormats
 468 (JNIEnv *env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource, jobject formats) {
 469 
 470 #if USE_DAUDIO == TRUE
 471     AddFormatCreator creator;
 472     creator.env = env;
 473     creator.vector = formats;
 474     creator.directAudioDeviceClass = clazz;
 475     creator.addFormat = (*env)->GetStaticMethodID(env, clazz, "addFormat",
 476                                                   "(Ljava/util/Vector;IIIFIZZ)V");
 477     if (creator.addFormat == NULL) {
 478         ERROR0("Could not get method ID for addFormat!\n");
 479     } else {
 480         DAUDIO_GetFormats((INT32) mixerIndex, (INT32) deviceID, (int) isSource, &creator);
 481     }
 482 #endif
 483 }
 484 
 485 
 486 
 487 /*
 488  * Class:     com_sun_media_sound_DirectAudioDevice
 489  * Method:    nOpen
 490  * Signature: (IIZIFIIZZI)J
 491  */
 492 JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nOpen
 493 (JNIEnv* env, jclass clazz, jint mixerIndex, jint deviceID, jboolean isSource,
 494  jint encoding, jfloat sampleRate, jint sampleSizeInBits, jint frameSize, jint channels,
 495  jboolean isSigned, jboolean isBigendian, jint bufferSizeInBytes) {
 496 
 497     DAUDIO_Info* info = NULL;
 498 #if USE_DAUDIO == TRUE
 499 
 500     info = (DAUDIO_Info*) malloc(sizeof(DAUDIO_Info));
 501     if (info == NULL) {
 502         ERROR0("DirectAudioDevice_nOpen: Out of memory!\n");
 503     } else {
 504         info->handle =DAUDIO_Open((int) mixerIndex, (INT32) deviceID, (int) isSource,
 505                                   (int) encoding, (float) sampleRate, (int) sampleSizeInBits,
 506                                   (int) frameSize, (int) channels,
 507                                   (int) isSigned, (int) isBigendian, (int) bufferSizeInBytes);
 508         if (!info->handle) {
 509             free(info);
 510             info = NULL;
 511         } else {
 512             info->encoding = encoding;
 513             info->sampleSizeInBits = sampleSizeInBits;
 514             info->frameSize = frameSize;
 515             info->channels = channels;
 516             info->isSigned = isSigned;
 517             info->isBigEndian = isBigendian && (sampleSizeInBits > 8);
 518             /* will be populated on demand */
 519             info->conversionBuffer = NULL;
 520             info->conversionBufferSize = 0;
 521         }
 522     }
 523 #endif
 524     return (jlong) (UINT_PTR) info;
 525 }
 526 
 527 /*
 528  * Class:     com_sun_media_sound_DirectAudioDevice
 529  * Method:    nStart
 530  * Signature: (JZ)V
 531  */
 532 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStart
 533 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 534 #if USE_DAUDIO == TRUE
 535     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 536     if (info && info->handle) {
 537         DAUDIO_Start(info->handle, (int) isSource);
 538     }
 539 #endif
 540 }
 541 
 542 
 543 /*
 544  * Class:     com_sun_media_sound_DirectAudioDevice
 545  * Method:    nStop
 546  * Signature: (JZ)V
 547  */
 548 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nStop
 549 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 550 #if USE_DAUDIO == TRUE
 551     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 552     if (info && info->handle) {
 553         DAUDIO_Stop(info->handle, (int) isSource);
 554     }
 555 #endif
 556 }
 557 
 558 
 559 /*
 560  * Class:     com_sun_media_sound_DirectAudioDevice
 561  * Method:    nClose
 562  * Signature: (JZ)V
 563  */
 564 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nClose
 565 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 566 #if USE_DAUDIO == TRUE
 567     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 568     if (info && info->handle) {
 569         DAUDIO_Close(info->handle, (int) isSource);
 570         if (info->conversionBuffer) {
 571             free(info->conversionBuffer);
 572         }
 573         free(info);
 574     }
 575 #endif
 576 }
 577 
 578 /*
 579  * Class:     com_sun_media_sound_DirectAudioDevice
 580  * Method:    nWrite
 581  * Signature: (J[BII)I
 582  */
 583 JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nWrite
 584 (JNIEnv *env, jclass clazz, jlong id, jbyteArray jData,
 585  jint offset, jint len, jint conversionSize, jfloat leftGain, jfloat rightGain) {
 586     int ret = -1;
 587 #if USE_DAUDIO == TRUE
 588     UINT8* data;
 589     UINT8* dataOffset;
 590     UINT8* convertedData;
 591     jboolean didCopy;
 592     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 593 
 594     /* a little sanity */
 595     if (offset < 0 || len < 0) {
 596         ERROR2("nWrite: wrong parameters: offset=%d, len=%d\n", offset, len);
 597         return ret;
 598     }
 599     if (len == 0) return 0;
 600     if (info && info->handle) {
 601         data = (UINT8*) ((*env)->GetByteArrayElements(env, jData, &didCopy));
 602         dataOffset = data;
 603         dataOffset += (int) offset;
 604         convertedData = dataOffset;
 605 
 606         if (conversionSize > 0 || leftGain != 1.0f || rightGain != 1.0f) {
 607             /* make sure we have a buffer for the intermediate data */
 608             if (didCopy == JNI_FALSE) {
 609                 /* let's do our own copy */
 610                 if (info->conversionBuffer
 611                     && info->conversionBufferSize < len) {
 612                     free(info->conversionBuffer);
 613                     info->conversionBuffer = NULL;
 614                     info->conversionBufferSize = 0;
 615                 }
 616                 if (!info->conversionBuffer) {
 617                     info->conversionBuffer = (UINT8*) malloc(len);
 618                     if (!info->conversionBuffer) {
 619                         // do not commit the native array
 620                         (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT);
 621                         return -1;
 622                     }
 623                     info->conversionBufferSize = len;
 624                 }
 625                 convertedData = info->conversionBuffer;
 626             }
 627             if (((ABS_VALUE(leftGain - 1.0f) < 0.01)
 628                  && (ABS_VALUE(rightGain - 1.0f) < 0.01))
 629                 || info->encoding!=DAUDIO_PCM
 630                 || ((info->channels * info->sampleSizeInBits / 8) != info->frameSize)
 631                 || (info->sampleSizeInBits != 8 && info->sampleSizeInBits != 16)) {
 632                 handleSignEndianConversion((INT8*) dataOffset, (INT8*) convertedData, (int) len,
 633                                            (int) conversionSize);
 634             } else {
 635                 handleGainAndConversion(info, dataOffset, convertedData,
 636                                         (int) len, (float) leftGain, (float) rightGain,
 637                                         (int) conversionSize);
 638             }
 639         }
 640 
 641         ret = DAUDIO_Write(info->handle, (INT8*) convertedData, (int) len);
 642 
 643         // do not commit the native array
 644         (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, JNI_ABORT);
 645     }
 646 #endif
 647     return (jint) ret;
 648 }
 649 
 650 /*
 651  * Class:     com_sun_media_sound_DirectAudioDevice
 652  * Method:    nRead
 653  * Signature: (J[BII)I
 654  */
 655 JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRead
 656 (JNIEnv* env, jclass clazz, jlong id, jbyteArray jData, jint offset, jint len, jint conversionSize) {
 657     int ret = -1;
 658 #if USE_DAUDIO == TRUE
 659     char* data;
 660     char* dataOffset;
 661     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 662 
 663     /* a little sanity */
 664     if (offset < 0 || len < 0) {
 665         ERROR2("nRead: wrong parameters: offset=%d, len=%d\n", offset, len);
 666         return ret;
 667     }
 668     if (info && info->handle) {
 669         data = (char*) ((*env)->GetByteArrayElements(env, jData, NULL));
 670         dataOffset = data;
 671         dataOffset += (int) offset;
 672         ret = DAUDIO_Read(info->handle, dataOffset, (int) len);
 673         if (conversionSize > 0) {
 674             handleSignEndianConversion(dataOffset, dataOffset, (int) len, (int) conversionSize);
 675         }
 676         // commit the native array
 677         (*env)->ReleaseByteArrayElements(env, jData, (jbyte*) data, 0);
 678     }
 679 #endif
 680     return (jint) ret;
 681 }
 682 
 683 /*
 684  * Class:     com_sun_media_sound_DirectAudioDevice
 685  * Method:    nGetBufferSize
 686  * Signature: (JZ)I
 687  */
 688 JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize
 689 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 690     int ret = -1;
 691 #if USE_DAUDIO == TRUE
 692     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 693     if (info && info->handle) {
 694         ret = DAUDIO_GetBufferSize(info->handle, (int) isSource);
 695     }
 696 #endif
 697     return (jint) ret;
 698 }
 699 
 700 
 701 /*
 702  * Class:     com_sun_media_sound_DirectAudioDevice
 703  * Method:    nIsStillDraining
 704  * Signature: (JZ)Z
 705  */
 706 JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining
 707 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 708     int ret = FALSE;
 709 #if USE_DAUDIO == TRUE
 710     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 711     if (info && info->handle) {
 712         ret = DAUDIO_StillDraining(info->handle, (int) isSource)?TRUE:FALSE;
 713     }
 714 #endif
 715     return (jboolean) ret;
 716 }
 717 
 718 
 719 /*
 720  * Class:     com_sun_media_sound_DirectAudioDevice
 721  * Method:    nFlush
 722  * Signature: (JZ)V
 723  */
 724 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nFlush
 725 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 726 #if USE_DAUDIO == TRUE
 727     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 728     if (info && info->handle) {
 729         DAUDIO_Flush(info->handle, (int) isSource);
 730     }
 731 #endif
 732 }
 733 
 734 
 735 /*
 736  * Class:     com_sun_media_sound_DirectAudioDevice
 737  * Method:    nAvailable
 738  * Signature: (JZ)I
 739  */
 740 JNIEXPORT jint JNICALL Java_com_sun_media_sound_DirectAudioDevice_nAvailable
 741 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 742     int ret = -1;
 743 #if USE_DAUDIO == TRUE
 744     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 745     if (info && info->handle) {
 746         ret = DAUDIO_GetAvailable(info->handle, (int) isSource);
 747     }
 748 #endif
 749     return (jint) ret;
 750 }
 751 
 752 
 753 /*
 754  * Class:     com_sun_media_sound_DirectAudioDevice
 755  * Method:    nGetBytePosition
 756  * Signature: (JZJ)J
 757  */
 758 JNIEXPORT jlong JNICALL Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition
 759 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong javaBytePos) {
 760     INT64 ret = (INT64) javaBytePos;
 761 #if USE_DAUDIO == TRUE
 762     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 763     if (info && info->handle) {
 764         ret = DAUDIO_GetBytePosition(info->handle, (int) isSource, (INT64) javaBytePos);
 765     }
 766 #endif
 767     return (jlong) ret;
 768 }
 769 
 770 /*
 771  * Class:     com_sun_media_sound_DirectAudioDevice
 772  * Method:    nSetBytePosition
 773  * Signature: (JZJ)V
 774  */
 775 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition
 776 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource, jlong pos) {
 777 #if USE_DAUDIO == TRUE
 778     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 779     if (info && info->handle) {
 780         DAUDIO_SetBytePosition(info->handle, (int) isSource, (INT64) pos);
 781     }
 782 #endif
 783 }
 784 
 785 /*
 786  * Class:     com_sun_media_sound_DirectAudioDevice
 787  * Method:    nRequiresServicing
 788  * Signature: (JZ)B
 789  */
 790 JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing
 791 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 792     int ret = FALSE;
 793 #if USE_DAUDIO == TRUE
 794     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 795     if (info && info->handle) {
 796         ret = DAUDIO_RequiresServicing(info->handle, (int) isSource);
 797     }
 798 #endif
 799     return (jboolean) ret;
 800 }
 801 /*
 802  * Class:     com_sun_media_sound_DirectAudioDevice
 803  * Method:    nService
 804  * Signature: (JZ)V
 805  */
 806 JNIEXPORT void JNICALL Java_com_sun_media_sound_DirectAudioDevice_nService
 807 (JNIEnv* env, jclass clazz, jlong id, jboolean isSource) {
 808 #if USE_DAUDIO == TRUE
 809     DAUDIO_Info* info = (DAUDIO_Info*) (UINT_PTR) id;
 810     if (info && info->handle) {
 811         DAUDIO_Service(info->handle, (int) isSource);
 812     }
 813 #endif
 814 }