1 /*
2 * Copyright (c) 2002, 2020, 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 //#define USE_ERROR
27 //#define USE_TRACE
28 //#define USE_VERBOSE_TRACE
29
30 #include <AudioUnit/AudioUnit.h>
31 #include <AudioToolbox/AudioConverter.h>
32 #include <pthread.h>
33 #include <math.h>
34 /*
35 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
36 #include <CoreAudio/CoreAudioTypes.h>
37 #else
38 #include <CoreAudioTypes.h>
39 #endif
40 */
41
42 #include "PLATFORM_API_MacOSX_Utils.h"
43
44 extern "C" {
45 #include "Utilities.h"
46 #include "DirectAudio.h"
47 }
48
49 #if USE_DAUDIO == TRUE
50
51
52 #ifdef USE_TRACE
PrintStreamDesc(const AudioStreamBasicDescription * inDesc)53 static void PrintStreamDesc(const AudioStreamBasicDescription *inDesc) {
54 TRACE4("ID='%c%c%c%c'", (char)(inDesc->mFormatID >> 24), (char)(inDesc->mFormatID >> 16), (char)(inDesc->mFormatID >> 8), (char)(inDesc->mFormatID));
55 TRACE2(", %f Hz, flags=0x%lX", (float)inDesc->mSampleRate, (long unsigned)inDesc->mFormatFlags);
56 TRACE2(", %ld channels, %ld bits", (long)inDesc->mChannelsPerFrame, (long)inDesc->mBitsPerChannel);
57 TRACE1(", %ld bytes per frame\n", (long)inDesc->mBytesPerFrame);
58 }
59 #else
PrintStreamDesc(const AudioStreamBasicDescription * inDesc)60 static inline void PrintStreamDesc(const AudioStreamBasicDescription *inDesc) { }
61 #endif
62
63
64 #define MAX(x, y) ((x) >= (y) ? (x) : (y))
65 #define MIN(x, y) ((x) <= (y) ? (x) : (y))
66
67
68 // =======================================
69 // MixerProvider functions implementation
70
71 static DeviceList deviceCache;
72
DAUDIO_GetDirectAudioDeviceCount()73 INT32 DAUDIO_GetDirectAudioDeviceCount() {
74 deviceCache.Refresh();
75 int count = deviceCache.GetCount();
76 if (count > 0) {
77 // add "default" device
78 count++;
79 TRACE1("DAUDIO_GetDirectAudioDeviceCount: returns %d devices\n", count);
80 } else {
81 TRACE0("DAUDIO_GetDirectAudioDeviceCount: no devices found\n");
82 }
83 return count;
84 }
85
DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex,DirectAudioDeviceDescription * desc)86 INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription *desc) {
87 bool result = true;
88 desc->deviceID = 0;
89 if (mixerIndex == 0) {
90 // default device
91 strncpy(desc->name, "Default Audio Device", DAUDIO_STRING_LENGTH);
92 strncpy(desc->description, "Default Audio Device", DAUDIO_STRING_LENGTH);
93 desc->maxSimulLines = -1;
94 } else {
95 AudioDeviceID deviceID;
96 result = deviceCache.GetDeviceInfo(mixerIndex-1, &deviceID, DAUDIO_STRING_LENGTH,
97 desc->name, desc->vendor, desc->description, desc->version);
98 if (result) {
99 desc->deviceID = (INT32)deviceID;
100 desc->maxSimulLines = -1;
101 }
102 }
103 return result ? TRUE : FALSE;
104 }
105
106
DAUDIO_GetFormats(INT32 mixerIndex,INT32 deviceID,int isSource,void * creator)107 void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
108 TRACE3(">>DAUDIO_GetFormats mixerIndex=%d deviceID=0x%x isSource=%d\n", (int)mixerIndex, (int)deviceID, isSource);
109
110 AudioDeviceID audioDeviceID = deviceID == 0 ? GetDefaultDevice(isSource) : (AudioDeviceID)deviceID;
111
112 if (audioDeviceID == 0) {
113 return;
114 }
115
116 int totalChannels = GetChannelCount(audioDeviceID, isSource);
117
118 if (totalChannels == 0) {
119 TRACE0("<<DAUDIO_GetFormats, no streams!\n");
120 return;
121 }
122
123 if (isSource && totalChannels < 2) {
124 // report 2 channels even if only mono is supported
125 totalChannels = 2;
126 }
127
128 int channels[] = {1, 2, totalChannels};
129 int channelsCount = MIN(totalChannels, 3);
130
131 float hardwareSampleRate = GetSampleRate(audioDeviceID, isSource);
132 TRACE2(" DAUDIO_GetFormats: got %d channels, sampleRate == %f\n", totalChannels, hardwareSampleRate);
133
134 // any sample rates are supported
135 float sampleRate = -1;
136
137 static int sampleBits[] = {8, 16, 24};
138 static int sampleBitsCount = sizeof(sampleBits)/sizeof(sampleBits[0]);
139
140 // the last audio format is the default one (used by DataLine.open() if format is not specified)
141 // consider as default 16bit PCM stereo (mono is stereo is not supported) with the current sample rate
142 int defBits = 16;
143 int defChannels = MIN(2, channelsCount);
144 float defSampleRate = hardwareSampleRate;
145 // don't add default format is sample rate is not specified
146 bool addDefault = defSampleRate > 0;
147
148 // TODO: CoreAudio can handle signed/unsigned, little-endian/big-endian
149 // TODO: register the formats (to prevent DirectAudio software conversion) - need to fix DirectAudioDevice.createDataLineInfo
150 // to avoid software conversions if both signed/unsigned or big-/little-endian are supported
151 for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++) {
152 for (int bitIndex = 0; bitIndex < sampleBitsCount; bitIndex++) {
153 int bits = sampleBits[bitIndex];
154 if (addDefault && bits == defBits && channels[channelIndex] != defChannels && sampleRate == defSampleRate) {
155 // the format is the default one, don't add it now
156 continue;
157 }
158 DAUDIO_AddAudioFormat(creator,
159 bits, // sample size in bits
160 -1, // frame size (auto)
161 channels[channelIndex], // channels
162 sampleRate, // sample rate
163 DAUDIO_PCM, // only accept PCM
164 bits == 8 ? FALSE : TRUE, // signed
165 bits == 8 ? FALSE // little-endian for 8bit
166 : UTIL_IsBigEndianPlatform());
167 }
168 }
169 // add default format
170 if (addDefault) {
171 DAUDIO_AddAudioFormat(creator,
172 defBits, // 16 bits
173 -1, // automatically calculate frame size
174 defChannels, // channels
175 defSampleRate, // sample rate
176 DAUDIO_PCM, // PCM
177 TRUE, // signed
178 UTIL_IsBigEndianPlatform()); // native endianess
179 }
180
181 TRACE0("<<DAUDIO_GetFormats\n");
182 }
183
184
185 // =======================================
186 // Source/Target DataLine functions implementation
187
188 // ====
189 /* 1writer-1reader ring buffer class with flush() support */
190 class RingBuffer {
191 public:
RingBuffer()192 RingBuffer() : pBuffer(NULL), nBufferSize(0) {
193 pthread_mutex_init(&lockMutex, NULL);
194 }
~RingBuffer()195 ~RingBuffer() {
196 Deallocate();
197 pthread_mutex_destroy(&lockMutex);
198 }
199
200 // extraBytes: number of additionally allocated bytes to prevent data
201 // overlapping when almost whole buffer is filled
202 // (required only if Write() can override the buffer)
Allocate(int requestedBufferSize,int extraBytes)203 bool Allocate(int requestedBufferSize, int extraBytes) {
204 int fullBufferSize = requestedBufferSize + extraBytes;
205 long powerOfTwo = 1;
206 while (powerOfTwo < fullBufferSize) {
207 powerOfTwo <<= 1;
208 }
209 if (powerOfTwo > INT_MAX || fullBufferSize < 0) {
210 ERROR0("RingBuffer::Allocate: REQUESTED MEMORY SIZE IS TOO BIG\n");
211 return false;
212 }
213 pBuffer = (Byte*)malloc(powerOfTwo);
214 if (pBuffer == NULL) {
215 ERROR0("RingBuffer::Allocate: OUT OF MEMORY\n");
216 return false;
217 }
218
219 nBufferSize = requestedBufferSize;
220 nAllocatedBytes = powerOfTwo;
221 nPosMask = powerOfTwo - 1;
222 nWritePos = 0;
223 nReadPos = 0;
224 nFlushPos = -1;
225
226 TRACE2("RingBuffer::Allocate: OK, bufferSize=%d, allocated:%d\n", nBufferSize, nAllocatedBytes);
227 return true;
228 }
229
Deallocate()230 void Deallocate() {
231 if (pBuffer) {
232 free(pBuffer);
233 pBuffer = NULL;
234 nBufferSize = 0;
235 }
236 }
237
GetBufferSize()238 inline int GetBufferSize() {
239 return nBufferSize;
240 }
241
GetAllocatedSize()242 inline int GetAllocatedSize() {
243 return nAllocatedBytes;
244 }
245
246 // gets number of bytes available for reading
GetValidByteCount()247 int GetValidByteCount() {
248 lock();
249 INT64 result = nWritePos - (nFlushPos >= 0 ? nFlushPos : nReadPos);
250 unlock();
251 return result > (INT64)nBufferSize ? nBufferSize : (int)result;
252 }
253
Write(void * srcBuffer,int len,bool preventOverflow)254 int Write(void *srcBuffer, int len, bool preventOverflow) {
255 lock();
256 TRACE2("RingBuffer::Write (%d bytes, preventOverflow=%d)\n", len, preventOverflow ? 1 : 0);
257 TRACE2(" writePos = %lld (%d)", (long long)nWritePos, Pos2Offset(nWritePos));
258 TRACE2(" readPos=%lld (%d)", (long long)nReadPos, Pos2Offset(nReadPos));
259 TRACE2(" flushPos=%lld (%d)\n", (long long)nFlushPos, Pos2Offset(nFlushPos));
260
261 INT64 writePos = nWritePos;
262 if (preventOverflow) {
263 INT64 avail_read = writePos - (nFlushPos >= 0 ? nFlushPos : nReadPos);
264 if (avail_read >= (INT64)nBufferSize) {
265 // no space
266 TRACE0(" preventOverlow: OVERFLOW => len = 0;\n");
267 len = 0;
268 } else {
269 int avail_write = nBufferSize - (int)avail_read;
270 if (len > avail_write) {
271 TRACE2(" preventOverlow: desrease len: %d => %d\n", len, avail_write);
272 len = avail_write;
273 }
274 }
275 }
276 unlock();
277
278 if (len > 0) {
279
280 write((Byte *)srcBuffer, Pos2Offset(writePos), len);
281
282 lock();
283 TRACE4("--RingBuffer::Write writePos: %lld (%d) => %lld, (%d)\n",
284 (long long)nWritePos, Pos2Offset(nWritePos), (long long)nWritePos + len, Pos2Offset(nWritePos + len));
285 nWritePos += len;
286 unlock();
287 }
288 return len;
289 }
290
Read(void * dstBuffer,int len)291 int Read(void *dstBuffer, int len) {
292 lock();
293 TRACE1("RingBuffer::Read (%d bytes)\n", len);
294 TRACE2(" writePos = %lld (%d)", (long long)nWritePos, Pos2Offset(nWritePos));
295 TRACE2(" readPos=%lld (%d)", (long long)nReadPos, Pos2Offset(nReadPos));
296 TRACE2(" flushPos=%lld (%d)\n", (long long)nFlushPos, Pos2Offset(nFlushPos));
297
298 applyFlush();
299 INT64 avail_read = nWritePos - nReadPos;
300 // check for overflow
301 if (avail_read > (INT64)nBufferSize) {
302 nReadPos = nWritePos - nBufferSize;
303 avail_read = nBufferSize;
304 TRACE0(" OVERFLOW\n");
305 }
306 INT64 readPos = nReadPos;
307 unlock();
308
309 if (len > (int)avail_read) {
310 TRACE2(" RingBuffer::Read - don't have enough data, len: %d => %d\n", len, (int)avail_read);
311 len = (int)avail_read;
312 }
313
314 if (len > 0) {
315
316 read((Byte *)dstBuffer, Pos2Offset(readPos), len);
317
318 lock();
319 if (applyFlush()) {
320 // just got flush(), results became obsolete
321 TRACE0("--RingBuffer::Read, got Flush, return 0\n");
322 len = 0;
323 } else {
324 TRACE4("--RingBuffer::Read readPos: %lld (%d) => %lld (%d)\n",
325 (long long)nReadPos, Pos2Offset(nReadPos), (long long)nReadPos + len, Pos2Offset(nReadPos + len));
326 nReadPos += len;
327 }
328 unlock();
329 } else {
330 // underrun!
331 }
332 return len;
333 }
334
335 // returns number of the flushed bytes
Flush()336 int Flush() {
337 lock();
338 INT64 flushedBytes = nWritePos - (nFlushPos >= 0 ? nFlushPos : nReadPos);
339 nFlushPos = nWritePos;
340 unlock();
341 return flushedBytes > (INT64)nBufferSize ? nBufferSize : (int)flushedBytes;
342 }
343
344 private:
345 Byte *pBuffer;
346 int nBufferSize;
347 int nAllocatedBytes;
348 INT64 nPosMask;
349
350 pthread_mutex_t lockMutex;
351
352 volatile INT64 nWritePos;
353 volatile INT64 nReadPos;
354 // Flush() sets nFlushPos value to nWritePos;
355 // next Read() sets nReadPos to nFlushPos and resests nFlushPos to -1
356 volatile INT64 nFlushPos;
357
lock()358 inline void lock() {
359 pthread_mutex_lock(&lockMutex);
360 }
unlock()361 inline void unlock() {
362 pthread_mutex_unlock(&lockMutex);
363 }
364
applyFlush()365 inline bool applyFlush() {
366 if (nFlushPos >= 0) {
367 nReadPos = nFlushPos;
368 nFlushPos = -1;
369 return true;
370 }
371 return false;
372 }
373
Pos2Offset(INT64 pos)374 inline int Pos2Offset(INT64 pos) {
375 return (int)(pos & nPosMask);
376 }
377
write(Byte * srcBuffer,int dstOffset,int len)378 void write(Byte *srcBuffer, int dstOffset, int len) {
379 int dstEndOffset = dstOffset + len;
380
381 int lenAfterWrap = dstEndOffset - nAllocatedBytes;
382 if (lenAfterWrap > 0) {
383 // dest.buffer does wrap
384 len = nAllocatedBytes - dstOffset;
385 memcpy(pBuffer+dstOffset, srcBuffer, len);
386 memcpy(pBuffer, srcBuffer+len, lenAfterWrap);
387 } else {
388 // dest.buffer does not wrap
389 memcpy(pBuffer+dstOffset, srcBuffer, len);
390 }
391 }
392
read(Byte * dstBuffer,int srcOffset,int len)393 void read(Byte *dstBuffer, int srcOffset, int len) {
394 int srcEndOffset = srcOffset + len;
395
396 int lenAfterWrap = srcEndOffset - nAllocatedBytes;
397 if (lenAfterWrap > 0) {
398 // need to unwrap data
399 len = nAllocatedBytes - srcOffset;
400 memcpy(dstBuffer, pBuffer+srcOffset, len);
401 memcpy(dstBuffer+len, pBuffer, lenAfterWrap);
402 } else {
403 // source buffer is not wrapped
404 memcpy(dstBuffer, pBuffer+srcOffset, len);
405 }
406 }
407 };
408
409
410 class Resampler {
411 private:
412 enum {
413 kResamplerEndOfInputData = 1 // error to interrupt conversion (end of input data)
414 };
415 public:
Resampler()416 Resampler() : converter(NULL), outBuffer(NULL) { }
~Resampler()417 ~Resampler() {
418 if (converter != NULL) {
419 AudioConverterDispose(converter);
420 }
421 if (outBuffer != NULL) {
422 free(outBuffer);
423 }
424 }
425
426 // inFormat & outFormat must be interleaved!
Init(const AudioStreamBasicDescription * inFormat,const AudioStreamBasicDescription * outFormat,int inputBufferSizeInBytes)427 bool Init(const AudioStreamBasicDescription *inFormat, const AudioStreamBasicDescription *outFormat,
428 int inputBufferSizeInBytes)
429 {
430 TRACE0(">>Resampler::Init\n");
431 TRACE0(" inFormat: ");
432 PrintStreamDesc(inFormat);
433 TRACE0(" outFormat: ");
434 PrintStreamDesc(outFormat);
435 TRACE1(" inputBufferSize: %d bytes\n", inputBufferSizeInBytes);
436 OSStatus err;
437
438 if ((outFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0 && outFormat->mChannelsPerFrame != 1) {
439 ERROR0("Resampler::Init ERROR: outFormat is non-interleaved\n");
440 return false;
441 }
442 if ((inFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0 && inFormat->mChannelsPerFrame != 1) {
443 ERROR0("Resampler::Init ERROR: inFormat is non-interleaved\n");
444 return false;
445 }
446
447 memcpy(&asbdIn, inFormat, sizeof(AudioStreamBasicDescription));
448 memcpy(&asbdOut, outFormat, sizeof(AudioStreamBasicDescription));
449
450 err = AudioConverterNew(inFormat, outFormat, &converter);
451
452 if (err || converter == NULL) {
453 OS_ERROR1(err, "Resampler::Init (AudioConverterNew), converter=%p", converter);
454 return false;
455 }
456
457 // allocate buffer for output data
458 int maximumInFrames = inputBufferSizeInBytes / inFormat->mBytesPerFrame;
459 // take into account trailingFrames
460 AudioConverterPrimeInfo primeInfo = {0, 0};
461 UInt32 sizePrime = sizeof(primeInfo);
462 err = AudioConverterGetProperty(converter, kAudioConverterPrimeInfo, &sizePrime, &primeInfo);
463 if (err) {
464 OS_ERROR0(err, "Resampler::Init (get kAudioConverterPrimeInfo)");
465 // ignore the error
466 } else {
467 // the default primeMethod is kConverterPrimeMethod_Normal, so we need only trailingFrames
468 maximumInFrames += primeInfo.trailingFrames;
469 }
470 float outBufferSizeInFrames = (outFormat->mSampleRate / inFormat->mSampleRate) * ((float)maximumInFrames);
471 // to avoid complex calculation just set outBufferSize as double of the calculated value
472 outBufferSize = (int)outBufferSizeInFrames * outFormat->mBytesPerFrame * 2;
473 // safety check - consider 256 frame as the minimum input buffer
474 int minOutSize = 256 * outFormat->mBytesPerFrame;
475 if (outBufferSize < minOutSize) {
476 outBufferSize = minOutSize;
477 }
478
479 outBuffer = malloc(outBufferSize);
480
481 if (outBuffer == NULL) {
482 ERROR1("Resampler::Init ERROR: malloc failed (%d bytes)\n", outBufferSize);
483 AudioConverterDispose(converter);
484 converter = NULL;
485 return false;
486 }
487
488 TRACE1(" allocated: %d bytes for output buffer\n", outBufferSize);
489
490 TRACE0("<<Resampler::Init: OK\n");
491 return true;
492 }
493
494 // returns size of the internal output buffer
GetOutBufferSize()495 int GetOutBufferSize() {
496 return outBufferSize;
497 }
498
499 // process next part of data (writes resampled data to the ringBuffer without overflow check)
Process(void * srcBuffer,int len,RingBuffer * ringBuffer)500 int Process(void *srcBuffer, int len, RingBuffer *ringBuffer) {
501 int bytesWritten = 0;
502 TRACE2(">>Resampler::Process: %d bytes, converter = %p\n", len, converter);
503 if (converter == NULL) { // sanity check
504 bytesWritten = ringBuffer->Write(srcBuffer, len, false);
505 } else {
506 InputProcData data;
507 data.pThis = this;
508 data.data = (Byte *)srcBuffer;
509 data.dataSize = len;
510
511 OSStatus err;
512 do {
513 AudioBufferList abl; // by default it contains 1 AudioBuffer
514 abl.mNumberBuffers = 1;
515 abl.mBuffers[0].mNumberChannels = asbdOut.mChannelsPerFrame;
516 abl.mBuffers[0].mDataByteSize = outBufferSize;
517 abl.mBuffers[0].mData = outBuffer;
518
519 UInt32 packets = (UInt32)outBufferSize / asbdOut.mBytesPerPacket;
520
521 TRACE2(">>AudioConverterFillComplexBuffer: request %d packets, provide %d bytes buffer\n",
522 (int)packets, (int)abl.mBuffers[0].mDataByteSize);
523
524 err = AudioConverterFillComplexBuffer(converter, ConverterInputProc, &data, &packets, &abl, NULL);
525
526 TRACE2("<<AudioConverterFillComplexBuffer: got %d packets (%d bytes)\n",
527 (int)packets, (int)abl.mBuffers[0].mDataByteSize);
528 if (packets > 0) {
529 int bytesToWrite = (int)(packets * asbdOut.mBytesPerPacket);
530 bytesWritten += ringBuffer->Write(abl.mBuffers[0].mData, bytesToWrite, false);
531 }
532
533 // if outputBuffer is small to store all available frames,
534 // we get noErr here. In the case just continue the conversion
535 } while (err == noErr);
536
537 if (err != kResamplerEndOfInputData) {
538 // unexpected error
539 OS_ERROR0(err, "Resampler::Process (AudioConverterFillComplexBuffer)");
540 }
541 }
542 TRACE2("<<Resampler::Process: written %d bytes (converted from %d bytes)\n", bytesWritten, len);
543
544 return bytesWritten;
545 }
546
547 // resets internal bufferes
Discontinue()548 void Discontinue() {
549 TRACE0(">>Resampler::Discontinue\n");
550 if (converter != NULL) {
551 AudioConverterReset(converter);
552 }
553 TRACE0("<<Resampler::Discontinue\n");
554 }
555
556 private:
557 AudioConverterRef converter;
558
559 // buffer for output data
560 // note that there is no problem if the buffer is not big enough to store
561 // all converted data - it's only performance issue
562 void *outBuffer;
563 int outBufferSize;
564
565 AudioStreamBasicDescription asbdIn;
566 AudioStreamBasicDescription asbdOut;
567
568 struct InputProcData {
569 Resampler *pThis;
570 Byte *data; // data == NULL means we handle Discontinue(false)
571 int dataSize; // == 0 if all data was already provided to the converted of we handle Discontinue(false)
572 };
573
ConverterInputProc(AudioConverterRef inAudioConverter,UInt32 * ioNumberDataPackets,AudioBufferList * ioData,AudioStreamPacketDescription ** outDataPacketDescription,void * inUserData)574 static OSStatus ConverterInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
575 AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
576 {
577 InputProcData *data = (InputProcData *)inUserData;
578
579 TRACE3(" >>ConverterInputProc: requested %d packets, data contains %d bytes (%d packets)\n",
580 (int)*ioNumberDataPackets, (int)data->dataSize, (int)(data->dataSize / data->pThis->asbdIn.mBytesPerPacket));
581 if (data->dataSize == 0) {
582 // already called & provided all input data
583 // interrupt conversion by returning error
584 *ioNumberDataPackets = 0;
585 TRACE0(" <<ConverterInputProc: returns kResamplerEndOfInputData\n");
586 return kResamplerEndOfInputData;
587 }
588
589 ioData->mNumberBuffers = 1;
590 ioData->mBuffers[0].mNumberChannels = data->pThis->asbdIn.mChannelsPerFrame;
591 ioData->mBuffers[0].mDataByteSize = data->dataSize;
592 ioData->mBuffers[0].mData = data->data;
593
594 *ioNumberDataPackets = data->dataSize / data->pThis->asbdIn.mBytesPerPacket;
595
596 // all data has been provided to the converter
597 data->dataSize = 0;
598
599 TRACE1(" <<ConverterInputProc: returns %d packets\n", (int)(*ioNumberDataPackets));
600 return noErr;
601 }
602
603 };
604
605
606 struct OSX_DirectAudioDevice {
607 AudioUnit audioUnit;
608 RingBuffer ringBuffer;
609 AudioStreamBasicDescription asbd;
610
611 // only for target lines
612 UInt32 inputBufferSizeInBytes;
613 Resampler *resampler;
614 // to detect discontinuity (to reset resampler)
615 SInt64 lastWrittenSampleTime;
616
617
OSX_DirectAudioDeviceOSX_DirectAudioDevice618 OSX_DirectAudioDevice() : audioUnit(NULL), asbd(), resampler(NULL), lastWrittenSampleTime(0) {
619 }
620
~OSX_DirectAudioDeviceOSX_DirectAudioDevice621 ~OSX_DirectAudioDevice() {
622 if (audioUnit) {
623 AudioComponentInstanceDispose(audioUnit);
624 }
625 if (resampler) {
626 delete resampler;
627 }
628 }
629 };
630
CreateOutputUnit(AudioDeviceID deviceID,int isSource)631 static AudioUnit CreateOutputUnit(AudioDeviceID deviceID, int isSource)
632 {
633 OSStatus err;
634 AudioUnit unit;
635
636 AudioComponentDescription desc;
637 desc.componentType = kAudioUnitType_Output;
638 desc.componentSubType = (deviceID == 0 && isSource) ? kAudioUnitSubType_DefaultOutput : kAudioUnitSubType_HALOutput;
639 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
640 desc.componentFlags = 0;
641 desc.componentFlagsMask = 0;
642
643 AudioComponent comp = AudioComponentFindNext(NULL, &desc);
644 err = AudioComponentInstanceNew(comp, &unit);
645
646 if (err) {
647 OS_ERROR0(err, "CreateOutputUnit:OpenAComponent");
648 return NULL;
649 }
650
651 if (!isSource) {
652 int enableIO = 0;
653 err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
654 0, &enableIO, sizeof(enableIO));
655 if (err) {
656 OS_ERROR0(err, "SetProperty (output EnableIO)");
657 }
658 enableIO = 1;
659 err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
660 1, &enableIO, sizeof(enableIO));
661 if (err) {
662 OS_ERROR0(err, "SetProperty (input EnableIO)");
663 }
664
665 if (!deviceID) {
666 // get real AudioDeviceID for default input device (macosx current input device)
667 deviceID = GetDefaultDevice(isSource);
668 if (!deviceID) {
669 AudioComponentInstanceDispose(unit);
670 return NULL;
671 }
672 }
673 }
674
675 if (deviceID) {
676 err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
677 0, &deviceID, sizeof(deviceID));
678 if (err) {
679 OS_ERROR0(err, "SetProperty (CurrentDevice)");
680 AudioComponentInstanceDispose(unit);
681 return NULL;
682 }
683 }
684
685 return unit;
686 }
687
OutputCallback(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)688 static OSStatus OutputCallback(void *inRefCon,
689 AudioUnitRenderActionFlags *ioActionFlags,
690 const AudioTimeStamp *inTimeStamp,
691 UInt32 inBusNumber,
692 UInt32 inNumberFrames,
693 AudioBufferList *ioData)
694 {
695 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)inRefCon;
696
697 int nchannels = ioData->mNumberBuffers; // should be always == 1 (interleaved channels)
698 AudioBuffer *audioBuffer = ioData->mBuffers;
699
700 TRACE3(">>OutputCallback: busNum=%d, requested %d frames (%d bytes)\n",
701 (int)inBusNumber, (int)inNumberFrames, (int)(inNumberFrames * device->asbd.mBytesPerFrame));
702 TRACE3(" abl: %d buffers, buffer[0].channels=%d, buffer.size=%d\n",
703 nchannels, (int)audioBuffer->mNumberChannels, (int)audioBuffer->mDataByteSize);
704
705 int bytesToRead = inNumberFrames * device->asbd.mBytesPerFrame;
706 if (bytesToRead > (int)audioBuffer->mDataByteSize) {
707 TRACE0("--OutputCallback: !!! audioBuffer IS TOO SMALL!!!\n");
708 bytesToRead = audioBuffer->mDataByteSize / device->asbd.mBytesPerFrame * device->asbd.mBytesPerFrame;
709 }
710 int bytesRead = device->ringBuffer.Read(audioBuffer->mData, bytesToRead);
711 if (bytesRead < bytesToRead) {
712 // no enough data (underrun)
713 TRACE2("--OutputCallback: !!! UNDERRUN (read %d bytes of %d)!!!\n", bytesRead, bytesToRead);
714 // silence the rest
715 memset((Byte*)audioBuffer->mData + bytesRead, 0, bytesToRead-bytesRead);
716 bytesRead = bytesToRead;
717 }
718
719 audioBuffer->mDataByteSize = (UInt32)bytesRead;
720 // SAFETY: set mDataByteSize for all other AudioBuffer in the AudioBufferList to zero
721 while (--nchannels > 0) {
722 audioBuffer++;
723 audioBuffer->mDataByteSize = 0;
724 }
725 TRACE1("<<OutputCallback (returns %d)\n", bytesRead);
726
727 return noErr;
728 }
729
InputCallback(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)730 static OSStatus InputCallback(void *inRefCon,
731 AudioUnitRenderActionFlags *ioActionFlags,
732 const AudioTimeStamp *inTimeStamp,
733 UInt32 inBusNumber,
734 UInt32 inNumberFrames,
735 AudioBufferList *ioData)
736 {
737 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)inRefCon;
738
739 TRACE4(">>InputCallback: busNum=%d, timeStamp=%lld, %d frames (%d bytes)\n",
740 (int)inBusNumber, (long long)inTimeStamp->mSampleTime, (int)inNumberFrames, (int)(inNumberFrames * device->asbd.mBytesPerFrame));
741
742 AudioBufferList abl; // by default it contains 1 AudioBuffer
743 abl.mNumberBuffers = 1;
744 abl.mBuffers[0].mNumberChannels = device->asbd.mChannelsPerFrame;
745 abl.mBuffers[0].mDataByteSize = device->inputBufferSizeInBytes; // assume this is == (inNumberFrames * device->asbd.mBytesPerFrame)
746 abl.mBuffers[0].mData = NULL; // request for the audioUnit's buffer
747
748 OSStatus err = AudioUnitRender(device->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &abl);
749 if (err) {
750 OS_ERROR0(err, "<<InputCallback: AudioUnitRender");
751 } else {
752 if (device->resampler != NULL) {
753 // test for discontinuity
754 // AUHAL starts timestamps at zero, so test if the current timestamp less then the last written
755 SInt64 sampleTime = inTimeStamp->mSampleTime;
756 if (sampleTime < device->lastWrittenSampleTime) {
757 // discontinuity, reset the resampler
758 TRACE2(" InputCallback (RESAMPLED), DISCONTINUITY (%f -> %f)\n",
759 (float)device->lastWrittenSampleTime, (float)sampleTime);
760
761 device->resampler->Discontinue();
762 } else {
763 TRACE2(" InputCallback (RESAMPLED), continuous: lastWrittenSampleTime = %f, sampleTime=%f\n",
764 (float)device->lastWrittenSampleTime, (float)sampleTime);
765 }
766 device->lastWrittenSampleTime = sampleTime + inNumberFrames;
767
768 int bytesWritten = device->resampler->Process(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, &device->ringBuffer);
769 TRACE2("<<InputCallback (RESAMPLED, saved %d bytes of %d)\n", bytesWritten, (int)abl.mBuffers[0].mDataByteSize);
770 } else {
771 int bytesWritten = device->ringBuffer.Write(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, false);
772 TRACE2("<<InputCallback (saved %d bytes of %d)\n", bytesWritten, (int)abl.mBuffers[0].mDataByteSize);
773 }
774 }
775
776 return noErr;
777 }
778
779
FillASBDForNonInterleavedPCM(AudioStreamBasicDescription & asbd,float sampleRate,int channels,int sampleSizeInBits,bool isFloat,int isSigned,bool isBigEndian)780 static void FillASBDForNonInterleavedPCM(AudioStreamBasicDescription& asbd,
781 float sampleRate, int channels, int sampleSizeInBits, bool isFloat, int isSigned, bool isBigEndian)
782 {
783 // FillOutASBDForLPCM cannot produce unsigned integer format
784 asbd.mSampleRate = sampleRate;
785 asbd.mFormatID = kAudioFormatLinearPCM;
786 asbd.mFormatFlags = (isFloat ? kAudioFormatFlagIsFloat : (isSigned ? kAudioFormatFlagIsSignedInteger : 0))
787 | (isBigEndian ? (kAudioFormatFlagIsBigEndian) : 0)
788 | kAudioFormatFlagIsPacked;
789 asbd.mBytesPerPacket = channels * ((sampleSizeInBits + 7) / 8);
790 asbd.mFramesPerPacket = 1;
791 asbd.mBytesPerFrame = asbd.mBytesPerPacket;
792 asbd.mChannelsPerFrame = channels;
793 asbd.mBitsPerChannel = sampleSizeInBits;
794 }
795
DAUDIO_Open(INT32 mixerIndex,INT32 deviceID,int isSource,int encoding,float sampleRate,int sampleSizeInBits,int frameSize,int channels,int isSigned,int isBigEndian,int bufferSizeInBytes)796 void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
797 int encoding, float sampleRate, int sampleSizeInBits,
798 int frameSize, int channels,
799 int isSigned, int isBigEndian, int bufferSizeInBytes)
800 {
801 TRACE3(">>DAUDIO_Open: mixerIndex=%d deviceID=0x%x isSource=%d\n", (int)mixerIndex, (unsigned int)deviceID, isSource);
802 TRACE3(" sampleRate=%d sampleSizeInBits=%d channels=%d\n", (int)sampleRate, sampleSizeInBits, channels);
803 #ifdef USE_TRACE
804 {
805 AudioDeviceID audioDeviceID = deviceID;
806 if (audioDeviceID == 0) {
807 // default device
808 audioDeviceID = GetDefaultDevice(isSource);
809 }
810 char name[256];
811 OSStatus err = GetAudioObjectProperty(audioDeviceID, kAudioUnitScope_Global, kAudioDevicePropertyDeviceName, 256, &name, 0);
812 if (err != noErr) {
813 OS_ERROR1(err, " audioDeviceID=0x%x, name is N/A:", (int)audioDeviceID);
814 } else {
815 TRACE2(" audioDeviceID=0x%x, name=%s\n", (int)audioDeviceID, name);
816 }
817 }
818 #endif
819
820 if (encoding != DAUDIO_PCM) {
821 ERROR1("<<DAUDIO_Open: ERROR: unsupported encoding (%d)\n", encoding);
822 return NULL;
823 }
824 if (channels <= 0) {
825 ERROR1("<<DAUDIO_Open: ERROR: Invalid number of channels=%d!\n", channels);
826 return NULL;
827 }
828
829 OSX_DirectAudioDevice *device = new OSX_DirectAudioDevice();
830
831 AudioUnitScope scope = isSource ? kAudioUnitScope_Input : kAudioUnitScope_Output;
832 int element = isSource ? 0 : 1;
833 OSStatus err = noErr;
834 int extraBufferBytes = 0;
835
836 device->audioUnit = CreateOutputUnit(deviceID, isSource);
837
838 if (!device->audioUnit) {
839 delete device;
840 return NULL;
841 }
842
843 if (!isSource) {
844 AudioDeviceID actualDeviceID = deviceID != 0 ? deviceID : GetDefaultDevice(isSource);
845 float hardwareSampleRate = GetSampleRate(actualDeviceID, isSource);
846 TRACE2("--DAUDIO_Open: sampleRate = %f, hardwareSampleRate=%f\n", sampleRate, hardwareSampleRate);
847
848 if (fabs(sampleRate - hardwareSampleRate) > 1) {
849 device->resampler = new Resampler();
850
851 // request HAL for Float32 with native endianess
852 FillASBDForNonInterleavedPCM(device->asbd, hardwareSampleRate, channels, 32, true, false, kAudioFormatFlagsNativeEndian != 0);
853 } else {
854 sampleRate = hardwareSampleRate; // in case sample rates are not exactly equal
855 }
856 }
857
858 if (device->resampler == NULL) {
859 // no resampling, request HAL for the requested format
860 FillASBDForNonInterleavedPCM(device->asbd, sampleRate, channels, sampleSizeInBits, false, isSigned, isBigEndian);
861 }
862
863 err = AudioUnitSetProperty(device->audioUnit, kAudioUnitProperty_StreamFormat, scope, element, &device->asbd, sizeof(device->asbd));
864 if (err) {
865 OS_ERROR0(err, "<<DAUDIO_Open set StreamFormat");
866 delete device;
867 return NULL;
868 }
869
870 AURenderCallbackStruct output;
871 output.inputProc = isSource ? OutputCallback : InputCallback;
872 output.inputProcRefCon = device;
873
874 err = AudioUnitSetProperty(device->audioUnit,
875 isSource
876 ? (AudioUnitPropertyID)kAudioUnitProperty_SetRenderCallback
877 : (AudioUnitPropertyID)kAudioOutputUnitProperty_SetInputCallback,
878 kAudioUnitScope_Global, 0, &output, sizeof(output));
879 if (err) {
880 OS_ERROR0(err, "<<DAUDIO_Open set RenderCallback");
881 delete device;
882 return NULL;
883 }
884
885 err = AudioUnitInitialize(device->audioUnit);
886 if (err) {
887 OS_ERROR0(err, "<<DAUDIO_Open UnitInitialize");
888 delete device;
889 return NULL;
890 }
891
892 if (!isSource) {
893 // for target lines we need extra bytes in the ringBuffer
894 // to prevent collisions when InputCallback overrides data on overflow
895 UInt32 size;
896 OSStatus err;
897
898 size = sizeof(device->inputBufferSizeInBytes);
899 err = AudioUnitGetProperty(device->audioUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global,
900 0, &device->inputBufferSizeInBytes, &size);
901 if (err) {
902 OS_ERROR0(err, "<<DAUDIO_Open (TargetDataLine)GetBufferSize\n");
903 delete device;
904 return NULL;
905 }
906 device->inputBufferSizeInBytes *= device->asbd.mBytesPerFrame; // convert frames to bytes
907 extraBufferBytes = (int)device->inputBufferSizeInBytes;
908 }
909
910 if (device->resampler != NULL) {
911 // resampler output format is a user requested format (== ringBuffer format)
912 AudioStreamBasicDescription asbdOut; // ringBuffer format
913 FillASBDForNonInterleavedPCM(asbdOut, sampleRate, channels, sampleSizeInBits, false, isSigned, isBigEndian);
914
915 // set resampler input buffer size to the HAL buffer size
916 if (!device->resampler->Init(&device->asbd, &asbdOut, (int)device->inputBufferSizeInBytes)) {
917 ERROR0("<<DAUDIO_Open: resampler.Init() FAILED.\n");
918 delete device;
919 return NULL;
920 }
921 // extra bytes in the ringBuffer (extraBufferBytes) should be equal resampler output buffer size
922 extraBufferBytes = device->resampler->GetOutBufferSize();
923 }
924
925 if (!device->ringBuffer.Allocate(bufferSizeInBytes, extraBufferBytes)) {
926 ERROR0("<<DAUDIO_Open: Ring buffer allocation error\n");
927 delete device;
928 return NULL;
929 }
930
931 TRACE0("<<DAUDIO_Open: OK\n");
932 return device;
933 }
934
DAUDIO_Start(void * id,int isSource)935 int DAUDIO_Start(void* id, int isSource) {
936 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
937 TRACE0("DAUDIO_Start\n");
938
939 OSStatus err = AudioOutputUnitStart(device->audioUnit);
940
941 if (err != noErr) {
942 OS_ERROR0(err, "DAUDIO_Start");
943 }
944
945 return err == noErr ? TRUE : FALSE;
946 }
947
DAUDIO_Stop(void * id,int isSource)948 int DAUDIO_Stop(void* id, int isSource) {
949 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
950 TRACE0("DAUDIO_Stop\n");
951
952 OSStatus err = AudioOutputUnitStop(device->audioUnit);
953
954 return err == noErr ? TRUE : FALSE;
955 }
956
DAUDIO_Close(void * id,int isSource)957 void DAUDIO_Close(void* id, int isSource) {
958 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
959 TRACE0("DAUDIO_Close\n");
960
961 delete device;
962 }
963
DAUDIO_Write(void * id,char * data,int byteSize)964 int DAUDIO_Write(void* id, char* data, int byteSize) {
965 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
966 TRACE1(">>DAUDIO_Write: %d bytes to write\n", byteSize);
967
968 int result = device->ringBuffer.Write(data, byteSize, true);
969
970 TRACE1("<<DAUDIO_Write: %d bytes written\n", result);
971 return result;
972 }
973
DAUDIO_Read(void * id,char * data,int byteSize)974 int DAUDIO_Read(void* id, char* data, int byteSize) {
975 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
976 TRACE1(">>DAUDIO_Read: %d bytes to read\n", byteSize);
977
978 int result = device->ringBuffer.Read(data, byteSize);
979
980 TRACE1("<<DAUDIO_Read: %d bytes has been read\n", result);
981 return result;
982 }
983
DAUDIO_GetBufferSize(void * id,int isSource)984 int DAUDIO_GetBufferSize(void* id, int isSource) {
985 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
986
987 int bufferSizeInBytes = device->ringBuffer.GetBufferSize();
988
989 TRACE1("DAUDIO_GetBufferSize returns %d\n", bufferSizeInBytes);
990 return bufferSizeInBytes;
991 }
992
DAUDIO_StillDraining(void * id,int isSource)993 int DAUDIO_StillDraining(void* id, int isSource) {
994 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
995
996 int draining = device->ringBuffer.GetValidByteCount() > 0 ? TRUE : FALSE;
997
998 TRACE1("DAUDIO_StillDraining returns %d\n", draining);
999 return draining;
1000 }
1001
DAUDIO_Flush(void * id,int isSource)1002 int DAUDIO_Flush(void* id, int isSource) {
1003 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
1004 TRACE0("DAUDIO_Flush\n");
1005
1006 device->ringBuffer.Flush();
1007
1008 return TRUE;
1009 }
1010
DAUDIO_GetAvailable(void * id,int isSource)1011 int DAUDIO_GetAvailable(void* id, int isSource) {
1012 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
1013
1014 int bytesInBuffer = device->ringBuffer.GetValidByteCount();
1015 if (isSource) {
1016 return device->ringBuffer.GetBufferSize() - bytesInBuffer;
1017 } else {
1018 return bytesInBuffer;
1019 }
1020 }
1021
DAUDIO_GetBytePosition(void * id,int isSource,INT64 javaBytePos)1022 INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
1023 OSX_DirectAudioDevice *device = (OSX_DirectAudioDevice*)id;
1024 INT64 position;
1025
1026 if (isSource) {
1027 position = javaBytePos - device->ringBuffer.GetValidByteCount();
1028 } else {
1029 position = javaBytePos + device->ringBuffer.GetValidByteCount();
1030 }
1031
1032 TRACE2("DAUDIO_GetBytePosition returns %lld (javaBytePos = %lld)\n", (long long)position, (long long)javaBytePos);
1033 return position;
1034 }
1035
DAUDIO_SetBytePosition(void * id,int isSource,INT64 javaBytePos)1036 void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
1037 // no need javaBytePos (it's available in DAUDIO_GetBytePosition)
1038 }
1039
DAUDIO_RequiresServicing(void * id,int isSource)1040 int DAUDIO_RequiresServicing(void* id, int isSource) {
1041 return FALSE;
1042 }
1043
DAUDIO_Service(void * id,int isSource)1044 void DAUDIO_Service(void* id, int isSource) {
1045 // unreachable
1046 }
1047
1048 #endif // USE_DAUDIO == TRUE
1049