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 | |
48 | typedef 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 */ |
64 | typedef INT32 MAP_Sample; |
65 | |
66 | static INLINE UINT16 MAP_SWAP16_impl(UINT16 a) { |
67 | return (a>>8) | (a<<8); |
68 | } |
69 | |
70 | static INLINE UINT32 MAP_SWAP32_impl(UINT32 a) { |
71 | return (a>>24) |
72 | | ((a>>8) & 0xFF00) |
73 | | ((a<<8) & 0xFF0000) |
74 | | (a<<24); |
75 | } |
76 | |
77 | static INLINE UINT32 MAP_SWAP16BIT(UINT32 sh) { |
78 | return (UINT32) ((sh & 0xFF) << 8) | ((sh & 0xFF00) >> 8); |
79 | } |
80 | |
81 | static 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 | |
92 | static 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 | |
102 | static 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 | |
113 | static 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 | */ |
180 | void 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 | |
319 | void 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 | |
424 | float 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 |
434 | typedef 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 | |
445 | void 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 | */ |
472 | JNIEXPORT 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 | */ |
497 | JNIEXPORT 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 | */ |
537 | JNIEXPORT 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 | */ |
553 | JNIEXPORT 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 | */ |
569 | JNIEXPORT 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 | */ |
588 | JNIEXPORT 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 | */ |
661 | JNIEXPORT 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 | */ |
695 | JNIEXPORT 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 | */ |
713 | JNIEXPORT 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 | */ |
731 | JNIEXPORT 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 | */ |
747 | JNIEXPORT 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 | */ |
765 | JNIEXPORT 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 | */ |
782 | JNIEXPORT 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 | */ |
797 | JNIEXPORT 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 | */ |
813 | JNIEXPORT 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 | |