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