Changeset 89022 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 12, 2021 10:05:33 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144361
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88993 r89022 2204 2204 drvAudioStreamResetInternal(pStreamEx); 2205 2205 2206 /** @todo 2207 * We need to zero the backend storage here!! 2208 * We need to zero the backend storage here!! 2209 * We need to zero the backend storage here!! 2210 * We need to zero the backend storage here!! 2211 * We need to zero the backend storage here!! 2212 * We need to zero the backend storage here!! 2213 * We need to zero the backend storage here!! 2214 * */ 2206 2215 PDMAUDIOSTREAMCFG CfgHostAcq; 2207 2216 rc = drvAudioStreamCreateInternalBackend(pThis, pStreamEx, &pStreamEx->Host.Cfg, &CfgHostAcq); -
trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp
r89009 r89022 2 2 /** @file 3 3 * Host audio driver - Mac OS X CoreAudio. 4 * 5 * For relevant Apple documentation, here are some starters: 6 * - http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html 7 * - http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html 8 * - http://developer.apple.com/mac/library/qa/qa2007/qa1533.html 9 * - http://developer.apple.com/mac/library/qa/qa2001/qa1317.html 10 * - http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html 4 11 */ 5 12 … … 56 63 */ 57 64 58 /* 59 * Most of this is based on: 60 * http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html 61 * http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html 62 * http://developer.apple.com/mac/library/qa/qa2007/qa1533.html 63 * http://developer.apple.com/mac/library/qa/qa2001/qa1317.html 64 * http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html 65 */ 66 67 /* Prototypes needed for COREAUDIODEVICE. */ 68 struct DRVHOSTCOREAUDIO; 65 66 /********************************************************************************************************************************* 67 * Structures and Typedefs * 68 *********************************************************************************************************************************/ 69 /** Pointer to the instance data for a Core Audio driver instance. */ 69 70 typedef struct DRVHOSTCOREAUDIO *PDRVHOSTCOREAUDIO; 70 71 /** 72 * Core Audio-specific device entry. 71 /** Pointer to the Core Audio specific backend data for an audio stream. */ 72 typedef struct COREAUDIOSTREAM *PCOREAUDIOSTREAM; 73 74 /** 75 * Core Audio device entry (enumeration). 73 76 * 74 77 * @note This is definitely not safe to just copy! … … 77 80 { 78 81 /** The core PDM structure. */ 79 PDMAUDIOHOSTDEV 82 PDMAUDIOHOSTDEV Core; 80 83 81 84 /** Pointer to driver instance this device is bound to. */ … … 89 92 RTLISTANCHOR lstStreams; 90 93 } COREAUDIODEVICEDATA; 94 /** Pointer to a Core Audio device entry (enumeration). */ 91 95 typedef COREAUDIODEVICEDATA *PCOREAUDIODEVICEDATA; 92 96 93 /** 94 * Host Coreaudio driver instance data. 97 98 /** 99 * Core Audio stream state. 100 */ 101 typedef enum COREAUDIOINITSTATE 102 { 103 /** The device is uninitialized. */ 104 COREAUDIOINITSTATE_UNINIT = 0, 105 /** The device is currently initializing. */ 106 COREAUDIOINITSTATE_IN_INIT, 107 /** The device is initialized. */ 108 COREAUDIOINITSTATE_INIT, 109 /** The device is currently uninitializing. */ 110 COREAUDIOINITSTATE_IN_UNINIT, 111 /** The usual 32-bit hack. */ 112 COREAUDIOINITSTATE_32BIT_HACK = 0x7fffffff 113 } COREAUDIOINITSTATE; 114 115 116 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER 117 /** 118 * Context data for the audio format converter. 119 */ 120 typedef struct COREAUDIOCONVCBCTX 121 { 122 /** Pointer to the stream this context is bound to. */ 123 PCOREAUDIOSTREAM pStream; /**< @todo r=bird: It's part of the COREAUDIOSTREAM structure! You don't need this. */ 124 /** Source stream description. */ 125 AudioStreamBasicDescription asbdSrc; 126 /** Destination stream description. */ 127 AudioStreamBasicDescription asbdDst; 128 /** Pointer to native buffer list used for rendering the source audio data into. */ 129 AudioBufferList *pBufLstSrc; 130 /** Total packet conversion count. */ 131 UInt32 uPacketCnt; 132 /** Current packet conversion index. */ 133 UInt32 uPacketIdx; 134 /** Error count, for limiting the logging. */ 135 UInt32 cErrors; 136 } COREAUDIOCONVCBCTX; 137 /** Pointer to the context of a conversion callback. */ 138 typedef COREAUDIOCONVCBCTX *PCOREAUDIOCONVCBCTX; 139 #endif /* VBOX_WITH_AUDIO_CA_CONVERTER */ 140 141 142 /** 143 * Core Audio specific data for an audio stream. 144 */ 145 typedef struct COREAUDIOSTREAM 146 { 147 /** Common part. */ 148 PDMAUDIOBACKENDSTREAM Core; 149 150 /** The stream's acquired configuration. */ 151 PDMAUDIOSTREAMCFG Cfg; 152 /** Stream-specific data, depending on the stream type. */ 153 union 154 { 155 struct 156 { 157 #if 0 /* Unused */ 158 /** The ratio between the device & the stream sample rate. */ 159 Float64 sampleRatio; 160 #endif 161 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER 162 /** The audio converter if necessary. NULL if no converter is being used. */ 163 AudioConverterRef ConverterRef; 164 /** Callback context for the audio converter. */ 165 COREAUDIOCONVCBCTX convCbCtx; 166 #endif 167 } In; 168 //struct {} Out; 169 }; 170 /** List node for the device's stream list. */ 171 RTLISTNODE Node; 172 /** Pointer to driver instance this stream is bound to. */ 173 PDRVHOSTCOREAUDIO pDrv; 174 /** The stream's thread handle for maintaining the audio queue. */ 175 RTTHREAD hThread; 176 /** The runloop of the queue thread. */ 177 CFRunLoopRef hRunLoop; 178 /** Flag indicating to start a stream's data processing. */ 179 bool fRun; 180 /** Whether the stream is in a running (active) state or not. 181 * For playback streams this means that audio data can be (or is being) played, 182 * for capturing streams this means that audio data is being captured (if available). */ 183 bool fIsRunning; 184 /** Thread shutdown indicator. */ 185 bool volatile fShutdown; 186 /** The actual audio queue being used. */ 187 AudioQueueRef hAudioQueue; 188 /** The audio buffers which are used with the above audio queue. */ 189 AudioQueueBufferRef apAudioBuffers[2]; 190 /** The acquired (final) audio format for this stream. */ 191 AudioStreamBasicDescription asbdStream; 192 /** The audio unit for this stream. */ 193 struct 194 { 195 /** Pointer to the device this audio unit is bound to. 196 * Can be NULL if not bound to a device (anymore). */ 197 PCOREAUDIODEVICEDATA pDevice; 198 #if 0 /* not used */ 199 /** The actual audio unit object. */ 200 AudioUnit hAudioUnit; 201 /** Stream description for using with VBox: 202 * - When using this audio unit for input (capturing), this format states 203 * the unit's output format. 204 * - When using this audio unit for output (playback), this format states 205 * the unit's input format. */ 206 AudioStreamBasicDescription StreamFmt; 207 #endif 208 } Unit; 209 /** Initialization status tracker, actually COREAUDIOINITSTATE. 210 * Used when some of the device parameters or the device itself is changed 211 * during the runtime. */ 212 volatile uint32_t enmInitState; 213 /** An internal ring buffer for transferring data from/to the rendering callbacks. */ 214 PRTCIRCBUF pCircBuf; 215 /** Critical section for serializing access between thread + callbacks. */ 216 RTCRITSECT CritSect; 217 } COREAUDIOSTREAM; 218 219 220 /** 221 * Instance data for a Core Audio host audio driver. 222 * 95 223 * @implements PDMIAUDIOCONNECTOR 96 224 */ … … 114 242 PPDMIHOSTAUDIOPORT pIHostAudioPort; 115 243 /** Indicates whether we've registered default input device change listener. */ 116 bool 244 bool fRegisteredDefaultInputListener; 117 245 /** Indicates whether we've registered default output device change listener. */ 118 bool fRegisteredDefaultOutputListener; 119 } DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO; 120 121 /** Converts a pointer to DRVHOSTCOREAUDIO::IHostAudio to a PDRVHOSTCOREAUDIO. */ 122 #define PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio) 123 124 /** 125 * Structure for holding a Core Audio unit 126 * and its data. 127 */ 128 typedef struct COREAUDIOUNIT 129 { 130 /** Pointer to the device this audio unit is bound to. 131 * Can be NULL if not bound to a device (anymore). */ 132 PCOREAUDIODEVICEDATA pDevice; 133 /** The actual audio unit object. */ 134 AudioUnit audioUnit; 135 /** Stream description for using with VBox: 136 * - When using this audio unit for input (capturing), this format states 137 * the unit's output format. 138 * - When using this audio unit for output (playback), this format states 139 * the unit's input format. */ 140 AudioStreamBasicDescription streamFmt; 141 } COREAUDIOUNIT, *PCOREAUDIOUNIT; 142 143 144 DECLHIDDEN(int) coreAudioInputPermissionCheck(void); 246 bool fRegisteredDefaultOutputListener; 247 } DRVHOSTCOREAUDIO; 145 248 146 249 147 250 /********************************************************************************************************************************* 148 * Helper function section*251 * Global Variables * 149 252 *********************************************************************************************************************************/ 150 151 /* Move these down below the internal function prototypes... */ 253 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER 254 /** Error code which indicates "End of data" */ 255 static const OSStatus g_rcCoreAudioConverterEOFDErr = 0x656F6664; /* 'eofd' */ 256 #endif 257 258 259 /********************************************************************************************************************************* 260 * Internal Functions * 261 *********************************************************************************************************************************/ 262 DECLHIDDEN(int) coreAudioInputPermissionCheck(void); /* DrvHostAudioCoreAudioAuth.mm */ 263 static int drvHostCoreAudioStreamControlInternal(PCOREAUDIOSTREAM pStreamCA, PDMAUDIOSTREAMCMD enmStreamCmd); 264 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer, 265 const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc, 266 const AudioStreamPacketDescription *paPacketDesc); 267 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer); 268 269 270 152 271 153 272 static void coreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescription *pASBD) … … 184 303 } 185 304 305 186 306 static void coreAudioPCMPropsToASBD(PCPDMAUDIOPCMPROPS pProps, AudioStreamBasicDescription *pASBD) 187 307 { … … 258 378 259 379 260 /*********************************************************************************************************************************261 * Structures and Typedefs *262 *********************************************************************************************************************************/263 264 /** @name Initialization status indicator used for the recreation of the AudioUnits.265 *266 * Global structures section267 *268 ******************************************************************************/269 270 /**271 * Enumeration for a Core Audio stream status.272 */273 typedef enum COREAUDIOSTATUS274 {275 /** The device is uninitialized. */276 COREAUDIOSTATUS_UNINIT = 0,277 /** The device is currently initializing. */278 COREAUDIOSTATUS_IN_INIT,279 /** The device is initialized. */280 COREAUDIOSTATUS_INIT,281 /** The device is currently uninitializing. */282 COREAUDIOSTATUS_IN_UNINIT,283 /** The usual 32-bit hack. */284 COREAUDIOSTATUS_32BIT_HACK = 0x7fffffff285 } COREAUDIOSTATUS, *PCOREAUDIOSTATUS;286 287 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER288 /* Error code which indicates "End of data" */289 static const OSStatus caConverterEOFDErr = 0x656F6664; /* 'eofd' */290 #endif291 292 /* Prototypes needed for COREAUDIOSTREAMCBCTX. */293 struct COREAUDIOSTREAM;294 typedef struct COREAUDIOSTREAM *PCOREAUDIOSTREAM;295 296 /**297 * Structure for keeping a conversion callback context.298 * This is needed when using an audio converter during input/output processing.299 */300 typedef struct COREAUDIOCONVCBCTX301 {302 /** Pointer to the stream this context is bound to. */303 PCOREAUDIOSTREAM pStream;304 /** Source stream description. */305 AudioStreamBasicDescription asbdSrc;306 /** Destination stream description. */307 AudioStreamBasicDescription asbdDst;308 /** Pointer to native buffer list used for rendering the source audio data into. */309 AudioBufferList *pBufLstSrc;310 /** Total packet conversion count. */311 UInt32 uPacketCnt;312 /** Current packet conversion index. */313 UInt32 uPacketIdx;314 /** Error count, for limiting the logging. */315 UInt32 cErrors;316 } COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;317 318 /**319 * Structure for keeping the input stream specifics.320 */321 typedef struct COREAUDIOSTREAMIN322 {323 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER324 /** The audio converter if necessary. NULL if no converter is being used. */325 AudioConverterRef ConverterRef;326 /** Callback context for the audio converter. */327 COREAUDIOCONVCBCTX convCbCtx;328 #endif329 /** The ratio between the device & the stream sample rate. */330 Float64 sampleRatio;331 } COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;332 333 /**334 * Structure for keeping the output stream specifics.335 */336 typedef struct COREAUDIOSTREAMOUT337 {338 /** Nothing here yet. */339 } COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;340 341 /**342 * Structure for maintaining a Core Audio stream.343 */344 typedef struct COREAUDIOSTREAM345 {346 /** Common part. */347 PDMAUDIOBACKENDSTREAM Core;348 349 /** The stream's acquired configuration. */350 PPDMAUDIOSTREAMCFG pCfg;351 /** Stream-specific data, depending on the stream type. */352 union353 {354 COREAUDIOSTREAMIN In;355 COREAUDIOSTREAMOUT Out;356 };357 /** List node for the device's stream list. */358 RTLISTNODE Node;359 /** Pointer to driver instance this stream is bound to. */360 PDRVHOSTCOREAUDIO pDrv;361 /** The stream's thread handle for maintaining the audio queue. */362 RTTHREAD hThread;363 /** Flag indicating to start a stream's data processing. */364 bool fRun;365 /** Whether the stream is in a running (active) state or not.366 * For playback streams this means that audio data can be (or is being) played,367 * for capturing streams this means that audio data is being captured (if available). */368 bool fIsRunning;369 /** Thread shutdown indicator. */370 bool fShutdown;371 /** Critical section for serializing access between thread + callbacks. */372 RTCRITSECT CritSect;373 /** The actual audio queue being used. */374 AudioQueueRef audioQueue;375 /** The audio buffers which are used with the above audio queue. */376 AudioQueueBufferRef audioBuffer[2];377 /** The acquired (final) audio format for this stream. */378 AudioStreamBasicDescription asbdStream;379 /** The audio unit for this stream. */380 COREAUDIOUNIT Unit;381 /** Initialization status tracker, actually COREAUDIOSTATUS.382 * Used when some of the device parameters or the device itself is changed383 * during the runtime. */384 volatile uint32_t enmStatus;385 /** An internal ring buffer for transferring data from/to the rendering callbacks. */386 PRTCIRCBUF pCircBuf;387 } COREAUDIOSTREAM, *PCOREAUDIOSTREAM;388 389 390 /*********************************************************************************************************************************391 * Internal Functions *392 *********************************************************************************************************************************/393 static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream);394 395 static int coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd);396 397 static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);398 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,399 const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc,400 const AudioStreamPacketDescription *paPacketDesc);401 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer);402 403 404 380 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER 405 381 … … 467 443 * @param enmSts Status to propagate. 468 444 */ 469 static int coreAudioDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIO STATUSenmSts)445 static int coreAudioDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIOINITSTATE enmSts) 470 446 { 471 447 AssertPtrReturn(pDev, VERR_INVALID_POINTER); … … 477 453 LogFlowFunc(("pDev=%p enmSts=%RU32\n", pDev, enmSts)); 478 454 479 PCOREAUDIOSTREAM p CAStream;480 RTListForEach(&pDev->lstStreams, p CAStream, COREAUDIOSTREAM, Node)481 { 482 LogFlowFunc(("p CAStream=%p\n", pCAStream));455 PCOREAUDIOSTREAM pStreamCA; 456 RTListForEach(&pDev->lstStreams, pStreamCA, COREAUDIOSTREAM, Node) 457 { 458 LogFlowFunc(("pStreamCA=%p\n", pStreamCA)); 483 459 484 460 /* We move the reinitialization to the next output event. 485 461 * This make sure this thread isn't blocked and the 486 462 * reinitialization is done when necessary only. */ 487 ASMAtomic XchgU32(&pCAStream->enmStatus, enmSts);463 ASMAtomicWriteU32(&pStreamCA->enmInitState, enmSts); 488 464 } 489 465 … … 536 512 537 513 /* Mark device as dead. */ 538 rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIO STATUS_UNINIT);514 rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOINITSTATE_UNINIT); 539 515 AssertRC(rc2); 540 516 } … … 613 589 RT_NOREF(inAudioConverter); 614 590 615 AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);616 AssertPtrReturn(ioData, caConverterEOFDErr);591 AssertPtrReturn(ioNumberDataPackets, g_rcCoreAudioConverterEOFDErr); 592 AssertPtrReturn(ioData, g_rcCoreAudioConverterEOFDErr); 617 593 618 594 PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser; … … 693 669 694 670 /** 695 * Thread for a Core Audio stream's audio queue handling. 671 * @callback_method_impl{FNRTTHREAD, 672 * Thread for a Core Audio stream's audio queue handling.} 696 673 * 697 674 * This thread is required per audio queue to pump data to/from the Core Audio 698 675 * stream and handling its callbacks. 699 *700 * @returns IPRT status code.701 * @param hThreadSelf Thread handle.702 * @param pvUser User argument.703 676 */ 704 677 static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser) 705 678 { 706 RT_NOREF(hThreadSelf); 707 708 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser; 709 AssertPtr(pCAStream); 710 AssertPtr(pCAStream->pCfg); 711 712 const bool fIn = pCAStream->pCfg->enmDir == PDMAUDIODIR_IN; 713 714 LogFunc(("Thread started for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn)); 679 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser; 680 AssertPtr(pStreamCA); 681 const bool fIn = pStreamCA->Cfg.enmDir == PDMAUDIODIR_IN; 682 PCOREAUDIODEVICEDATA const pDev = (PCOREAUDIODEVICEDATA)pStreamCA->Unit.pDevice; 683 CFRunLoopRef const hRunLoop = CFRunLoopGetCurrent(); 684 AssertPtr(pDev); 685 686 LogFunc(("Thread started for pStreamCA=%p fIn=%RTbool\n", pStreamCA, fIn)); 715 687 716 688 /* 717 689 * Create audio queue. 718 690 */ 719 OSStatus err; 691 int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 692 OSStatus orc; 720 693 if (fIn) 721 err = AudioQueueNewInput(&pCAStream->asbdStream, coreAudioInputQueueCb, pCAStream/* pvData */,722 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &p CAStream->audioQueue);694 orc = AudioQueueNewInput(&pStreamCA->asbdStream, coreAudioInputQueueCb, pStreamCA /* pvData */, 695 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pStreamCA->hAudioQueue); 723 696 else 724 err = AudioQueueNewOutput(&pCAStream->asbdStream, coreAudioOutputQueueCb, pCAStream /* pvData */, 725 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue); 726 727 if (err != noErr) 728 return VERR_GENERAL_FAILURE; /** @todo Fudge! */ 729 730 /* 731 * Assign device to queue. 732 */ 733 PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pCAStream->Unit.pDevice; 734 AssertPtr(pDev); 735 736 UInt32 uSize = sizeof(pDev->UUID); 737 err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pDev->UUID, uSize); 738 if (err != noErr) 739 return VERR_GENERAL_FAILURE; /** @todo Fudge! */ 740 741 const size_t cbBufSize = PDMAudioPropsFramesToBytes(&pCAStream->pCfg->Props, pCAStream->pCfg->Backend.cFramesPeriod); 742 743 /* 744 * Allocate audio buffers. 745 */ 746 for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++) 747 { 748 err = AudioQueueAllocateBuffer(pCAStream->audioQueue, cbBufSize, &pCAStream->audioBuffer[i]); 749 if (err != noErr) 750 break; 751 } 752 753 if (err != noErr) 754 return VERR_GENERAL_FAILURE; /** @todo Fudge! */ 755 756 /* Signal the main thread before entering the main loop. */ 757 RTThreadUserSignal(RTThreadSelf()); 758 759 /* 760 * Enter the main loop. 761 */ 762 while (!ASMAtomicReadBool(&pCAStream->fShutdown)) 763 { 764 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1); 765 } 766 767 /* 768 * Cleanup. 769 */ 770 if (fIn) 771 { 772 AudioQueueStop(pCAStream->audioQueue, 1); 697 orc = AudioQueueNewOutput(&pStreamCA->asbdStream, coreAudioOutputQueueCb, pStreamCA /* pvData */, 698 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pStreamCA->hAudioQueue); 699 if (orc == noErr) 700 { 701 /* 702 * Assign device to the queue. 703 */ 704 UInt32 uSize = sizeof(pDev->UUID); 705 orc = AudioQueueSetProperty(pStreamCA->hAudioQueue, kAudioQueueProperty_CurrentDevice, &pDev->UUID, uSize); 706 if (orc == noErr) 707 { 708 /* 709 * Allocate audio buffers. 710 */ 711 const size_t cbBuf = PDMAudioPropsFramesToBytes(&pStreamCA->Cfg.Props, pStreamCA->Cfg.Backend.cFramesPeriod); 712 size_t iBuf; 713 for (iBuf = 0; orc == noErr && iBuf < RT_ELEMENTS(pStreamCA->apAudioBuffers); iBuf++) 714 orc = AudioQueueAllocateBuffer(pStreamCA->hAudioQueue, cbBuf, &pStreamCA->apAudioBuffers[iBuf]); 715 if (orc == noErr) 716 { 717 /* 718 * Get a reference to our runloop so it can be stopped then signal 719 * our creator to say that we're done. The runloop reference is the 720 * success indicator. 721 */ 722 pStreamCA->hRunLoop = hRunLoop; 723 CFRetain(hRunLoop); 724 RTThreadUserSignal(hThreadSelf); 725 726 /* 727 * The main loop. 728 */ 729 while (!ASMAtomicReadBool(&pStreamCA->fShutdown)) 730 { 731 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30.0 /*sec*/, 1); 732 } 733 734 AudioQueueStop(pStreamCA->hAudioQueue, fIn ? 1 : 0); 735 rc = VINF_SUCCESS; 736 } 737 else 738 LogRel(("CoreAudio: Failed to allocate %#x byte queue buffer #%u: %#x (%d)\n", cbBuf, iBuf, orc, orc)); 739 740 while (iBuf-- > 0) 741 { 742 AudioQueueFreeBuffer(pStreamCA->hAudioQueue, pStreamCA->apAudioBuffers[iBuf]); 743 pStreamCA->apAudioBuffers[iBuf] = NULL; 744 } 745 } 746 else 747 LogRel(("CoreAudio: Failed to associate device with queue: %#x (%d)\n", orc, orc)); 748 749 AudioQueueDispose(pStreamCA->hAudioQueue, 1); 773 750 } 774 751 else 775 { 776 AudioQueueStop(pCAStream->audioQueue, 0); 777 } 778 779 for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++) 780 { 781 if (pCAStream->audioBuffer[i]) 782 AudioQueueFreeBuffer(pCAStream->audioQueue, pCAStream->audioBuffer[i]); 783 } 784 785 AudioQueueDispose(pCAStream->audioQueue, 1); 786 787 LogFunc(("Thread ended for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn)); 788 return VINF_SUCCESS; 752 LogRel(("CoreAudio: Failed to create audio queue: %#x (%d)\n", orc, orc)); 753 754 755 RTThreadUserSignal(hThreadSelf); 756 LogFunc(("Thread ended for pStreamCA=%p fIn=%RTbool: rc=%Rrc (orc=%#x/%d)\n", pStreamCA, fIn, rc, orc, orc)); 757 return rc; 789 758 } 790 759 … … 793 762 * 794 763 * @returns IPRT status code. 795 * @param p CAStreamCore Audio stream to store input data into.764 * @param pStreamCA Core Audio stream to store input data into. 796 765 * @param audioBuffer Audio buffer to process input data from. 797 766 */ 798 static int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM p CAStream, AudioQueueBufferRef audioBuffer)799 { 800 PRTCIRCBUF pCircBuf = p CAStream->pCircBuf;767 static int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer) 768 { 769 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf; 801 770 AssertPtr(pCircBuf); 802 771 … … 818 787 819 788 /* Copy the data from our ring buffer to the core audio buffer. */ 789 /** @todo r=bird: WTF is the (UInt8 *) cast for? Despite the 'pv' prefix, pvDst 790 * is a UInt8 pointer. Whoever wrote this crap needs to check his/her 791 * medication. I shouldn't have to wast my time fixing crap like this! */ 820 792 memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite); 821 793 … … 829 801 } 830 802 831 Log3Func(("p CAStream=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",832 p CAStream, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));803 Log3Func(("pStreamCA=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n", 804 pStreamCA, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten)); 833 805 834 806 return VINF_SUCCESS; … … 839 811 * 840 812 * @param pvUser User argument. 841 * @param audioQueueAudio queue to process input data from.813 * @param hAudioQueue Audio queue to process input data from. 842 814 * @param audioBuffer Audio buffer to process input data from. Must be part of audio queue. 843 815 * @param pAudioTS Audio timestamp. … … 845 817 * @param paPacketDesc Array of packet descriptors. 846 818 */ 847 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,819 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer, 848 820 const AudioTimeStamp *pAudioTS, 849 821 UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc) 850 822 { 851 RT_NOREF( audioQueue,pAudioTS, cPacketDesc, paPacketDesc);852 853 PCOREAUDIOSTREAM p CAStream= (PCOREAUDIOSTREAM)pvUser;854 AssertPtr(p CAStream);855 856 int rc = RTCritSectEnter(&p CAStream->CritSect);823 RT_NOREF(pAudioTS, cPacketDesc, paPacketDesc); 824 825 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser; 826 AssertPtr(pStreamCA); 827 828 int rc = RTCritSectEnter(&pStreamCA->CritSect); 857 829 AssertRC(rc); 858 830 859 rc = coreAudioInputQueueProcBuffer(p CAStream, audioBuffer);831 rc = coreAudioInputQueueProcBuffer(pStreamCA, audioBuffer); 860 832 if (RT_SUCCESS(rc)) 861 AudioQueueEnqueueBuffer( audioQueue, audioBuffer, 0, NULL);862 863 rc = RTCritSectLeave(&p CAStream->CritSect);833 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL); 834 835 rc = RTCritSectLeave(&pStreamCA->CritSect); 864 836 AssertRC(rc); 865 837 } … … 869 841 * 870 842 * @returns IPRT status code. 871 * @param p CAStreamCore Audio stream to process output data for.843 * @param pStreamCA Core Audio stream to process output data for. 872 844 * @param audioBuffer Audio buffer to store data into. 873 845 */ 874 int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM p CAStream, AudioQueueBufferRef audioBuffer)875 { 876 AssertPtr(p CAStream);877 878 PRTCIRCBUF pCircBuf = p CAStream->pCircBuf;846 int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer) 847 { 848 AssertPtr(pStreamCA); 849 850 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf; 879 851 AssertPtr(pCircBuf); 880 852 … … 922 894 } 923 895 924 Log3Func(("p CAStream=%p, cbCapacity=%RU32, cbRead=%zu\n",925 p CAStream, audioBuffer->mAudioDataBytesCapacity, cbRead));896 Log3Func(("pStreamCA=%p, cbCapacity=%RU32, cbRead=%zu\n", 897 pStreamCA, audioBuffer->mAudioDataBytesCapacity, cbRead)); 926 898 927 899 return VINF_SUCCESS; … … 932 904 * 933 905 * @param pvUser User argument. 934 * @param audioQueueAudio queue to process output data for.906 * @param hAudioQueue Audio queue to process output data for. 935 907 * @param audioBuffer Audio buffer to store output data in. Must be part of audio queue. 936 908 */ 937 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer) 938 { 939 RT_NOREF(audioQueue); 940 941 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser; 942 AssertPtr(pCAStream); 943 944 int rc = RTCritSectEnter(&pCAStream->CritSect); 909 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer) 910 { 911 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser; 912 AssertPtr(pStreamCA); 913 914 int rc = RTCritSectEnter(&pStreamCA->CritSect); 945 915 AssertRC(rc); 946 916 947 rc = coreAudioOutputQueueProcBuffer(p CAStream, audioBuffer);917 rc = coreAudioOutputQueueProcBuffer(pStreamCA, audioBuffer); 948 918 if (RT_SUCCESS(rc)) 949 AudioQueueEnqueueBuffer( audioQueue, audioBuffer, 0, NULL);950 951 rc = RTCritSectLeave(&p CAStream->CritSect);919 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL); 920 921 rc = RTCritSectLeave(&pStreamCA->CritSect); 952 922 AssertRC(rc); 953 923 } … … 957 927 * 958 928 * @returns IPRT status code. 959 * @param pCAStream Core Audio stream to invalidate its queue for. 960 */ 961 static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream) 929 * @param pStreamCA Core Audio stream to invalidate its queue for. 930 * 931 * @todo r=bird: Which use of the word 'invalidate' is this? 932 */ 933 static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pStreamCA) 962 934 { 963 935 int rc = VINF_SUCCESS; 964 936 965 Log3Func(("pCAStream=%p\n", pCAStream)); 966 967 for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++) 968 { 969 AudioQueueBufferRef pBuf = pCAStream->audioBuffer[i]; 970 971 if (pCAStream->pCfg->enmDir == PDMAUDIODIR_IN) 972 { 973 int rc2 = coreAudioInputQueueProcBuffer(pCAStream, pBuf); 937 Log3Func(("pStreamCA=%p\n", pStreamCA)); 938 939 for (size_t i = 0; i < RT_ELEMENTS(pStreamCA->apAudioBuffers); i++) 940 { 941 AudioQueueBufferRef pBuf = pStreamCA->apAudioBuffers[i]; 942 if (pStreamCA->Cfg.enmDir == PDMAUDIODIR_IN) 943 { 944 int rc2 = coreAudioInputQueueProcBuffer(pStreamCA, pBuf); 974 945 if (RT_SUCCESS(rc2)) 975 { 976 AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL); 977 } 978 } 979 else if (pCAStream->pCfg->enmDir == PDMAUDIODIR_OUT) 980 { 981 int rc2 = coreAudioOutputQueueProcBuffer(pCAStream, pBuf); 946 AudioQueueEnqueueBuffer(pStreamCA->hAudioQueue, pBuf, 0 /*inNumPacketDescs*/, NULL /*inPacketDescs*/); 947 } 948 else 949 { 950 Assert(pStreamCA->Cfg.enmDir == PDMAUDIODIR_OUT); 951 int rc2 = coreAudioOutputQueueProcBuffer(pStreamCA, pBuf); 982 952 if ( RT_SUCCESS(rc2) 983 953 && pBuf->mAudioDataByteSize) 984 { 985 AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL); 986 } 954 AudioQueueEnqueueBuffer(pStreamCA->hAudioQueue, pBuf, 0 /*inNumPacketDescs*/, NULL /*inPacketDescs*/); 987 955 988 956 if (RT_SUCCESS(rc)) 989 957 rc = rc2; 990 958 } 991 else992 AssertFailed();993 959 } 994 960 … … 1043 1009 static DECLCALLBACK(int) drvHostCoreAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) 1044 1010 { 1045 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);1011 PDRVHOSTCOREAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio); 1046 1012 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER); 1047 1013 … … 1096 1062 /** 1097 1063 * Does a (re-)enumeration of the host's playback + recording devices. 1064 * 1065 * @todo No, it doesn't do playback & recording, it does only what @a enmUsage 1066 * says. 1098 1067 * 1099 1068 * @return IPRT status code. … … 1647 1616 static DECLCALLBACK(int) drvHostCoreAudioHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum) 1648 1617 { 1649 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1618 PDRVHOSTCOREAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio); 1650 1619 AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER); 1651 1620 1652 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface); 1653 1621 PDMAudioHostEnumInit(pDeviceEnum); 1622 1623 /* 1624 * We update the enumeration associated with pThis. 1625 */ 1654 1626 int rc = RTCritSectEnter(&pThis->CritSect); 1655 1627 if (RT_SUCCESS(rc)) … … 1658 1630 if (RT_SUCCESS(rc)) 1659 1631 { 1660 if (pDeviceEnum) 1661 { 1662 /* Return a copy with only PDMAUDIOHOSTDEV, none of the extra bits in COREAUDIODEVICEDATA. */ 1663 PDMAudioHostEnumInit(pDeviceEnum); 1664 rc = PDMAudioHostEnumCopy(pDeviceEnum, &pThis->Devices, PDMAUDIODIR_INVALID /*all*/, true /*fOnlyCoreData*/); 1665 if (RT_FAILURE(rc)) 1666 PDMAudioHostEnumDelete(pDeviceEnum); 1667 } 1668 } 1669 1670 int rc2 = RTCritSectLeave(&pThis->CritSect); 1671 AssertRC(rc2); 1672 } 1673 1674 LogFlowFunc(("Returning %Rrc\n", rc)); 1632 /* 1633 * Return a copy with only PDMAUDIOHOSTDEV and none of the extra 1634 * bits in COREAUDIODEVICEDATA. 1635 */ 1636 rc = PDMAudioHostEnumCopy(pDeviceEnum, &pThis->Devices, PDMAUDIODIR_INVALID /*all*/, true /*fOnlyCoreData*/); 1637 if (RT_FAILURE(rc)) 1638 PDMAudioHostEnumDelete(pDeviceEnum); 1639 } 1640 1641 RTCritSectLeave(&pThis->CritSect); 1642 } 1643 1644 LogFlowFunc(("returns %Rrc\n", rc)); 1675 1645 return rc; 1676 1646 } … … 1683 1653 { 1684 1654 RT_NOREF(pInterface, enmDir); 1685 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);1686 1687 1655 return PDMAUDIOBACKENDSTS_RUNNING; 1688 1656 } … … 1690 1658 1691 1659 /** 1692 * Initializes a Core Audio stream's audio queue. 1693 * 1694 * @returns IPRT status code. 1695 * @param pCAStream Core Audio stream to initialize audio queue for. 1696 * @param pCfgReq Requested stream configuration. 1697 * @param pCfgAcq Acquired stream configuration on success. 1698 */ 1699 static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1700 { 1701 RT_NOREF(pCfgAcq); 1702 1703 LogFunc(("pCAStream=%p, pCfgReq=%p, pCfgAcq=%p\n", pCAStream, pCfgReq, pCfgAcq)); 1704 1705 /* No device assigned? Bail out early. */ 1706 if (pCAStream->Unit.pDevice == NULL) 1707 return VERR_NOT_AVAILABLE; 1708 1709 const bool fIn = pCfgReq->enmDir == PDMAUDIODIR_IN; 1710 1711 int rc = VINF_SUCCESS; 1712 1713 if (fIn) 1660 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 1661 */ 1662 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1663 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1664 { 1665 PDRVHOSTCOREAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio); 1666 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 1667 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 1668 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 1669 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 1670 AssertReturn(pCfgReq->enmDir == PDMAUDIODIR_IN || pCfgReq->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER); 1671 int rc; 1672 1673 /* 1674 * Permission check for input devices before we start. 1675 */ 1676 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 1714 1677 { 1715 1678 rc = coreAudioInputPermissionCheck(); … … 1718 1681 } 1719 1682 1720 /* Create the recording device's out format based on our required audio settings. */1721 Assert(pCAStream->pCfg == NULL);1722 pCAStream->pCfg = PDMAudioStrmCfgDup(pCfgReq);1723 if (!pCAStream->pCfg)1724 rc = VERR_NO_MEMORY;1725 1726 coreAudioPCMPropsToASBD(&pCfgReq->Props, &pCAStream->asbdStream);1727 /** @todo Do some validation? */1728 1729 coreAudioPrintASBD( fIn1730 ? "Capturing queue format"1731 : "Playback queue format", &pCAStream->asbdStream);1732 1733 if (RT_FAILURE(rc))1734 {1735 LogRel(("CoreAudio: Failed to convert requested %s format to native format (%Rrc)\n", fIn ? "input" : "output", rc));1736 return rc;1737 }1738 1739 rc = RTCircBufCreate(&pCAStream->pCircBuf, PDMAUDIOSTREAMCFG_F2B(pCfgReq, pCfgReq->Backend.cFramesBufferSize));1740 if (RT_FAILURE(rc))1741 return rc;1742 1743 1683 /* 1744 * Start the thread.1684 * Do we have a device for the requested stream direction? 1745 1685 */ 1746 rc = RTThreadCreate(&pCAStream->hThread, coreAudioQueueThread, 1747 pCAStream /* pvUser */, 0 /* Default stack size */, 1748 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CAQUEUE"); 1749 if (RT_SUCCESS(rc)) 1750 rc = RTThreadUserWait(pCAStream->hThread, 10 * 1000 /* 10s timeout */); 1751 1752 LogFunc(("Returning %Rrc\n", rc)); 1753 return rc; 1754 } 1755 1756 1757 /** 1758 * Initializes a Core Audio stream. 1759 * 1760 * @return IPRT status code. 1761 * @param pThis Driver instance. 1762 * @param pCAStream Stream to initialize. 1763 * @param pDev Audio device to use for this stream. 1764 */ 1765 static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev) 1766 { 1767 AssertPtrReturn(pCAStream, VERR_INVALID_POINTER); 1768 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1769 AssertPtrReturn(pDev, VERR_INVALID_POINTER); 1770 1771 Assert(pCAStream->Unit.pDevice == NULL); /* Make sure no device is assigned yet. */ 1772 Assert(pDev->Core.cbSelf == sizeof(COREAUDIODEVICEDATA)); 1773 1774 LogFunc(("pCAStream=%p, pDev=%p ('%s', ID=%RU32)\n", pCAStream, pDev, pDev->Core.szName, pDev->deviceID)); 1775 1776 pCAStream->Unit.pDevice = pDev; 1777 pCAStream->pDrv = pThis; 1778 1779 return VINF_SUCCESS; 1780 } 1781 1782 1783 /** 1784 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 1785 */ 1786 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1787 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 1788 { 1789 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 1790 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1791 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 1792 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 1793 1794 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface); 1795 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream; 1796 1797 int rc = RTCritSectInit(&pCAStream->CritSect); 1798 if (RT_FAILURE(rc)) 1799 return rc; 1800 1801 pCAStream->hThread = NIL_RTTHREAD; 1802 pCAStream->fRun = false; 1803 pCAStream->fIsRunning = false; 1804 pCAStream->fShutdown = false; 1805 1806 /* Input or output device? */ 1807 bool fIn = pCfgReq->enmDir == PDMAUDIODIR_IN; 1808 1809 /* For now, just use the default device available. */ 1810 PCOREAUDIODEVICEDATA pDev = fIn ? pThis->pDefaultDevIn : pThis->pDefaultDevOut; 1811 1812 LogFunc(("pStream=%p, pCfgReq=%p, pCfgAcq=%p, fIn=%RTbool, pDev=%p\n", pStream, pCfgReq, pCfgAcq, fIn, pDev)); 1813 1814 if (pDev) /* (Default) device available? */ 1815 { 1816 /* Sanity. */ 1686 PCOREAUDIODEVICEDATA pDev = pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->pDefaultDevIn : pThis->pDefaultDevOut; 1687 #ifdef LOG_ENABLED 1688 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX]; 1689 #endif 1690 LogFunc(("pDev=%p *pCfgReq: %s\n", pDev, PDMAudioStrmCfgToString(pCfgReq, szTmp, sizeof(szTmp)) )); 1691 if (pDev) 1692 { 1817 1693 Assert(pDev->Core.cbSelf == sizeof(*pDev)); 1818 1694 1819 /* Init the Core Audio stream. */ 1820 rc = coreAudioStreamInit(pCAStream, pThis, pDev); 1695 /* 1696 * Basic structure init. 1697 */ 1698 pStreamCA->pDrv = pThis; 1699 pStreamCA->hThread = NIL_RTTHREAD; 1700 pStreamCA->fRun = false; 1701 pStreamCA->fIsRunning = false; 1702 pStreamCA->fShutdown = false; 1703 pStreamCA->Unit.pDevice = pDev; /** @todo r=bird: How do we protect this against enumeration releasing pDefaultDevOut/In. */ 1704 pStreamCA->enmInitState = COREAUDIOINITSTATE_IN_INIT; 1705 1706 rc = RTCritSectInit(&pStreamCA->CritSect); 1821 1707 if (RT_SUCCESS(rc)) 1822 1708 { 1823 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_INIT); 1824 1825 rc = coreAudioStreamInitQueue(pCAStream, pCfgReq, pCfgAcq); 1709 /* 1710 * Do format conversion and create the circular buffer we use to shuffle 1711 * data to/from the queue thread. 1712 */ 1713 PDMAudioStrmCfgCopy(&pStreamCA->Cfg, pCfgReq); 1714 coreAudioPCMPropsToASBD(&pCfgReq->Props, &pStreamCA->asbdStream); 1715 /** @todo Do some validation? */ 1716 coreAudioPrintASBD( pCfgReq->enmDir == PDMAUDIODIR_IN 1717 ? "Capturing queue format" 1718 : "Playback queue format", &pStreamCA->asbdStream); 1719 1720 rc = RTCircBufCreate(&pStreamCA->pCircBuf, 1721 PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize)); 1826 1722 if (RT_SUCCESS(rc)) 1827 1723 { 1828 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_INIT); 1724 /* 1725 * Start the thread. 1726 */ 1727 static uint32_t volatile s_idxThread = 0; 1728 uint32_t idxThread = ASMAtomicIncU32(&s_idxThread); 1729 1730 rc = RTThreadCreateF(&pStreamCA->hThread, coreAudioQueueThread, pStreamCA, 0 /*cbStack*/, 1731 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "CaQue%u", idxThread); 1732 if (RT_SUCCESS(rc)) 1733 { 1734 rc = RTThreadUserWait(pStreamCA->hThread, RT_MS_10SEC); 1735 AssertRC(rc); 1736 if (RT_SUCCESS(rc) && pStreamCA->hRunLoop != NULL) 1737 { 1738 ASMAtomicWriteU32(&pStreamCA->enmInitState, COREAUDIOINITSTATE_INIT); 1739 1740 LogFunc(("returns VINF_SUCCESS\n")); 1741 return VINF_SUCCESS; 1742 } 1743 1744 /* 1745 * Failed, clean up. 1746 */ 1747 LogRel(("CoreAudio: Thread failed to initialize in a timely manner (%Rrc).\n", rc)); 1748 1749 ASMAtomicWriteBool(&pStreamCA->fShutdown, true); 1750 RTThreadPoke(pStreamCA->hThread); 1751 int rcThread = 0; 1752 rc = RTThreadWait(pStreamCA->hThread, RT_MS_15SEC, NULL); 1753 AssertLogRelRC(rc); 1754 LogRel(("CoreAudio: Thread exit code: %Rrc / %Rrc.\n", rc, rcThread)); 1755 pStreamCA->hThread = NIL_RTTHREAD; 1756 } 1757 else 1758 LogRel(("CoreAudio: Failed to create queue thread for stream: %Rrc\n", rc)); 1759 RTCircBufDestroy(pStreamCA->pCircBuf); 1760 pStreamCA->pCircBuf = NULL; 1829 1761 } 1830 1762 else 1763 LogRel(("CoreAudio: Failed to allocate stream buffer: %Rrc\n", rc)); 1764 RTCritSectDelete(&pStreamCA->CritSect); 1765 } 1766 else 1767 LogRel(("CoreAudio: Failed to initialize critical section for stream: %Rrc\n", rc)); 1768 } 1769 else 1770 { 1771 LogFunc(("No device for stream.\n")); 1772 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1773 } 1774 1775 LogFunc(("returns %Rrc\n", rc)); 1776 return rc; 1777 } 1778 1779 1780 /** 1781 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 1782 */ 1783 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1784 { 1785 RT_NOREF(pInterface); 1786 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 1787 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 1788 1789 /* 1790 * Never mind if the status isn't INIT (it should always be, though). 1791 */ 1792 COREAUDIOINITSTATE const enmInitState = (COREAUDIOINITSTATE)ASMAtomicReadU32(&pStreamCA->enmInitState); 1793 AssertMsg(enmInitState == COREAUDIOINITSTATE_INIT, ("%d\n", enmInitState)); 1794 if (enmInitState == COREAUDIOINITSTATE_INIT) 1795 { 1796 Assert(RTCritSectIsInitialized(&pStreamCA->CritSect)); 1797 1798 /* 1799 * Disable (stop) the stream just in case it's running. 1800 */ 1801 /** @todo this isn't paranoid enough, the pStreamCA->hAudioQueue is 1802 * owned+released by the queue thread. */ 1803 drvHostCoreAudioStreamControlInternal(pStreamCA, PDMAUDIOSTREAMCMD_DISABLE); 1804 1805 /* 1806 * Change the state (cannot do before the stop). 1807 * Enter and leave the critsect afterwards for paranoid reasons. 1808 */ 1809 ASMAtomicWriteU32(&pStreamCA->enmInitState, COREAUDIOINITSTATE_IN_UNINIT); 1810 RTCritSectEnter(&pStreamCA->CritSect); 1811 RTCritSectLeave(&pStreamCA->CritSect); 1812 1813 /* 1814 * Bring down the queue thread. 1815 */ 1816 if (pStreamCA->hThread != NIL_RTTHREAD) 1817 { 1818 LogFunc(("Waiting for thread ...\n")); 1819 ASMAtomicXchgBool(&pStreamCA->fShutdown, true); 1820 int rcThread = VERR_IPE_UNINITIALIZED_STATUS; 1821 int rc = VERR_TIMEOUT; 1822 for (uint32_t iWait = 0; rc == VERR_TIMEOUT && iWait < 60; iWait++) 1831 1823 { 1832 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_UNINIT); 1833 1834 int rc2 = coreAudioStreamUninit(pCAStream); 1835 AssertRC(rc2); 1836 1837 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_UNINIT); 1824 LogFunc(("%u ...\n", iWait)); 1825 if (pStreamCA->hRunLoop != NULL) 1826 CFRunLoopStop(pStreamCA->hRunLoop); 1827 if (iWait >= 10) 1828 RTThreadPoke(pStreamCA->hThread); 1829 1830 rcThread = VERR_IPE_UNINITIALIZED_STATUS; 1831 rc = RTThreadWait(pStreamCA->hThread, RT_MS_1SEC / 2, &rcThread); 1838 1832 } 1839 } 1840 } 1841 else 1842 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1843 1844 LogFunc(("Returning %Rrc\n", rc)); 1845 return rc; 1846 } 1847 1848 1849 static int coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd) 1850 { 1851 RT_NOREF(pThis); 1852 1853 uint32_t enmStatus = ASMAtomicReadU32(&pCAStream->enmStatus); 1854 1855 LogFlowFunc(("enmStreamCmd=%RU32, enmStatus=%RU32\n", enmStreamCmd, enmStatus)); 1856 1857 if (enmStatus != COREAUDIOSTATUS_INIT) 1833 AssertLogRelRC(rc); 1834 LogFunc(("Thread stopped with: %Rrc/%Rrc\n", rc, rcThread)); 1835 pStreamCA->hThread = NIL_RTTHREAD; 1836 } 1837 1838 if (pStreamCA->hRunLoop != NULL) 1839 { 1840 CFRelease(pStreamCA->hRunLoop); 1841 pStreamCA->hRunLoop = NULL; 1842 } 1843 1844 /* 1845 * Kill the circular buffer and NULL essential variable. 1846 */ 1847 if (pStreamCA->pCircBuf) 1848 { 1849 RTCircBufDestroy(pStreamCA->pCircBuf); 1850 pStreamCA->pCircBuf = NULL; 1851 } 1852 1853 pStreamCA->Unit.pDevice = NULL; 1854 pStreamCA->pDrv = NULL; 1855 1856 RTCritSectDelete(&pStreamCA->CritSect); 1857 1858 /* 1859 * Done. 1860 */ 1861 ASMAtomicWriteU32(&pStreamCA->enmInitState, COREAUDIOINITSTATE_UNINIT); 1862 } 1863 1864 LogFunc(("returns\n")); 1865 return VINF_SUCCESS; 1866 } 1867 1868 1869 static int drvHostCoreAudioStreamControlInternal(PCOREAUDIOSTREAM pStreamCA, PDMAUDIOSTREAMCMD enmStreamCmd) 1870 { 1871 uint32_t enmInitState = ASMAtomicReadU32(&pStreamCA->enmInitState); 1872 1873 LogFlowFunc(("enmStreamCmd=%RU32, enmInitState=%RU32\n", enmStreamCmd, enmInitState)); 1874 1875 if (enmInitState != COREAUDIOINITSTATE_INIT) 1858 1876 { 1859 1877 return VINF_SUCCESS; 1860 1878 } 1861 1879 1862 if (!pCAStream->pCfg) /* Not (yet) configured? Skip. */1863 return VINF_SUCCESS;1864 1865 1880 int rc = VINF_SUCCESS; 1866 1867 1881 switch (enmStreamCmd) 1868 1882 { … … 1871 1885 { 1872 1886 LogFunc(("Queue enable\n")); 1873 if (p CAStream->pCfg->enmDir == PDMAUDIODIR_IN)1887 if (pStreamCA->Cfg.enmDir == PDMAUDIODIR_IN) 1874 1888 { 1875 rc = coreAudioStreamInvalidateQueue(p CAStream);1889 rc = coreAudioStreamInvalidateQueue(pStreamCA); 1876 1890 if (RT_SUCCESS(rc)) 1877 1891 { 1878 1892 /* Start the audio queue immediately. */ 1879 AudioQueueStart(p CAStream->audioQueue, NULL);1893 AudioQueueStart(pStreamCA->hAudioQueue, NULL); 1880 1894 } 1881 1895 } 1882 else if (p CAStream->pCfg->enmDir == PDMAUDIODIR_OUT)1896 else if (pStreamCA->Cfg.enmDir == PDMAUDIODIR_OUT) 1883 1897 { 1884 1898 /* Touch the run flag to start the audio queue as soon as 1885 1899 * we have anough data to actually play something. */ 1886 ASMAtomicXchgBool(&p CAStream->fRun, true);1900 ASMAtomicXchgBool(&pStreamCA->fRun, true); 1887 1901 } 1888 1902 break; … … 1892 1906 { 1893 1907 LogFunc(("Queue disable\n")); 1894 AudioQueueStop(p CAStream->audioQueue, 1 /* Immediately */);1895 ASMAtomicXchgBool(&p CAStream->fRun, false);1896 ASMAtomicXchgBool(&p CAStream->fIsRunning, false);1908 AudioQueueStop(pStreamCA->hAudioQueue, 1 /* Immediately */); 1909 ASMAtomicXchgBool(&pStreamCA->fRun, false); 1910 ASMAtomicXchgBool(&pStreamCA->fIsRunning, false); 1897 1911 break; 1898 1912 } … … 1900 1914 { 1901 1915 LogFunc(("Queue pause\n")); 1902 AudioQueuePause(p CAStream->audioQueue);1903 ASMAtomicXchgBool(&p CAStream->fIsRunning, false);1916 AudioQueuePause(pStreamCA->hAudioQueue); 1917 ASMAtomicXchgBool(&pStreamCA->fIsRunning, false); 1904 1918 break; 1905 1919 } … … 1916 1930 1917 1931 /** 1918 * Unitializes a Core Audio stream's audio queue.1919 *1920 * @returns IPRT status code.1921 * @param pCAStream Core Audio stream to unitialize audio queue for.1922 */1923 static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)1924 {1925 LogFunc(("pCAStream=%p\n", pCAStream));1926 1927 if (pCAStream->hThread != NIL_RTTHREAD)1928 {1929 LogFunc(("Waiting for thread ...\n"));1930 1931 ASMAtomicXchgBool(&pCAStream->fShutdown, true);1932 1933 int rcThread;1934 int rc = RTThreadWait(pCAStream->hThread, 30 * 1000, &rcThread);1935 if (RT_FAILURE(rc))1936 return rc;1937 1938 RT_NOREF(rcThread);1939 LogFunc(("Thread stopped with %Rrc\n", rcThread));1940 1941 pCAStream->hThread = NIL_RTTHREAD;1942 }1943 1944 if (pCAStream->pCfg)1945 {1946 PDMAudioStrmCfgFree(pCAStream->pCfg);1947 pCAStream->pCfg = NULL;1948 }1949 1950 if (pCAStream->pCircBuf)1951 {1952 RTCircBufDestroy(pCAStream->pCircBuf);1953 pCAStream->pCircBuf = NULL;1954 }1955 1956 LogFunc(("Returning\n"));1957 return VINF_SUCCESS;1958 }1959 1960 1961 /**1962 * Unitializes a Core Audio stream.1963 *1964 * @returns IPRT status code.1965 * @param pCAStream Core Audio stream to uninitialize.1966 */1967 static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)1968 {1969 LogFunc(("pCAStream=%p\n", pCAStream));1970 1971 int rc = coreAudioStreamUninitQueue(pCAStream);1972 if (RT_SUCCESS(rc))1973 {1974 pCAStream->Unit.pDevice = NULL;1975 pCAStream->pDrv = NULL;1976 }1977 1978 return rc;1979 }1980 1981 1982 /**1983 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}1984 */1985 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)1986 {1987 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);1988 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1989 1990 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);1991 1992 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream;1993 1994 uint32_t status = ASMAtomicReadU32(&pCAStream->enmStatus);1995 if (status != COREAUDIOSTATUS_INIT)1996 {1997 return VINF_SUCCESS;1998 }1999 2000 if (!pCAStream->pCfg) /* Not (yet) configured? Skip. */2001 return VINF_SUCCESS;2002 2003 int rc = coreAudioStreamControl(pThis, pCAStream, PDMAUDIOSTREAMCMD_DISABLE);2004 if (RT_SUCCESS(rc))2005 {2006 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_UNINIT);2007 2008 rc = coreAudioStreamUninit(pCAStream);2009 2010 if (RT_SUCCESS(rc))2011 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_UNINIT);2012 }2013 2014 if (RT_SUCCESS(rc))2015 {2016 if (RTCritSectIsInitialized(&pCAStream->CritSect))2017 RTCritSectDelete(&pCAStream->CritSect);2018 }2019 2020 LogFunc(("rc=%Rrc\n", rc));2021 return rc;2022 }2023 2024 2025 /**2026 1932 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} 2027 1933 */ 2028 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, 2029 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) 2030 { 2031 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2032 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2033 2034 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface); 2035 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream; 2036 2037 return coreAudioStreamControl(pThis, pCAStream, enmStreamCmd); 1934 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1935 PDMAUDIOSTREAMCMD enmStreamCmd) 1936 { 1937 RT_NOREF(pInterface); 1938 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 1939 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 1940 1941 return drvHostCoreAudioStreamControlInternal(pStreamCA, enmStreamCmd); 2038 1942 } 2039 1943 … … 2045 1949 { 2046 1950 RT_NOREF(pInterface); 2047 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2048 2049 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream; 2050 2051 if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT) 1951 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 1952 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 1953 1954 if (ASMAtomicReadU32(&pStreamCA->enmInitState) != COREAUDIOINITSTATE_INIT) 2052 1955 return 0; 2053 1956 2054 AssertPtr(pCAStream->pCfg); 2055 AssertPtr(pCAStream->pCircBuf); 2056 2057 switch (pCAStream->pCfg->enmDir) 2058 { 2059 case PDMAUDIODIR_IN: 2060 return (uint32_t)RTCircBufUsed(pCAStream->pCircBuf); 2061 2062 case PDMAUDIODIR_OUT: 2063 default: 2064 AssertFailed(); 2065 break; 2066 } 2067 1957 if (pStreamCA->Cfg.enmDir == PDMAUDIODIR_IN) 1958 { 1959 AssertPtr(pStreamCA->pCircBuf); 1960 return (uint32_t)RTCircBufUsed(pStreamCA->pCircBuf); 1961 } 1962 AssertFailed(); 2068 1963 return 0; 2069 1964 } … … 2076 1971 { 2077 1972 RT_NOREF(pInterface); 2078 AssertPtrReturn(pStream, VERR_INVALID_POINTER);2079 2080 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream; 1973 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 1974 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 1975 2081 1976 2082 1977 uint32_t cbWritable = 0; 2083 2084 if (ASMAtomicReadU32(&pCAStream->enmStatus) == COREAUDIOSTATUS_INIT) 2085 { 2086 AssertPtr(pCAStream->pCfg); 2087 AssertPtr(pCAStream->pCircBuf); 2088 2089 switch (pCAStream->pCfg->enmDir) 2090 { 2091 case PDMAUDIODIR_OUT: 2092 cbWritable = (uint32_t)RTCircBufFree(pCAStream->pCircBuf); 2093 break; 2094 2095 default: 2096 break; 2097 } 1978 if (ASMAtomicReadU32(&pStreamCA->enmInitState) == COREAUDIOINITSTATE_INIT) 1979 { 1980 AssertPtr(pStreamCA->pCircBuf); 1981 1982 if (pStreamCA->Cfg.enmDir == PDMAUDIODIR_OUT) 1983 cbWritable = (uint32_t)RTCircBufFree(pStreamCA->pCircBuf); 2098 1984 } 2099 1985 … … 2113 1999 AssertPtrReturn(pStreamCa, PDMHOSTAUDIOSTREAMSTATE_INVALID); 2114 2000 2115 if (pStreamCa->pCfg) /* Configured? */ 2116 { 2117 if (ASMAtomicReadU32(&pStreamCa->enmStatus) == COREAUDIOSTATUS_INIT) 2118 return PDMHOSTAUDIOSTREAMSTATE_OKAY; 2119 } 2120 2001 if (ASMAtomicReadU32(&pStreamCa->enmInitState) == COREAUDIOINITSTATE_INIT) 2002 return PDMHOSTAUDIOSTREAMSTATE_OKAY; 2121 2003 return PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING; /** @todo ?? */ 2122 2004 } … … 2128 2010 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 2129 2011 { 2130 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);2131 PCOREAUDIOSTREAM p CAStream= (PCOREAUDIOSTREAM)pStream;2012 PDRVHOSTCOREAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio); 2013 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 2132 2014 2133 2015 RT_NOREF(pThis); 2134 2016 2135 if (ASMAtomicReadU32(&p CAStream->enmStatus) != COREAUDIOSTATUS_INIT)2017 if (ASMAtomicReadU32(&pStreamCA->enmInitState) != COREAUDIOINITSTATE_INIT) 2136 2018 { 2137 2019 *pcbWritten = 0; … … 2139 2021 } 2140 2022 2023 int rc = RTCritSectEnter(&pStreamCA->CritSect); 2024 AssertRCReturn(rc, rc); 2025 2026 size_t cbToWrite = RT_MIN(cbBuf, RTCircBufFree(pStreamCA->pCircBuf)); 2027 Log3Func(("cbToWrite=%zu\n", cbToWrite)); 2028 2141 2029 uint32_t cbWrittenTotal = 0; 2142 2143 int rc = VINF_SUCCESS; 2144 2145 rc = RTCritSectEnter(&pCAStream->CritSect); 2146 AssertRC(rc); 2147 2148 size_t cbToWrite = RT_MIN(cbBuf, RTCircBufFree(pCAStream->pCircBuf)); 2149 Log3Func(("cbToWrite=%zu\n", cbToWrite)); 2150 2151 uint8_t *pvChunk; 2152 size_t cbChunk; 2153 2154 while (cbToWrite) 2030 while (cbToWrite > 0) 2155 2031 { 2156 2032 /* Try to acquire the necessary space from the ring buffer. */ 2157 RTCircBufAcquireWriteBlock(pCAStream->pCircBuf, cbToWrite, (void **)&pvChunk, &cbChunk); 2158 if (!cbChunk) 2159 { 2160 RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbChunk); 2161 break; 2162 } 2033 void *pvChunk = NULL; 2034 size_t cbChunk = 0; 2035 RTCircBufAcquireWriteBlock(pStreamCA->pCircBuf, cbToWrite, &pvChunk, &cbChunk); 2036 AssertBreakStmt(cbChunk > 0, RTCircBufReleaseWriteBlock(pStreamCA->pCircBuf, cbChunk)); 2163 2037 2164 2038 Assert(cbChunk <= cbToWrite); … … 2181 2055 2182 2056 /* Release the ring buffer, so the read thread could start reading this data. */ 2183 RTCircBufReleaseWriteBlock(p CAStream->pCircBuf, cbChunk);2057 RTCircBufReleaseWriteBlock(pStreamCA->pCircBuf, cbChunk); 2184 2058 2185 2059 if (RT_FAILURE(rc)) … … 2193 2067 2194 2068 if ( RT_SUCCESS(rc) 2195 && p CAStream->fRun2196 && !p CAStream->fIsRunning)2197 { 2198 rc = coreAudioStreamInvalidateQueue(p CAStream);2069 && pStreamCA->fRun 2070 && !pStreamCA->fIsRunning) 2071 { 2072 rc = coreAudioStreamInvalidateQueue(pStreamCA); 2199 2073 if (RT_SUCCESS(rc)) 2200 2074 { 2201 AudioQueueStart(p CAStream->audioQueue, NULL);2202 p CAStream->fRun = false;2203 p CAStream->fIsRunning = true;2204 } 2205 } 2206 2207 int rc2 = RTCritSectLeave(&p CAStream->CritSect);2075 AudioQueueStart(pStreamCA->hAudioQueue, NULL); 2076 pStreamCA->fRun = false; 2077 pStreamCA->fIsRunning = true; 2078 } 2079 } 2080 2081 int rc2 = RTCritSectLeave(&pStreamCA->CritSect); 2208 2082 AssertRC(rc2); 2209 2083 2210 if (RT_SUCCESS(rc)) 2211 *pcbWritten = cbWrittenTotal; 2212 2084 *pcbWritten = cbWrittenTotal; 2213 2085 return rc; 2214 2086 } … … 2221 2093 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 2222 2094 { 2223 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 2224 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2095 RT_NOREF(pInterface); 2096 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pStream; 2097 AssertPtrReturn(pStreamCA, VERR_INVALID_POINTER); 2225 2098 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER); 2226 2099 2227 PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream; 2228 PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface); 2229 2230 RT_NOREF(pThis); 2231 2232 if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT) 2100 2101 if (ASMAtomicReadU32(&pStreamCA->enmInitState) != COREAUDIOINITSTATE_INIT) 2233 2102 { 2234 2103 *pcbRead = 0; … … 2236 2105 } 2237 2106 2238 int rc = RTCritSectEnter(&p CAStream->CritSect);2107 int rc = RTCritSectEnter(&pStreamCA->CritSect); 2239 2108 AssertRCReturn(rc, rc); 2240 2109 2241 size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(p CAStream->pCircBuf));2242 Log3Func(("cbToWrite=%zu/%zu\n", cbToWrite, RTCircBufSize(p CAStream->pCircBuf)));2110 size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pStreamCA->pCircBuf)); 2111 Log3Func(("cbToWrite=%zu/%zu\n", cbToWrite, RTCircBufSize(pStreamCA->pCircBuf))); 2243 2112 2244 2113 uint32_t cbReadTotal = 0; … … 2247 2116 void *pvChunk = NULL; 2248 2117 size_t cbChunk = 0; 2249 RTCircBufAcquireReadBlock(p CAStream->pCircBuf, cbToWrite, &pvChunk, &cbChunk);2118 RTCircBufAcquireReadBlock(pStreamCA->pCircBuf, cbToWrite, &pvChunk, &cbChunk); 2250 2119 2251 2120 AssertStmt(cbChunk <= cbToWrite, cbChunk = cbToWrite); 2252 2121 memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk); 2253 2122 2254 RTCircBufReleaseReadBlock(p CAStream->pCircBuf, cbChunk);2123 RTCircBufReleaseReadBlock(pStreamCA->pCircBuf, cbChunk); 2255 2124 2256 2125 cbToWrite -= cbChunk; … … 2260 2129 *pcbRead = cbReadTotal; 2261 2130 2262 RTCritSectLeave(&p CAStream->CritSect);2131 RTCritSectLeave(&pStreamCA->CritSect); 2263 2132 return VINF_SUCCESS; 2264 2133 }
Note:
See TracChangeset
for help on using the changeset viewer.