Changeset 25770 in vbox
- Timestamp:
- Jan 12, 2010 4:17:04 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 56528
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r23981 r25770 1661 1661 ac97Reset (pDevIns); 1662 1662 1663 #ifndef RT_OS_DARWIN /* coreaudio doesn't supply these. */1664 1663 if (!s->voice_pi) 1665 1664 LogRel (("AC97: WARNING: Unable to open PCM IN!\n")); 1666 1665 if (!s->voice_mc) 1667 1666 LogRel (("AC97: WARNING: Unable to open PCM MC!\n")); 1668 #endif1669 1667 if (!s->voice_po) 1670 1668 LogRel (("AC97: WARNING: Unable to open PCM OUT!\n")); … … 1686 1684 "with the consequence that no sound is audible")); 1687 1685 } 1688 #ifndef RT_OS_DARWIN1689 1686 else if (!s->voice_pi || !s->voice_po || !s->voice_mc) 1690 1687 { … … 1704 1701 "subsystem"), szMissingVoices); 1705 1702 } 1706 #endif1707 1703 1708 1704 return VINF_SUCCESS; -
trunk/src/VBox/Devices/Audio/coreaudio.c
r1584 r25770 1 /* $Id$ */ 2 /** @file 3 * VBox audio devices: Mac OS X CoreAudio audio driver 4 */ 5 1 6 /* 2 * QEMU OS X CoreAudio audio driver3 *4 7 * Copyright (c) 2005 Mike Kronenberg 5 8 * … … 23 26 */ 24 27 28 #define LOG_GROUP LOG_GROUP_DEV_AUDIO 29 #include <VBox/log.h> 30 #include <iprt/mem.h> 31 #include <iprt/cdefs.h> 32 33 #define AUDIO_CAP "coreaudio" 34 #include "vl_vbox.h" 35 #include "audio.h" 36 #include "audio_int.h" 37 25 38 #include <CoreAudio/CoreAudio.h> 26 #include <string.h> /* strerror */ 27 #include <pthread.h> /* pthread_X */ 28 29 #ifndef VBOX 30 #include "vl.h" 31 #else 32 # include "vl_vbox.h" 33 # include "audio.h" 34 #endif 35 36 #define AUDIO_CAP "coreaudio" 37 #include "audio_int.h" 38 39 struct { 40 int buffer_frames; 41 int nbuffers; 42 int isAtexit; 43 } conf = { 44 .buffer_frames = 512, 45 .nbuffers = 4, 46 .isAtexit = 0 39 #include <AudioUnit/AudioUnit.h> 40 41 /* todo: 42 * - checking for properties changes of the devices 43 * - set frame size (use config) 44 * - AudioUnit converter for changing the sample rate 45 * - maybe get rid of the extra input sample buffer 46 * - maybe make sure the thread is immediately stopped if playing/recording stops 47 */ 48 49 /* Most of this is based on: 50 * http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html 51 * http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html 52 * http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html 53 */ 54 55 /******************************************************************************* 56 * 57 * IO Ring Buffer section 58 * 59 ******************************************************************************/ 60 61 /* Implementation of a lock free ring buffer which could be used in a multi 62 * threaded environment. */ 63 typedef struct IORINGBUFFER 64 { 65 /* The current read position in the buffer */ 66 uint32_t uReadPos; 67 /* The current write position in the buffer */ 68 uint32_t uWritePos; 69 /* How much space of the buffer is currently in use */ 70 volatile uint32_t cBufferUsed; 71 /* How big is the buffer */ 72 uint32_t cBufSize; 73 /* The buffer itself */ 74 char *pBuffer; 75 } IORINGBUFFER; 76 /* Pointer to an ring buffer structure */ 77 typedef IORINGBUFFER* PIORINGBUFFER; 78 79 80 static void IORingBufferCreate(PIORINGBUFFER *ppBuffer, uint32_t cSize) 81 { 82 PIORINGBUFFER pTmpBuffer; 83 84 AssertPtr(ppBuffer); 85 86 *ppBuffer = NULL; 87 pTmpBuffer = RTMemAllocZ(sizeof(IORINGBUFFER)); 88 if (pTmpBuffer) 89 { 90 pTmpBuffer->pBuffer = RTMemAlloc(cSize); 91 if(pTmpBuffer->pBuffer) 92 { 93 pTmpBuffer->cBufSize = cSize; 94 *ppBuffer = pTmpBuffer; 95 } 96 else 97 RTMemFree(pTmpBuffer); 98 } 99 } 100 101 static void IORingBufferDestroy(PIORINGBUFFER pBuffer) 102 { 103 if (pBuffer) 104 { 105 if (pBuffer->pBuffer) 106 RTMemFree(pBuffer->pBuffer); 107 RTMemFree(pBuffer); 108 } 109 } 110 111 DECL_FORCE_INLINE(void) IORingBufferReset(PIORINGBUFFER pBuffer) 112 { 113 AssertPtr(pBuffer); 114 115 pBuffer->uReadPos = 0; 116 pBuffer->uWritePos = 0; 117 pBuffer->cBufferUsed = 0; 118 } 119 120 DECL_FORCE_INLINE(uint32_t) IORingBufferFree(PIORINGBUFFER pBuffer) 121 { 122 AssertPtr(pBuffer); 123 return pBuffer->cBufSize - pBuffer->cBufferUsed; 124 } 125 126 DECL_FORCE_INLINE(uint32_t) IORingBufferUsed(PIORINGBUFFER pBuffer) 127 { 128 AssertPtr(pBuffer); 129 return pBuffer->cBufferUsed; 130 } 131 132 static void IORingBufferAquireReadBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize) 133 { 134 uint32_t uUsed = 0; 135 uint32_t uSize = 0; 136 137 AssertPtr(pBuffer); 138 139 *ppStart = 0; 140 *pcSize = 0; 141 142 /* How much is in use? */ 143 uUsed = ASMAtomicAddU32(&pBuffer->cBufferUsed, 0); 144 if (uUsed > 0) 145 { 146 /* Get the size out of the requested size, the read block till the end 147 * of the buffer & the currently used size. */ 148 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uReadPos, uUsed)); 149 if (uSize > 0) 150 { 151 /* Return the pointer address which point to the current read 152 * position. */ 153 *ppStart = pBuffer->pBuffer + pBuffer->uReadPos; 154 *pcSize = uSize; 155 } 156 } 157 } 158 159 DECL_FORCE_INLINE(void) IORingBufferReleaseReadBlock(PIORINGBUFFER pBuffer, uint32_t cSize) 160 { 161 AssertPtr(pBuffer); 162 163 /* Split at the end of the buffer. */ 164 pBuffer->uReadPos = (pBuffer->uReadPos + cSize) % pBuffer->cBufSize; 165 166 ASMAtomicSubU32((int32_t*)&pBuffer->cBufferUsed, cSize); 167 } 168 169 static void IORingBufferAquireWriteBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize) 170 { 171 uint32_t uFree; 172 uint32_t uSize; 173 174 AssertPtr(pBuffer); 175 176 *ppStart = 0; 177 *pcSize = 0; 178 179 /* How much is free? */ 180 uFree = pBuffer->cBufSize - ASMAtomicAddU32(&pBuffer->cBufferUsed, 0); 181 if (uFree > 0) 182 { 183 /* Get the size out of the requested size, the write block till the end 184 * of the buffer & the currently free size. */ 185 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uWritePos, uFree)); 186 if (uSize > 0) 187 { 188 /* Return the pointer address which point to the current write 189 * position. */ 190 *ppStart = pBuffer->pBuffer + pBuffer->uWritePos; 191 *pcSize = uSize; 192 } 193 } 194 } 195 196 DECL_FORCE_INLINE(void) IORingBufferReleaseWriteBlock(PIORINGBUFFER pBuffer, uint32_t cSize) 197 { 198 AssertPtr(pBuffer); 199 200 /* Split at the end of the buffer. */ 201 pBuffer->uWritePos = (pBuffer->uWritePos + cSize) % pBuffer->cBufSize; 202 203 ASMAtomicAddU32(&pBuffer->cBufferUsed, cSize); 204 } 205 206 /******************************************************************************* 207 * 208 * Helper function section 209 * 210 ******************************************************************************/ 211 212 #if DEBUG 213 static void caDebugOutputAudioStreamBasicDescription(const char *pszDesc, const AudioStreamBasicDescription *pStreamDesc) 214 { 215 char pszSampleRate[32]; 216 Log(("%s AudioStreamBasicDescription:\n", pszDesc)); 217 Log(("CoreAudio: Format ID: %RU32 (%c%c%c%c)\n", pStreamDesc->mFormatID, RT_BYTE4(pStreamDesc->mFormatID), RT_BYTE3(pStreamDesc->mFormatID), RT_BYTE2(pStreamDesc->mFormatID), RT_BYTE1(pStreamDesc->mFormatID))); 218 Log(("CoreAudio: Flags: %RU32", pStreamDesc->mFormatFlags)); 219 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsFloat) 220 Log((" Float")); 221 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsBigEndian) 222 Log((" BigEndian")); 223 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsSignedInteger) 224 Log((" SignedInteger")); 225 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsPacked) 226 Log((" Packed")); 227 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsAlignedHigh) 228 Log((" AlignedHigh")); 229 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsNonInterleaved) 230 Log((" NonInterleaved")); 231 if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsNonMixable) 232 Log((" NonMixable")); 233 if (pStreamDesc->mFormatFlags & kAudioFormatFlagsAreAllClear) 234 Log((" AllClear")); 235 Log(("\n")); 236 snprintf(pszSampleRate, 32, "%.2f", (float)pStreamDesc->mSampleRate); 237 Log(("CoreAudio: SampleRate: %s\n", pszSampleRate)); 238 Log(("CoreAudio: ChannelsPerFrame: %RU32\n", pStreamDesc->mChannelsPerFrame)); 239 Log(("CoreAudio: FramesPerPacket: %RU32\n", pStreamDesc->mFramesPerPacket)); 240 Log(("CoreAudio: BitsPerChannel: %RU32\n", pStreamDesc->mBitsPerChannel)); 241 Log(("CoreAudio: BytesPerFrame: %RU32\n", pStreamDesc->mBytesPerFrame)); 242 Log(("CoreAudio: BytesPerPacket: %RU32\n", pStreamDesc->mBytesPerPacket)); 243 } 244 #endif /* DEBUG */ 245 246 static void caAudioSettingsToAudioStreamBasicDescription(const audsettings_t *pAS, AudioStreamBasicDescription *pStreamDesc) 247 { 248 pStreamDesc->mFormatID = kAudioFormatLinearPCM; 249 pStreamDesc->mFormatFlags = kAudioFormatFlagIsPacked; 250 pStreamDesc->mFramesPerPacket = 1; 251 pStreamDesc->mSampleRate = (Float64)pAS->freq; 252 pStreamDesc->mChannelsPerFrame = pAS->nchannels; 253 switch (pAS->fmt) 254 { 255 case AUD_FMT_U8: 256 { 257 pStreamDesc->mBitsPerChannel = 8; 258 break; 259 } 260 case AUD_FMT_S8: 261 { 262 pStreamDesc->mBitsPerChannel = 8; 263 pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; 264 break; 265 } 266 case AUD_FMT_U16: 267 { 268 pStreamDesc->mBitsPerChannel = 16; 269 break; 270 } 271 case AUD_FMT_S16: 272 { 273 pStreamDesc->mBitsPerChannel = 16; 274 pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; 275 break; 276 } 277 #ifdef PA_SAMPLE_S32LE 278 case AUD_FMT_U32: 279 { 280 pStreamDesc->mBitsPerChannel = 32; 281 break; 282 } 283 case AUD_FMT_S32: 284 { 285 pStreamDesc->mBitsPerChannel = 32; 286 pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; 287 break; 288 } 289 #endif 290 default: 291 break; 292 } 293 pStreamDesc->mBytesPerFrame = pStreamDesc->mChannelsPerFrame * (pStreamDesc->mBitsPerChannel / 8); 294 pStreamDesc->mBytesPerPacket = pStreamDesc->mFramesPerPacket * pStreamDesc->mBytesPerFrame; 295 } 296 297 DECL_FORCE_INLINE(bool) caIsRunning(AudioDeviceID deviceID) 298 { 299 OSStatus err = noErr; 300 UInt32 uFlag = 0; 301 UInt32 uSize = sizeof(uFlag); 302 err = AudioDeviceGetProperty(deviceID, 303 0, 304 0, 305 kAudioDevicePropertyDeviceIsRunning, 306 &uSize, 307 &uFlag); 308 if (err != kAudioHardwareNoError) 309 LogRel(("CoreAudio: Could not determine whether the device is running (%RI32)\n", err)); 310 return uFlag >= 1; 311 } 312 313 /******************************************************************************* 314 * 315 * Global structures section 316 * 317 ******************************************************************************/ 318 319 struct 320 { 321 int cBufferFrames; 322 } conf = 323 { 324 INIT_FIELD(.cBufferFrames =) 512 47 325 }; 48 326 49 typedef struct coreaudioVoiceOut { 327 typedef struct caVoiceOut 328 { 329 /* HW voice output struture defined by VBox */ 50 330 HWVoiceOut hw; 51 pthread_mutex_t mutex; 52 int isAtexit; 53 AudioDeviceID outputDeviceID; 54 UInt32 audioDevicePropertyBufferFrameSize; 55 AudioStreamBasicDescription outputStreamBasicDescription; 56 int live; 57 int decr; 58 int rpos; 59 } coreaudioVoiceOut; 60 61 static void coreaudio_logstatus (OSStatus status) 62 { 63 char *str = "BUG"; 64 65 switch(status) { 66 case kAudioHardwareNoError: 67 str = "kAudioHardwareNoError"; 68 break; 69 70 case kAudioHardwareNotRunningError: 71 str = "kAudioHardwareNotRunningError"; 72 break; 73 74 case kAudioHardwareUnspecifiedError: 75 str = "kAudioHardwareUnspecifiedError"; 76 break; 77 78 case kAudioHardwareUnknownPropertyError: 79 str = "kAudioHardwareUnknownPropertyError"; 80 break; 81 82 case kAudioHardwareBadPropertySizeError: 83 str = "kAudioHardwareBadPropertySizeError"; 84 break; 85 86 case kAudioHardwareIllegalOperationError: 87 str = "kAudioHardwareIllegalOperationError"; 88 break; 89 90 case kAudioHardwareBadDeviceError: 91 str = "kAudioHardwareBadDeviceError"; 92 break; 93 94 case kAudioHardwareBadStreamError: 95 str = "kAudioHardwareBadStreamError"; 96 break; 97 98 case kAudioHardwareUnsupportedOperationError: 99 str = "kAudioHardwareUnsupportedOperationError"; 100 break; 101 102 case kAudioDeviceUnsupportedFormatError: 103 str = "kAudioDeviceUnsupportedFormatError"; 104 break; 105 106 case kAudioDevicePermissionsError: 107 str = "kAudioDevicePermissionsError"; 108 break; 109 110 default: 111 AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status); 112 return; 113 } 114 115 AUD_log (AUDIO_CAP, "Reason: %s\n", str); 116 } 117 118 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr ( 119 OSStatus status, 120 const char *fmt, 121 ... 122 ) 123 { 124 va_list ap; 125 126 va_start (ap, fmt); 127 AUD_log (AUDIO_CAP, fmt, ap); 128 va_end (ap); 129 130 coreaudio_logstatus (status); 131 } 132 133 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( 134 OSStatus status, 135 const char *typ, 136 const char *fmt, 137 ... 138 ) 139 { 140 va_list ap; 141 142 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); 143 144 va_start (ap, fmt); 145 AUD_vlog (AUDIO_CAP, fmt, ap); 146 va_end (ap); 147 148 coreaudio_logstatus (status); 149 } 150 151 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID) 152 { 153 OSStatus status; 154 UInt32 result = 0; 155 UInt32 propertySize = sizeof(outputDeviceID); 156 status = AudioDeviceGetProperty( 157 outputDeviceID, 0, 0, 158 kAudioDevicePropertyDeviceIsRunning, &propertySize, &result); 159 if (status != kAudioHardwareNoError) { 160 coreaudio_logerr(status, 161 "Could not determine whether Device is playing\n"); 162 } 163 return result; 164 } 165 166 static void coreaudio_atexit (void) 167 { 168 conf.isAtexit = 1; 169 } 170 171 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) 172 { 173 int err; 174 175 err = pthread_mutex_lock (&core->mutex); 176 if (err) { 177 dolog ("Could not lock voice for %s\nReason: %s\n", 178 fn_name, strerror (err)); 179 return -1; 180 } 331 /* Stream description which is default on the device */ 332 AudioStreamBasicDescription deviceFormat; 333 /* Stream description which is selected for using by VBox */ 334 AudioStreamBasicDescription streamFormat; 335 /* The audio device ID of the currently used device */ 336 AudioDeviceID audioDeviceId; 337 /* The AudioUnit used */ 338 AudioUnit audioUnit; 339 /* A ring buffer for transfering data to the playback thread */ 340 PIORINGBUFFER pBuf; 341 } caVoiceOut; 342 343 typedef struct caVoiceIn 344 { 345 /* HW voice input struture defined by VBox */ 346 HWVoiceIn hw; 347 /* Stream description which is default on the device */ 348 AudioStreamBasicDescription deviceFormat; 349 /* Stream description which is selected for using by VBox */ 350 AudioStreamBasicDescription streamFormat; 351 /* The audio device ID of the currently used device */ 352 AudioDeviceID audioDeviceId; 353 /* The AudioUnit used */ 354 AudioUnit audioUnit; 355 /* An extra buffer used for render the audio data in the recording thread */ 356 AudioBufferList *pcaBufferList; 357 /* A ring buffer for transfering from to the recording thread */ 358 PIORINGBUFFER pBuf; 359 } caVoiceIn; 360 361 362 /******************************************************************************* 363 * 364 * CoreAudio output section 365 * 366 ******************************************************************************/ 367 368 /* callback to feed audiooutput buffer */ 369 static OSStatus caPlaybackCallback(void* inRefCon, 370 AudioUnitRenderActionFlags* ioActionFlags, 371 const AudioTimeStamp* inTimeStamp, 372 UInt32 inBusNumber, 373 UInt32 inNumberFrames, 374 AudioBufferList* ioData) 375 { 376 uint32_t csAvail = 0; 377 uint32_t cbToRead = 0; 378 uint32_t csToRead = 0; 379 uint32_t csReads = 0; 380 char *pcSrc = NULL; 381 382 caVoiceOut *caVoice = (caVoiceOut *) inRefCon; 383 384 /* How much space is used in the ring buffer? */ 385 csAvail = IORingBufferUsed(caVoice->pBuf) >> caVoice->hw.info.shift; /* bytes -> samples */ 386 /* How much space is available in the core audio buffer. Use the smaller 387 * size of the too. */ 388 csAvail = RT_MIN(csAvail, ioData->mBuffers[0].mDataByteSize >> caVoice->hw.info.shift); 389 390 Log2(("CoreAudio: [Output] Start reading buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift)); 391 392 /* Iterate as long as data is available */ 393 while(csReads < csAvail) 394 { 395 /* How much is left? */ 396 csToRead = csAvail - csReads; 397 cbToRead = csToRead << caVoice->hw.info.shift; /* samples -> bytes */ 398 Log2(("CoreAudio: [Output] Try reading %RU32 samples (%RU32 bytes)\n", csToRead, cbToRead)); 399 /* Try to aquire the necessary block from the ring buffer. */ 400 IORingBufferAquireReadBlock(caVoice->pBuf, cbToRead, &pcSrc, &cbToRead); 401 /* How much to we get? */ 402 csToRead = cbToRead >> caVoice->hw.info.shift; /* bytes -> samples */ 403 Log2(("CoreAudio: [Output] There are %RU32 samples (%RU32 bytes) available\n", csToRead, cbToRead)); 404 /* Break if nothing is used anymore. */ 405 if (RT_UNLIKELY(cbToRead == 0)) 406 break; 407 /* Copy the data from our ring buffer to the core audio buffer. */ 408 memcpy((char*)ioData->mBuffers[0].mData + (csReads << caVoice->hw.info.shift), pcSrc, cbToRead); 409 /* Release the read buffer, so it could be used for new data. */ 410 IORingBufferReleaseReadBlock(caVoice->pBuf, cbToRead); 411 /* How much have we reads so far. */ 412 csReads += csToRead; 413 } 414 /* Write the bytes to the core audio buffer which where really written. */ 415 ioData->mBuffers[0].mDataByteSize = csReads << caVoice->hw.info.shift; /* samples -> bytes */ 416 417 Log2(("CoreAudio: [Output] Finished reading buffer with %RU32 samples (%RU32 bytes)\n", csReads, csReads << caVoice->hw.info.shift)); 418 419 return noErr; 420 } 421 422 static int coreaudio_run_out(HWVoiceOut *hw) 423 { 424 uint32_t csAvail = 0; 425 uint32_t cbToWrite = 0; 426 uint32_t csToWrite = 0; 427 uint32_t csWritten = 0; 428 char *pcDst = NULL; 429 st_sample_t *psSrc = NULL; 430 431 caVoiceOut *caVoice = (caVoiceOut *) hw; 432 433 /* How much space is available in the ring buffer */ 434 csAvail = IORingBufferFree(caVoice->pBuf) >> hw->info.shift; /* bytes -> samples */ 435 /* How much data is availabe. Use the smaller size of the too. */ 436 csAvail = RT_MIN(csAvail, (uint32_t)audio_pcm_hw_get_live_out(hw)); 437 438 Log2(("CoreAudio: [Output] Start writing buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << hw->info.shift)); 439 440 /* Iterate as long as data is available */ 441 while (csWritten < csAvail) 442 { 443 /* How much is left? Split request at the end of our samples buffer. */ 444 csToWrite = RT_MIN(csAvail - csWritten, (uint32_t)(hw->samples - hw->rpos)); 445 cbToWrite = csToWrite << hw->info.shift; /* samples -> bytes */ 446 Log2(("CoreAudio: [Output] Try writing %RU32 samples (%RU32 bytes)\n", csToWrite, cbToWrite)); 447 /* Try to aquire the necessary space from the ring buffer. */ 448 IORingBufferAquireWriteBlock(caVoice->pBuf, cbToWrite, &pcDst, &cbToWrite); 449 /* How much to we get? */ 450 csToWrite = cbToWrite >> hw->info.shift; 451 Log2(("CoreAudio: [Output] There is space for %RU32 samples (%RU32 bytes) available\n", csToWrite, cbToWrite)); 452 /* Break if nothing is free anymore. */ 453 if (RT_UNLIKELY(cbToWrite == 0)) 454 break; 455 /* Copy the data from our mix buffer to the ring buffer. */ 456 psSrc = hw->mix_buf + hw->rpos; 457 hw->clip((uint8_t*)pcDst, psSrc, csToWrite); 458 /* Release the ring buffer, so the read thread could start reading this data. */ 459 IORingBufferReleaseWriteBlock(caVoice->pBuf, cbToWrite); 460 hw->rpos = (hw->rpos + csToWrite) % hw->samples; 461 /* How much have we written so far. */ 462 csWritten += csToWrite; 463 } 464 465 Log2(("CoreAudio: [Output] Finished writing buffer with %RU32 samples (%RU32 bytes)\n", csWritten, csWritten << hw->info.shift)); 466 467 /* Return the count of samples we have processed. */ 468 return csWritten; 469 } 470 471 static int coreaudio_write(SWVoiceOut *sw, void *buf, int len) 472 { 473 return audio_pcm_sw_write (sw, buf, len); 474 } 475 476 static int coreaudio_init_out(HWVoiceOut *hw, audsettings_t *as) 477 { 478 OSStatus err = noErr; 479 UInt32 uSize = 0; /* temporary size of properties */ 480 UInt32 uFlag = 0; /* for setting flags */ 481 CFStringRef name; /* for the temporary device name fetching */ 482 const char *pszName; 483 ComponentDescription cd; /* description for an audio component */ 484 Component cp; /* an audio component */ 485 AURenderCallbackStruct cb; /* holds the callback structure */ 486 UInt32 cFrames; /* default frame count */ 487 488 caVoiceOut *caVoice = (caVoiceOut *) hw; 489 490 /* Initialize the hardware info section with the audio settings */ 491 audio_pcm_init_info(&hw->info, as); 492 493 /* Fetch the default audio output device currently in use */ 494 uSize = sizeof(caVoice->audioDeviceId); 495 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, 496 &uSize, 497 &caVoice->audioDeviceId); 498 if (RT_UNLIKELY(err != noErr)) 499 { 500 LogRel(("CoreAudio: [Output] Unable to find default output device (%RI32)\n", err)); 501 return -1; 502 } 503 504 /* Try to get the name of the default output device and log it. It's not 505 * fatal if it fails. */ 506 uSize = sizeof(CFStringRef); 507 err = AudioDeviceGetProperty(caVoice->audioDeviceId, 508 0, 509 0, 510 kAudioObjectPropertyName, 511 &uSize, 512 &name); 513 if (RT_LIKELY(err == noErr)) 514 { 515 pszName = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman); 516 if (pszName) 517 LogRel(("CoreAudio: Using default output device: %s\n", pszName)); 518 CFRelease(name); 519 } 520 else 521 LogRel(("CoreAudio: [Output] Unable to get output device name (%RI32)\n", err)); 522 523 cd.componentType = kAudioUnitType_Output; 524 cd.componentSubType = kAudioUnitSubType_HALOutput; 525 cd.componentManufacturer = kAudioUnitManufacturer_Apple; 526 cd.componentFlags = 0; 527 cd.componentFlagsMask = 0; 528 529 /* Try to find the default HAL output component. */ 530 cp = FindNextComponent(NULL, &cd); 531 if (RT_UNLIKELY(cp == 0)) 532 { 533 LogRel(("CoreAudio: [Output] Failed to find HAL output component\n")); 534 return -1; 535 } 536 537 /* Open the default HAL output component. */ 538 err = OpenAComponent(cp, &caVoice->audioUnit); 539 if (RT_UNLIKELY(err != noErr)) 540 { 541 LogRel(("CoreAudio: [Output] Failed to open output component (%RI32)\n", err)); 542 return -1; 543 } 544 545 /* Switch the I/O mode for output to on. */ 546 uFlag = 1; 547 err = AudioUnitSetProperty(caVoice->audioUnit, 548 kAudioOutputUnitProperty_EnableIO, 549 kAudioUnitScope_Output, 550 0, 551 &uFlag, 552 sizeof(uFlag)); 553 if (RT_UNLIKELY(err != noErr)) 554 { 555 LogRel(("CoreAudio: [Output] Failed to set output I/O mode enabled (%RI32)\n", err)); 556 return -1; 557 } 558 559 /* CoreAudio will inform us on a second thread when it needs more data for 560 * output. Therfor register an callback function which will provide the new 561 * data. */ 562 cb.inputProc = caPlaybackCallback; 563 cb.inputProcRefCon = caVoice; 564 565 err = AudioUnitSetProperty(caVoice->audioUnit, 566 kAudioUnitProperty_SetRenderCallback, 567 kAudioUnitScope_Global, 568 0, 569 &cb, 570 sizeof(cb)); 571 if (RT_UNLIKELY(err != noErr)) 572 { 573 LogRel(("CoreAudio: [Output] Failed to set callback (%RI32)\n", err)); 574 return -1; 575 } 576 577 /* Set the default audio output device as the device for the new AudioUnit. */ 578 err = AudioUnitSetProperty(caVoice->audioUnit, 579 kAudioOutputUnitProperty_CurrentDevice, 580 kAudioUnitScope_Global, 581 0, 582 &caVoice->audioDeviceId, 583 sizeof(caVoice->audioDeviceId)); 584 if (RT_UNLIKELY(err != noErr)) 585 { 586 LogRel(("CoreAudio: [Output] Failed to set current device (%RI32)\n", err)); 587 return -1; 588 } 589 590 /* Fetch the current stream format of the device. */ 591 uSize = sizeof(caVoice->deviceFormat); 592 err = AudioUnitGetProperty(caVoice->audioUnit, 593 kAudioUnitProperty_StreamFormat, 594 kAudioUnitScope_Input, 595 0, 596 &caVoice->deviceFormat, 597 &uSize); 598 if (RT_UNLIKELY(err != noErr)) 599 { 600 LogRel(("CoreAudio: [Output] Failed to get device format (%RI32)\n", err)); 601 return -1; 602 } 603 604 /* Create an AudioStreamBasicDescription based on the audio settings of 605 * VirtualBox. */ 606 caAudioSettingsToAudioStreamBasicDescription(as, &caVoice->streamFormat); 607 608 #if DEBUG 609 caDebugOutputAudioStreamBasicDescription("CoreAudio: [Output] device", &caVoice->deviceFormat); 610 caDebugOutputAudioStreamBasicDescription("CoreAudio: [Output] output", &caVoice->streamFormat); 611 #endif /* DEBUG */ 612 613 /* Set the device format description for the stream. */ 614 err = AudioUnitSetProperty(caVoice->audioUnit, 615 kAudioUnitProperty_StreamFormat, 616 kAudioUnitScope_Input, 617 0, 618 &caVoice->streamFormat, 619 sizeof(caVoice->streamFormat)); 620 if (RT_UNLIKELY(err != noErr)) 621 { 622 LogRel(("CoreAudio: [Output] Failed to set stream format (%RI32)\n", err)); 623 return -1; 624 } 625 626 /* Get the default frames buffer size, so that we can setup our internal 627 * buffers. */ 628 uSize = sizeof(cFrames); 629 err = AudioUnitGetProperty(caVoice->audioUnit, 630 kAudioDevicePropertyBufferFrameSize, 631 kAudioUnitScope_Output, 632 0, 633 &cFrames, 634 &uSize); 635 if (RT_UNLIKELY(err != noErr)) 636 { 637 LogRel(("CoreAudio: [Output] Failed to get frame buffer size (%RI32)\n", err)); 638 return -1; 639 } 640 641 /* cFrames = 1024;*/ 642 /* err = AudioUnitSetProperty(caVoice->audioUnit,*/ 643 /* kAudioDevicePropertyBufferFrameSize,*/ 644 /* kAudioUnitScope_Output,*/ 645 /* 0,*/ 646 /* &cFrames,*/ 647 /* sizeof(cFrames));*/ 648 /* if (RT_UNLIKELY(err != noErr))*/ 649 /* {*/ 650 /* LogRel(("CoreAudio: [Output] Failed to set frame buffer size (%RI32)\n", err));*/ 651 /* return -1;*/ 652 /* }*/ 653 654 /* Finaly init the new AudioUnit. */ 655 err = AudioUnitInitialize(caVoice->audioUnit); 656 if (RT_UNLIKELY(err != noErr)) 657 { 658 LogRel(("CoreAudio: [Output] Failed to initialize the AudioUnit (%RI32)\n", err)); 659 return -1; 660 } 661 662 /* Create the internal ring buffer. */ 663 hw->samples = cFrames * caVoice->streamFormat.mChannelsPerFrame; 664 IORingBufferCreate(&caVoice->pBuf, hw->samples << hw->info.shift); 665 if (!VALID_PTR(caVoice->pBuf)) 666 { 667 LogRel(("CoreAudio: [Output] Failed to create internal ring buffer\n")); 668 AudioUnitUninitialize(caVoice->audioUnit); 669 return -1; 670 } 671 672 Log(("CoreAudio: [Output] HW samples: %d; Frame count: %RU32\n", hw->samples, cFrames)); 673 181 674 return 0; 182 675 } 183 676 184 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name) 185 { 186 int err; 187 188 err = pthread_mutex_unlock (&core->mutex); 189 if (err) { 190 dolog ("Could not unlock voice for %s\nReason: %s\n", 191 fn_name, strerror (err)); 192 return -1; 677 static void coreaudio_fini_out(HWVoiceOut *hw) 678 { 679 OSStatus err = noErr; 680 caVoiceOut *caVoice = (caVoiceOut *) hw; 681 682 /* Only stop the device if it is actually running */ 683 if (caIsRunning(caVoice->audioDeviceId)) 684 err = AudioOutputUnitStop(caVoice->audioUnit); 685 if (RT_LIKELY(err == noErr)) 686 { 687 err = AudioUnitUninitialize(caVoice->audioUnit); 688 if (RT_LIKELY(err == noErr)) 689 { 690 caVoice->audioDeviceId = kAudioDeviceUnknown; 691 IORingBufferDestroy(caVoice->pBuf); 692 } 693 else 694 LogRel(("CoreAudio: [Output] Failed to uninitialize the AudioUnit (%RI32)\n", err)); 695 } 696 else 697 LogRel(("CoreAudio: [Output] Failed to stop playback (%RI32)\n", err)); 698 } 699 700 static int coreaudio_ctl_out(HWVoiceOut *hw, int cmd, ...) 701 { 702 OSStatus err = noErr; 703 caVoiceOut *caVoice = (caVoiceOut *) hw; 704 705 switch (cmd) 706 { 707 case VOICE_ENABLE: 708 { 709 /* Only start the device if it is actually stopped */ 710 if (!caIsRunning(caVoice->audioDeviceId)) 711 { 712 IORingBufferReset(caVoice->pBuf); 713 err = AudioOutputUnitStart(caVoice->audioUnit); 714 } 715 if (RT_UNLIKELY(err != noErr)) 716 { 717 LogRel(("CoreAudio: [Output] Failed to start playback (%RI32)\n", err)); 718 return -1; 719 } 720 break; 721 } 722 case VOICE_DISABLE: 723 { 724 /* Only stop the device if it is actually running */ 725 if (caIsRunning(caVoice->audioDeviceId)) 726 err = AudioOutputUnitStop(caVoice->audioUnit); 727 if (RT_UNLIKELY(err != noErr)) 728 { 729 LogRel(("CoreAudio: [Input] Failed to stop playback (%RI32)\n", err)); 730 return -1; 731 } 732 break; 733 } 193 734 } 194 735 return 0; 195 736 } 196 737 197 static int coreaudio_run_out (HWVoiceOut *hw) 198 { 199 int live, decr; 200 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 201 202 if (coreaudio_lock (core, "coreaudio_run_out")) { 203 return 0; 204 } 205 206 live = audio_pcm_hw_get_live_out (hw); 207 208 if (core->decr > live) { 209 ldebug ("core->decr %d live %d core->live %d\n", 210 core->decr, 211 live, 212 core->live); 213 } 214 215 decr = audio_MIN (core->decr, live); 216 core->decr -= decr; 217 218 core->live = live - decr; 219 hw->rpos = core->rpos; 220 221 coreaudio_unlock (core, "coreaudio_run_out"); 222 return decr; 223 } 224 225 /* callback to feed audiooutput buffer */ 226 static OSStatus audioDeviceIOProc( 227 AudioDeviceID inDevice, 228 const AudioTimeStamp* inNow, 229 const AudioBufferList* inInputData, 230 const AudioTimeStamp* inInputTime, 231 AudioBufferList* outOutputData, 232 const AudioTimeStamp* inOutputTime, 233 void* hwptr) 234 { 235 UInt32 frame, frameCount; 236 float *out = outOutputData->mBuffers[0].mData; 237 HWVoiceOut *hw = hwptr; 238 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; 239 int rpos, live; 240 st_sample_t *src; 241 #ifndef FLOAT_MIXENG 242 #ifdef RECIPROCAL 243 const float scale = 1.f / UINT_MAX; 244 #else 245 const float scale = UINT_MAX; 246 #endif 247 #endif 248 249 if (coreaudio_lock (core, "audioDeviceIOProc")) { 250 inInputTime = 0; 251 return 0; 252 } 253 254 frameCount = core->audioDevicePropertyBufferFrameSize; 255 live = core->live; 256 257 /* if there are not enough samples, set signal and return */ 258 if (live < frameCount) { 259 inInputTime = 0; 260 coreaudio_unlock (core, "audioDeviceIOProc(empty)"); 261 return 0; 262 } 263 264 rpos = core->rpos; 265 src = hw->mix_buf + rpos; 266 267 /* fill buffer */ 268 for (frame = 0; frame < frameCount; frame++) { 269 #ifdef FLOAT_MIXENG 270 *out++ = src[frame].l; /* left channel */ 271 *out++ = src[frame].r; /* right channel */ 272 #else 273 #ifdef RECIPROCAL 274 *out++ = src[frame].l * scale; /* left channel */ 275 *out++ = src[frame].r * scale; /* right channel */ 276 #else 277 *out++ = src[frame].l / scale; /* left channel */ 278 *out++ = src[frame].r / scale; /* right channel */ 279 #endif 280 #endif 281 } 282 283 rpos = (rpos + frameCount) % hw->samples; 284 core->decr += frameCount; 285 core->rpos = rpos; 286 287 coreaudio_unlock (core, "audioDeviceIOProc"); 738 /******************************************************************************* 739 * 740 * CoreAudio input section 741 * 742 ******************************************************************************/ 743 744 /* callback to feed audio input buffer */ 745 static OSStatus caRecordingCallback(void* inRefCon, 746 AudioUnitRenderActionFlags* ioActionFlags, 747 const AudioTimeStamp* inTimeStamp, 748 UInt32 inBusNumber, 749 UInt32 inNumberFrames, 750 AudioBufferList* ioData) 751 { 752 OSStatus err = noErr; 753 uint32_t csAvail = 0; 754 uint32_t csToWrite = 0; 755 uint32_t cbToWrite = 0; 756 uint32_t csWritten = 0; 757 char *pcDst = NULL; 758 759 caVoiceIn *caVoice = (caVoiceIn *) inRefCon; 760 761 /* If nothing is pending return immediately. */ 762 if (inNumberFrames == 0) 763 return noErr; 764 765 caVoice->pcaBufferList->mBuffers[0].mDataByteSize = caVoice->streamFormat.mBytesPerFrame * inNumberFrames; 766 caVoice->pcaBufferList->mBuffers[0].mData = RTMemAlloc(caVoice->pcaBufferList->mBuffers[0].mDataByteSize); 767 768 err = AudioUnitRender(caVoice->audioUnit, 769 ioActionFlags, 770 inTimeStamp, 771 inBusNumber, 772 inNumberFrames, 773 caVoice->pcaBufferList); 774 if(RT_UNLIKELY(err != noErr)) 775 { 776 Log(("CoreAudio: [Input] Failed to render audio data (%RI32)\n", err)); 777 RTMemFree(caVoice->pcaBufferList->mBuffers[0].mData); 778 return err; 779 } 780 781 /* How much space is free in the ring buffer? */ 782 csAvail = IORingBufferFree(caVoice->pBuf) >> caVoice->hw.info.shift; /* bytes -> samples */ 783 /* How much space is used in the core audio buffer. Use the smaller size of 784 * the too. */ 785 csAvail = RT_MIN(csAvail, caVoice->pcaBufferList->mBuffers[0].mDataByteSize >> caVoice->hw.info.shift); 786 787 Log2(("CoreAudio: [Input] Start writing buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift)); 788 789 /* Iterate as long as data is available */ 790 while(csWritten < csAvail) 791 { 792 /* How much is left? */ 793 csToWrite = csAvail - csWritten; 794 cbToWrite = csToWrite << caVoice->hw.info.shift; 795 Log2(("CoreAudio: [Input] Try writing %RU32 samples (%RU32 bytes)\n", csToWrite, cbToWrite)); 796 /* Try to aquire the necessary space from the ring buffer. */ 797 IORingBufferAquireWriteBlock(caVoice->pBuf, cbToWrite, &pcDst, &cbToWrite); 798 /* How much to we get? */ 799 csToWrite = cbToWrite >> caVoice->hw.info.shift; 800 Log2(("CoreAudio: [Input] There is space for %RU32 samples (%RU32 bytes) available\n", csToWrite, cbToWrite)); 801 /* Break if nothing is free anymore. */ 802 if (RT_UNLIKELY(cbToWrite == 0)) 803 break; 804 /* Copy the data from the core audio buffer to the ring buffer. */ 805 memcpy(pcDst, (char*)caVoice->pcaBufferList->mBuffers[0].mData + (csWritten << caVoice->hw.info.shift), cbToWrite); 806 /* Release the ring buffer, so the main thread could start reading this data. */ 807 IORingBufferReleaseWriteBlock(caVoice->pBuf, cbToWrite); 808 csWritten += csToWrite; 809 } 810 /* Cleanup */ 811 RTMemFree(caVoice->pcaBufferList->mBuffers[0].mData); 812 813 Log2(("CoreAudio: [Input] Finished writing buffer with %RU32 samples (%RU32 bytes)\n", csWritten, csWritten << caVoice->hw.info.shift)); 814 815 return noErr; 816 } 817 818 static int coreaudio_run_in(HWVoiceIn *hw) 819 { 820 uint32_t csAvail = 0; 821 uint32_t cbToRead = 0; 822 uint32_t csToRead = 0; 823 uint32_t csReads = 0; 824 char *pcSrc; 825 st_sample_t *psDst; 826 827 caVoiceIn *caVoice = (caVoiceIn *) hw; 828 829 /* How much space is used in the ring buffer? */ 830 csAvail = IORingBufferUsed(caVoice->pBuf) >> hw->info.shift; /* bytes -> samples */ 831 /* How much space is available in the mix buffer. Use the smaller size of 832 * the too. */ 833 csAvail = RT_MIN(csAvail, (uint32_t)(hw->samples - audio_pcm_hw_get_live_in (hw))); 834 835 Log2(("CoreAudio: [Input] Start reading buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift)); 836 837 /* Iterate as long as data is available */ 838 while (csReads < csAvail) 839 { 840 /* How much is left? Split request at the end of our samples buffer. */ 841 csToRead = RT_MIN(csAvail - csReads, (uint32_t)(hw->samples - hw->wpos)); 842 cbToRead = csToRead << hw->info.shift; 843 Log2(("CoreAudio: [Input] Try reading %RU32 samples (%RU32 bytes)\n", csToRead, cbToRead)); 844 /* Try to aquire the necessary block from the ring buffer. */ 845 IORingBufferAquireReadBlock(caVoice->pBuf, cbToRead, &pcSrc, &cbToRead); 846 /* How much to we get? */ 847 csToRead = cbToRead >> hw->info.shift; 848 Log2(("CoreAudio: [Input] There are %RU32 samples (%RU32 bytes) available\n", csToRead, cbToRead)); 849 /* Break if nothing is used anymore. */ 850 if (cbToRead == 0) 851 break; 852 /* Copy the data from our ring buffer to the mix buffer. */ 853 psDst = hw->conv_buf + hw->wpos; 854 hw->conv(psDst, pcSrc, csToRead, &nominal_volume); 855 /* Release the read buffer, so it could be used for new data. */ 856 IORingBufferReleaseReadBlock(caVoice->pBuf, cbToRead); 857 hw->wpos = (hw->wpos + csToRead) % hw->samples; 858 /* How much have we reads so far. */ 859 csReads += csToRead; 860 } 861 862 Log2(("CoreAudio: [Input] Finished reading buffer with %RU32 samples (%RU32 bytes)\n", csReads, csReads << caVoice->hw.info.shift)); 863 864 return csReads; 865 } 866 867 static int coreaudio_read(SWVoiceIn *sw, void *buf, int size) 868 { 869 return audio_pcm_sw_read (sw, buf, size); 870 } 871 872 static int coreaudio_init_in(HWVoiceIn *hw, audsettings_t *as) 873 { 874 OSStatus err = noErr; 875 int rc = -1; 876 UInt32 uSize = 0; /* temporary size of properties */ 877 UInt32 uFlag = 0; /* for setting flags */ 878 CFStringRef name; /* for the temporary device name fetching */ 879 const char *pszName; 880 ComponentDescription cd; /* description for an audio component */ 881 Component cp; /* an audio component */ 882 AURenderCallbackStruct cb; /* holds the callback structure */ 883 UInt32 cFrames; /* default frame count */ 884 885 caVoiceIn *caVoice = (caVoiceIn *) hw; 886 887 /* Initialize the hardware info section with the audio settings */ 888 audio_pcm_init_info(&hw->info, as); 889 890 /* Fetch the default audio input device currently in use */ 891 uSize = sizeof(caVoice->audioDeviceId); 892 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, 893 &uSize, 894 &caVoice->audioDeviceId); 895 if (RT_UNLIKELY(err != noErr)) 896 { 897 LogRel(("CoreAudio: [Input] Unable to find default input device (%RI32)\n", err)); 898 return -1; 899 } 900 901 /* Try to get the name of the default input device and log it. It's not 902 * fatal if it fails. */ 903 uSize = sizeof(CFStringRef); 904 err = AudioDeviceGetProperty(caVoice->audioDeviceId, 905 0, 906 1, 907 kAudioObjectPropertyName, 908 &uSize, 909 &name); 910 if (RT_LIKELY(err == noErr)) 911 { 912 pszName = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman); 913 if (pszName) 914 LogRel(("CoreAudio: Using default input device: %s\n", pszName)); 915 CFRelease(name); 916 } 917 else 918 LogRel(("CoreAudio: [Input] Unable to get input device name (%RI32)\n", err)); 919 920 cd.componentType = kAudioUnitType_Output; 921 cd.componentSubType = kAudioUnitSubType_HALOutput; 922 cd.componentManufacturer = kAudioUnitManufacturer_Apple; 923 cd.componentFlags = 0; 924 cd.componentFlagsMask = 0; 925 926 /* Try to find the default HAL output component. */ 927 cp = FindNextComponent(NULL, &cd); 928 if (RT_UNLIKELY(cp == 0)) 929 { 930 LogRel(("CoreAudio: [Input] Failed to find HAL output component\n")); 931 return -1; 932 } 933 934 /* Open the default HAL output component. */ 935 err = OpenAComponent(cp, &caVoice->audioUnit); 936 if (RT_UNLIKELY(err != noErr)) 937 { 938 LogRel(("CoreAudio: [Input] Failed to open output component (%RI32)\n", err)); 939 return -1; 940 } 941 942 /* Switch the I/O mode for input to on. */ 943 uFlag = 1; 944 err = AudioUnitSetProperty(caVoice->audioUnit, 945 kAudioOutputUnitProperty_EnableIO, 946 kAudioUnitScope_Input, 947 1, 948 &uFlag, 949 sizeof(uFlag)); 950 if (RT_UNLIKELY(err != noErr)) 951 { 952 LogRel(("CoreAudio: [Input] Failed to set input I/O mode enabled (%RI32)\n", err)); 953 return -1; 954 } 955 956 /* Switch the I/O mode for output to off. This is important, as this is a 957 * pure input stream. */ 958 uFlag = 0; 959 err = AudioUnitSetProperty(caVoice->audioUnit, 960 kAudioOutputUnitProperty_EnableIO, 961 kAudioUnitScope_Output, 962 0, 963 &uFlag, 964 sizeof(uFlag)); 965 if (RT_UNLIKELY(err != noErr)) 966 { 967 LogRel(("CoreAudio: [Input] Failed to set output I/O mode disabled (%RI32)\n", err)); 968 return -1; 969 } 970 971 /* CoreAudio will inform us on a second thread for new incoming audio data. 972 * Therfor register an callback function, which will process the new data. 973 * */ 974 cb.inputProc = caRecordingCallback; 975 cb.inputProcRefCon = caVoice; 976 977 err = AudioUnitSetProperty(caVoice->audioUnit, 978 kAudioOutputUnitProperty_SetInputCallback, 979 kAudioUnitScope_Global, 980 0, 981 &cb, 982 sizeof(cb)); 983 if (RT_UNLIKELY(err != noErr)) 984 { 985 LogRel(("CoreAudio: [Input] Failed to set callback (%RI32)\n", err)); 986 return -1; 987 } 988 989 /* Set the default audio input device as the device for the new AudioUnit. */ 990 err = AudioUnitSetProperty(caVoice->audioUnit, 991 kAudioOutputUnitProperty_CurrentDevice, 992 kAudioUnitScope_Global, 993 0, 994 &caVoice->audioDeviceId, 995 sizeof(caVoice->audioDeviceId)); 996 if (RT_UNLIKELY(err != noErr)) 997 { 998 LogRel(("CoreAudio: [Input] Failed to set current device (%RI32)\n", err)); 999 return -1; 1000 } 1001 1002 /* UInt32 fpb = 1024;*/ 1003 /* if (AudioDeviceSetProperty(core->audioDeviceId,*/ 1004 /* NULL,*/ 1005 /* 0,*/ 1006 /* 1,*/ 1007 /* kAudioDevicePropertyBufferSize,*/ 1008 /* sizeof(fpb), &fpb) != noErr)*/ 1009 /* {*/ 1010 /* LogRel(("CoreAudio: [Input] Unable to set frame buffer size)\n"));*/ 1011 /* return -1;*/ 1012 /* }*/ 1013 1014 /* Fetch the current stream format of the device. */ 1015 uSize = sizeof(caVoice->deviceFormat); 1016 err = AudioUnitGetProperty(caVoice->audioUnit, 1017 kAudioUnitProperty_StreamFormat, 1018 kAudioUnitScope_Input, 1019 1, 1020 &caVoice->deviceFormat, 1021 &uSize); 1022 if (RT_UNLIKELY(err != noErr)) 1023 { 1024 LogRel(("CoreAudio: [Input] Failed to get device format (%RI32)\n", err)); 1025 return -1; 1026 } 1027 1028 /* Create an AudioStreamBasicDescription based on the audio settings of 1029 * VirtualBox. */ 1030 caAudioSettingsToAudioStreamBasicDescription(as, &caVoice->streamFormat); 1031 1032 #if DEBUG 1033 caDebugOutputAudioStreamBasicDescription("CoreAudio: [Input] device", &caVoice->deviceFormat); 1034 caDebugOutputAudioStreamBasicDescription("CoreAudio: [Input] input", &caVoice->streamFormat); 1035 #endif /* DEBUG */ 1036 1037 /* If the frequency of the device is different from the requested one we 1038 * need a converter. */ 1039 if (caVoice->deviceFormat.mSampleRate != caVoice->streamFormat.mSampleRate) 1040 { 1041 Log(("CoreAudio: [Input] Converter in use\n")); 1042 /* Set the device format description for the stream. */ 1043 err = AudioUnitSetProperty(caVoice->audioUnit, 1044 kAudioUnitProperty_StreamFormat, 1045 kAudioUnitScope_Output, 1046 1, 1047 &caVoice->deviceFormat, 1048 sizeof(caVoice->deviceFormat)); 1049 } 1050 else 1051 { 1052 /* Set the new format description for the stream. */ 1053 err = AudioUnitSetProperty(caVoice->audioUnit, 1054 kAudioUnitProperty_StreamFormat, 1055 kAudioUnitScope_Output, 1056 1, 1057 &caVoice->streamFormat, 1058 sizeof(caVoice->streamFormat)); 1059 } 1060 if (RT_UNLIKELY(err != noErr)) 1061 { 1062 LogRel(("CoreAudio: [Input] Failed to set stream format (%RI32)\n", err)); 1063 return -1; 1064 } 1065 1066 /* Get the default frames per slice size, so that we can setup our internal 1067 * buffers. */ 1068 uSize = sizeof(cFrames); 1069 err = AudioUnitGetProperty(caVoice->audioUnit, 1070 kAudioDevicePropertyBufferFrameSize, 1071 kAudioUnitScope_Global, 1072 0, 1073 &cFrames, 1074 &uSize); 1075 if (RT_UNLIKELY(err != noErr)) 1076 { 1077 LogRel(("CoreAudio: [Input] Failed to get maximum frame per slice (%RI32)\n", err)); 1078 return -1; 1079 } 1080 1081 /* Finaly init the new AudioUnit. */ 1082 err = AudioUnitInitialize(caVoice->audioUnit); 1083 if (RT_UNLIKELY(err != noErr)) 1084 { 1085 LogRel(("CoreAudio: [Input] Failed to initialize the AudioUnit (%RI32)\n", err)); 1086 return -1; 1087 } 1088 1089 /* Set to zero first */ 1090 caVoice->pcaBufferList = NULL; 1091 caVoice->pBuf = NULL; 1092 /* Create the AudioBufferList structure with one buffer. */ 1093 caVoice->pcaBufferList = RTMemAllocZ(sizeof(AudioBufferList) + sizeof(AudioBuffer)); 1094 if (VALID_PTR(caVoice->pcaBufferList)) 1095 { 1096 caVoice->pcaBufferList->mNumberBuffers = 1; 1097 /* Initialize the buffer to nothing. */ 1098 caVoice->pcaBufferList->mBuffers[0].mNumberChannels = caVoice->streamFormat.mChannelsPerFrame; 1099 caVoice->pcaBufferList->mBuffers[0].mDataByteSize = 0; 1100 caVoice->pcaBufferList->mBuffers[0].mData = NULL; 1101 1102 /* Create the internal ring buffer. */ 1103 hw->samples = cFrames * caVoice->streamFormat.mChannelsPerFrame; 1104 IORingBufferCreate(&caVoice->pBuf, hw->samples << hw->info.shift); 1105 if (VALID_PTR(caVoice->pBuf)) 1106 rc = 0; 1107 else 1108 LogRel(("CoreAudio: [Input] Failed to create internal ring buffer\n")); 1109 } 1110 else 1111 LogRel(("CoreAudio: [Input] Failed to create the audio buffer list\n")); 1112 1113 if (rc != 0) 1114 { 1115 if (caVoice->pcaBufferList) 1116 RTMemFree(caVoice->pcaBufferList); 1117 if (caVoice->pBuf) 1118 IORingBufferDestroy(caVoice->pBuf); 1119 AudioUnitUninitialize(caVoice->audioUnit); 1120 } 1121 1122 Log(("CoreAudio: [Input] HW samples: %d; Frame count: %RU32\n", hw->samples, cFrames)); 1123 288 1124 return 0; 289 1125 } 290 1126 291 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len) 292 { 293 return audio_pcm_sw_write (sw, buf, len); 294 } 295 296 static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) 297 { 298 OSStatus status; 299 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 300 UInt32 propertySize; 301 int err; 302 const char *typ = "playback"; 303 AudioValueRange frameRange; 304 305 /* create mutex */ 306 err = pthread_mutex_init(&core->mutex, NULL); 307 if (err) { 308 dolog("Could not create mutex\nReason: %s\n", strerror (err)); 309 return -1; 310 } 311 312 audio_pcm_init_info (&hw->info, as); 313 314 /* open default output device */ 315 propertySize = sizeof(core->outputDeviceID); 316 status = AudioHardwareGetProperty( 317 kAudioHardwarePropertyDefaultOutputDevice, 318 &propertySize, 319 &core->outputDeviceID); 320 if (status != kAudioHardwareNoError) { 321 coreaudio_logerr2 (status, typ, 322 "Could not get default output Device\n"); 323 return -1; 324 } 325 if (core->outputDeviceID == kAudioDeviceUnknown) { 326 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); 327 return -1; 328 } 329 330 /* get minimum and maximum buffer frame sizes */ 331 propertySize = sizeof(frameRange); 332 status = AudioDeviceGetProperty( 333 core->outputDeviceID, 334 0, 335 0, 336 kAudioDevicePropertyBufferFrameSizeRange, 337 &propertySize, 338 &frameRange); 339 if (status != kAudioHardwareNoError) { 340 coreaudio_logerr2 (status, typ, 341 "Could not get device buffer frame range\n"); 342 return -1; 343 } 344 345 if (frameRange.mMinimum > conf.buffer_frames) { 346 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; 347 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); 348 } 349 else if (frameRange.mMaximum < conf.buffer_frames) { 350 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; 351 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); 352 } 353 else { 354 core->audioDevicePropertyBufferFrameSize = conf.buffer_frames; 355 } 356 357 /* set Buffer Frame Size */ 358 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); 359 status = AudioDeviceSetProperty( 360 core->outputDeviceID, 361 NULL, 362 0, 363 false, 364 kAudioDevicePropertyBufferFrameSize, 365 propertySize, 366 &core->audioDevicePropertyBufferFrameSize); 367 if (status != kAudioHardwareNoError) { 368 coreaudio_logerr2 (status, typ, 369 "Could not set device buffer frame size %ld\n", 370 core->audioDevicePropertyBufferFrameSize); 371 return -1; 372 } 373 374 /* get Buffer Frame Size */ 375 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); 376 status = AudioDeviceGetProperty( 377 core->outputDeviceID, 378 0, 379 false, 380 kAudioDevicePropertyBufferFrameSize, 381 &propertySize, 382 &core->audioDevicePropertyBufferFrameSize); 383 if (status != kAudioHardwareNoError) { 384 coreaudio_logerr2 (status, typ, 385 "Could not get device buffer frame size\n"); 386 return -1; 387 } 388 hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize; 389 390 /* get StreamFormat */ 391 propertySize = sizeof(core->outputStreamBasicDescription); 392 status = AudioDeviceGetProperty( 393 core->outputDeviceID, 394 0, 395 false, 396 kAudioDevicePropertyStreamFormat, 397 &propertySize, 398 &core->outputStreamBasicDescription); 399 if (status != kAudioHardwareNoError) { 400 coreaudio_logerr2 (status, typ, 401 "Could not get Device Stream properties\n"); 402 core->outputDeviceID = kAudioDeviceUnknown; 403 return -1; 404 } 405 406 /* set Samplerate */ 407 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; 408 propertySize = sizeof(core->outputStreamBasicDescription); 409 status = AudioDeviceSetProperty( 410 core->outputDeviceID, 411 0, 412 0, 413 0, 414 kAudioDevicePropertyStreamFormat, 415 propertySize, 416 &core->outputStreamBasicDescription); 417 if (status != kAudioHardwareNoError) { 418 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", 419 as->freq); 420 core->outputDeviceID = kAudioDeviceUnknown; 421 return -1; 422 } 423 424 /* set Callback */ 425 status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw); 426 if (status != kAudioHardwareNoError) { 427 coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); 428 core->outputDeviceID = kAudioDeviceUnknown; 429 return -1; 430 } 431 432 /* start Playback */ 433 if (!isPlaying(core->outputDeviceID)) { 434 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); 435 if (status != kAudioHardwareNoError) { 436 coreaudio_logerr2 (status, typ, "Could not start playback\n"); 437 AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); 438 core->outputDeviceID = kAudioDeviceUnknown; 439 return -1; 1127 static void coreaudio_fini_in(HWVoiceIn *hw) 1128 { 1129 OSStatus err = noErr; 1130 caVoiceIn *caVoice = (caVoiceIn *) hw; 1131 1132 /* Only stop the device if it is actually running */ 1133 if (caIsRunning(caVoice->audioDeviceId)) 1134 err = AudioOutputUnitStop(caVoice->audioUnit); 1135 if (RT_LIKELY(err == noErr)) 1136 { 1137 err = AudioUnitUninitialize(caVoice->audioUnit); 1138 if (RT_LIKELY(err == noErr)) 1139 { 1140 caVoice->audioDeviceId = kAudioDeviceUnknown; 1141 IORingBufferDestroy(caVoice->pBuf); 1142 RTMemFree(caVoice->pcaBufferList); 440 1143 } 441 } 442 1144 else 1145 LogRel(("CoreAudio: [Input] Failed to uninitialize the AudioUnit (%RI32)\n", err)); 1146 } 1147 else 1148 LogRel(("CoreAudio: [Input] Failed to stop recording (%RI32)\n", err)); 1149 } 1150 1151 static int coreaudio_ctl_in(HWVoiceIn *hw, int cmd, ...) 1152 { 1153 OSStatus err = noErr; 1154 caVoiceIn *caVoice = (caVoiceIn *) hw; 1155 1156 switch (cmd) 1157 { 1158 case VOICE_ENABLE: 1159 { 1160 /* Only start the device if it is actually stopped */ 1161 if (!caIsRunning(caVoice->audioDeviceId)) 1162 { 1163 IORingBufferReset(caVoice->pBuf); 1164 err = AudioOutputUnitStart(caVoice->audioUnit); 1165 } 1166 if (RT_UNLIKELY(err != noErr)) 1167 { 1168 LogRel(("CoreAudio: [Input] Failed to start recording (%RI32)\n", err)); 1169 return -1; 1170 } 1171 break; 1172 } 1173 case VOICE_DISABLE: 1174 { 1175 /* Only stop the device if it is actually running */ 1176 if (caIsRunning(caVoice->audioDeviceId)) 1177 err = AudioOutputUnitStop(caVoice->audioUnit); 1178 if (RT_UNLIKELY(err != noErr)) 1179 { 1180 LogRel(("CoreAudio: [Input] Failed to stop recording (%RI32)\n", err)); 1181 return -1; 1182 } 1183 break; 1184 } 1185 } 443 1186 return 0; 444 1187 } 445 1188 446 static void coreaudio_fini_out (HWVoiceOut *hw) 447 { 448 OSStatus status; 449 int err; 450 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 451 452 if (!conf.isAtexit) { 453 /* stop playback */ 454 if (isPlaying(core->outputDeviceID)) { 455 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); 456 if (status != kAudioHardwareNoError) { 457 coreaudio_logerr (status, "Could not stop playback\n"); 458 } 459 } 460 461 /* remove callback */ 462 status = AudioDeviceRemoveIOProc(core->outputDeviceID, 463 audioDeviceIOProc); 464 if (status != kAudioHardwareNoError) { 465 coreaudio_logerr (status, "Could not remove IOProc\n"); 466 } 467 } 468 core->outputDeviceID = kAudioDeviceUnknown; 469 470 /* destroy mutex */ 471 err = pthread_mutex_destroy(&core->mutex); 472 if (err) { 473 dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); 474 } 475 } 476 477 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) 478 { 479 OSStatus status; 480 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 481 482 switch (cmd) { 483 case VOICE_ENABLE: 484 /* start playback */ 485 if (!isPlaying(core->outputDeviceID)) { 486 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); 487 if (status != kAudioHardwareNoError) { 488 coreaudio_logerr (status, "Could not resume playback\n"); 489 } 490 } 491 break; 492 493 case VOICE_DISABLE: 494 /* stop playback */ 495 if (!conf.isAtexit) { 496 if (isPlaying(core->outputDeviceID)) { 497 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); 498 if (status != kAudioHardwareNoError) { 499 coreaudio_logerr (status, "Could not pause playback\n"); 500 } 501 } 502 } 503 break; 504 } 505 return 0; 506 } 507 508 static void *coreaudio_audio_init (void) 509 { 510 atexit(coreaudio_atexit); 511 return &coreaudio_audio_init; 512 } 513 514 static void coreaudio_audio_fini (void *opaque) 515 { 516 (void) opaque; 517 } 518 519 static struct audio_option coreaudio_options[] = { 520 {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames, 1189 /******************************************************************************* 1190 * 1191 * CoreAudio global section 1192 * 1193 ******************************************************************************/ 1194 1195 static void *coreaudio_audio_init(void) 1196 { 1197 return &conf; 1198 } 1199 1200 static void coreaudio_audio_fini(void *opaque) 1201 { 1202 NOREF(opaque); 1203 } 1204 1205 static struct audio_option coreaudio_options[] = 1206 { 1207 {"BUFFER_SIZE", AUD_OPT_INT, &conf.cBufferFrames, 521 1208 "Size of the buffer in frames", NULL, 0}, 522 {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,523 "Number of buffers", NULL, 0},524 1209 {NULL, 0, NULL, NULL, NULL, 0} 525 1210 }; 526 1211 527 static struct audio_pcm_ops coreaudio_pcm_ops = { 1212 static struct audio_pcm_ops coreaudio_pcm_ops = 1213 { 528 1214 coreaudio_init_out, 529 1215 coreaudio_fini_out, … … 532 1218 coreaudio_ctl_out, 533 1219 534 NULL,535 NULL,536 NULL,537 NULL,538 NULL1220 coreaudio_init_in, 1221 coreaudio_fini_in, 1222 coreaudio_run_in, 1223 coreaudio_read, 1224 coreaudio_ctl_in 539 1225 }; 540 1226 541 struct audio_driver coreaudio_audio_driver = { 542 INIT_FIELD (name = ) "coreaudio", 543 INIT_FIELD (descr = ) 1227 struct audio_driver coreaudio_audio_driver = 1228 { 1229 INIT_FIELD(name =) "coreaudio", 1230 INIT_FIELD(descr =) 544 1231 "CoreAudio http://developer.apple.com/audio/coreaudio.html", 545 INIT_FIELD (options =) coreaudio_options,546 INIT_FIELD (init =) coreaudio_audio_init,547 INIT_FIELD (fini =) coreaudio_audio_fini,548 INIT_FIELD (pcm_ops =) &coreaudio_pcm_ops,549 INIT_FIELD (can_be_default =) 1,550 INIT_FIELD (max_voices_out =) 1,551 INIT_FIELD (max_voices_in = ) 0,552 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),553 INIT_FIELD (voice_size_in = ) 01232 INIT_FIELD(options =) coreaudio_options, 1233 INIT_FIELD(init =) coreaudio_audio_init, 1234 INIT_FIELD(fini =) coreaudio_audio_fini, 1235 INIT_FIELD(pcm_ops =) &coreaudio_pcm_ops, 1236 INIT_FIELD(can_be_default =) 1, 1237 INIT_FIELD(max_voices_out =) 1, 1238 INIT_FIELD(max_voices_in =) 1, 1239 INIT_FIELD(voice_size_out =) sizeof(caVoiceOut), 1240 INIT_FIELD(voice_size_in =) sizeof(caVoiceIn) 554 1241 }; 1242 -
trunk/src/VBox/Devices/Makefile.kmk
r25336 r25770 231 231 VBoxDD_LDFLAGS.darwin = -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxDD.dylib \ 232 232 -framework CoreAudio \ 233 -framework AudioUnit \ 233 234 -framework IOKit \ 234 235 -framework Carbon \
Note:
See TracChangeset
for help on using the changeset viewer.