@@ -1741,7 +1741,7 @@ static OSStatus BlackHole_GetDevicePropertyDataSize(AudioServerPlugInDriverRef i
1741
1741
break ;
1742
1742
1743
1743
case kAudioDevicePropertyPreferredChannelLayout :
1744
- * outDataSize = offsetof(AudioChannelLayout , mChannelDescriptions ) + (2 * sizeof (AudioChannelDescription ));
1744
+ * outDataSize = offsetof(AudioChannelLayout , mChannelDescriptions ) + (NUMBER_OF_CHANNELS * sizeof (AudioChannelDescription ));
1745
1745
break ;
1746
1746
1747
1747
case kAudioDevicePropertyZeroTimeStampPeriod :
@@ -2170,12 +2170,12 @@ static OSStatus BlackHole_GetDevicePropertyData(AudioServerPlugInDriverRef inDri
2170
2170
// by default. For this device, we return a stereo ACL.
2171
2171
{
2172
2172
// calcualte how big the
2173
- UInt32 theACLSize = offsetof(AudioChannelLayout , mChannelDescriptions ) + (2 * sizeof (AudioChannelDescription ));
2173
+ UInt32 theACLSize = offsetof(AudioChannelLayout , mChannelDescriptions ) + (NUMBER_OF_CHANNELS * sizeof (AudioChannelDescription ));
2174
2174
FailWithAction (inDataSize < theACLSize , theAnswer = kAudioHardwareBadPropertySizeError , Done , "BlackHole_GetDevicePropertyData: not enough space for the return value of kAudioDevicePropertyPreferredChannelLayout for the device" );
2175
2175
((AudioChannelLayout * )outData )-> mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions ;
2176
2176
((AudioChannelLayout * )outData )-> mChannelBitmap = 0 ;
2177
- ((AudioChannelLayout * )outData )-> mNumberChannelDescriptions = 2 ;
2178
- for (theItemIndex = 0 ; theItemIndex < 2 ; ++ theItemIndex )
2177
+ ((AudioChannelLayout * )outData )-> mNumberChannelDescriptions = NUMBER_OF_CHANNELS ;
2178
+ for (theItemIndex = 0 ; theItemIndex < NUMBER_OF_CHANNELS ; ++ theItemIndex )
2179
2179
{
2180
2180
((AudioChannelLayout * )outData )-> mChannelDescriptions [theItemIndex ].mChannelLabel = kAudioChannelLabel_Left + theItemIndex ;
2181
2181
((AudioChannelLayout * )outData )-> mChannelDescriptions [theItemIndex ].mChannelFlags = 0 ;
@@ -2538,14 +2538,14 @@ static OSStatus BlackHole_GetStreamPropertyData(AudioServerPlugInDriverRef inDri
2538
2538
// format has to be the same as the physical format.
2539
2539
FailWithAction (inDataSize < sizeof (AudioStreamBasicDescription ), theAnswer = kAudioHardwareBadPropertySizeError , Done , "BlackHole_GetStreamPropertyData: not enough space for the return value of kAudioStreamPropertyVirtualFormat for the stream" );
2540
2540
pthread_mutex_lock (& gPlugIn_StateMutex );
2541
- ((AudioStreamBasicDescription * )outData )-> mSampleRate = gDevice_SampleRate ;
2542
- ((AudioStreamBasicDescription * )outData )-> mFormatID = kAudioFormatLinearPCM ;
2543
- ((AudioStreamBasicDescription * )outData )-> mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked ;
2544
- ((AudioStreamBasicDescription * )outData )-> mBytesPerPacket = BYTES_PER_CHANNEL * NUMBER_OF_CHANNELS ;
2545
- ((AudioStreamBasicDescription * )outData )-> mFramesPerPacket = 1 ;
2546
- ((AudioStreamBasicDescription * )outData )-> mBytesPerFrame = BYTES_PER_CHANNEL * NUMBER_OF_CHANNELS ;
2547
- ((AudioStreamBasicDescription * )outData )-> mChannelsPerFrame = NUMBER_OF_CHANNELS ;
2548
- ((AudioStreamBasicDescription * )outData )-> mBitsPerChannel = BITS_PER_CHANNEL ;
2541
+ ((AudioStreamBasicDescription * )outData )-> mSampleRate = gDevice_SampleRate ;
2542
+ ((AudioStreamBasicDescription * )outData )-> mFormatID = kAudioFormatLinearPCM ;
2543
+ ((AudioStreamBasicDescription * )outData )-> mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked ;
2544
+ ((AudioStreamBasicDescription * )outData )-> mBytesPerPacket = BYTES_PER_CHANNEL * NUMBER_OF_CHANNELS ;
2545
+ ((AudioStreamBasicDescription * )outData )-> mFramesPerPacket = 1 ;
2546
+ ((AudioStreamBasicDescription * )outData )-> mBytesPerFrame = BYTES_PER_CHANNEL * NUMBER_OF_CHANNELS ;
2547
+ ((AudioStreamBasicDescription * )outData )-> mChannelsPerFrame = NUMBER_OF_CHANNELS ;
2548
+ ((AudioStreamBasicDescription * )outData )-> mBitsPerChannel = BITS_PER_CHANNEL ;
2549
2549
pthread_mutex_unlock (& gPlugIn_StateMutex );
2550
2550
* outDataSize = sizeof (AudioStreamBasicDescription );
2551
2551
break ;
@@ -2569,16 +2569,16 @@ static OSStatus BlackHole_GetStreamPropertyData(AudioServerPlugInDriverRef inDri
2569
2569
// fill out the return array
2570
2570
if (theNumberItemsToFetch > 0 )
2571
2571
{
2572
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mSampleRate = 44100.0 ;
2573
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFormatID = kAudioFormatLinearPCM ;
2574
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked ;
2572
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mSampleRate = 44100.0 ;
2573
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFormatID = kAudioFormatLinearPCM ;
2574
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked ;
2575
2575
((AudioStreamRangedDescription * )outData )[0 ].mFormat .mBytesPerPacket = BYTES_PER_FRAME ;
2576
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFramesPerPacket = 1 ;
2577
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mBytesPerFrame = BYTES_PER_FRAME ;
2578
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mChannelsPerFrame = NUMBER_OF_CHANNELS ;
2579
- ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mBitsPerChannel = BITS_PER_CHANNEL ;
2580
- ((AudioStreamRangedDescription * )outData )[0 ].mSampleRateRange .mMinimum = 44100.0 ;
2581
- ((AudioStreamRangedDescription * )outData )[0 ].mSampleRateRange .mMaximum = 44100.0 ;
2576
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mFramesPerPacket = 1 ;
2577
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mBytesPerFrame = BYTES_PER_FRAME ;
2578
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mChannelsPerFrame = NUMBER_OF_CHANNELS ;
2579
+ ((AudioStreamRangedDescription * )outData )[0 ].mFormat .mBitsPerChannel = BITS_PER_CHANNEL ;
2580
+ ((AudioStreamRangedDescription * )outData )[0 ].mSampleRateRange .mMinimum = 44100.0 ;
2581
+ ((AudioStreamRangedDescription * )outData )[0 ].mSampleRateRange .mMaximum = 44100.0 ;
2582
2582
}
2583
2583
if (theNumberItemsToFetch > 1 )
2584
2584
{
@@ -3642,6 +3642,8 @@ static OSStatus BlackHole_StartIO(AudioServerPlugInDriverRef inDriver, AudioObje
3642
3642
// important to note that multiple clients can have IO running on the device at the same time.
3643
3643
// So, work only needs to be done when the first client starts. All subsequent starts simply
3644
3644
// increment the counter.
3645
+
3646
+ DebugMsg ("BlackHole Start IO" );
3645
3647
3646
3648
#pragma unused(inClientID)
3647
3649
@@ -3668,6 +3670,9 @@ static OSStatus BlackHole_StartIO(AudioServerPlugInDriverRef inDriver, AudioObje
3668
3670
gDevice_NumberTimeStamps = 0 ;
3669
3671
gDevice_AnchorSampleTime = 0 ;
3670
3672
gDevice_AnchorHostTime = mach_absolute_time ();
3673
+
3674
+ // allocate ring buffer
3675
+ ringBuffer = malloc (RING_BUFFER_SIZE );
3671
3676
}
3672
3677
else
3673
3678
{
@@ -3686,6 +3691,8 @@ static OSStatus BlackHole_StopIO(AudioServerPlugInDriverRef inDriver, AudioObjec
3686
3691
{
3687
3692
// This call tells the device that the client has stopped IO. The driver can stop the hardware
3688
3693
// once all clients have stopped.
3694
+
3695
+ DebugMsg ("BlackHole Stop IO" );
3689
3696
3690
3697
#pragma unused(inClientID)
3691
3698
@@ -3709,6 +3716,7 @@ static OSStatus BlackHole_StopIO(AudioServerPlugInDriverRef inDriver, AudioObjec
3709
3716
{
3710
3717
// We need to stop the hardware, which in this case means that there's nothing to do.
3711
3718
gDevice_IOIsRunning = 0 ;
3719
+ free (ringBuffer );
3712
3720
}
3713
3721
else
3714
3722
{
@@ -3755,7 +3763,9 @@ static OSStatus BlackHole_GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver,
3755
3763
3756
3764
// calculate the next host time
3757
3765
theHostTicksPerRingBuffer = gDevice_HostTicksPerFrame * ((Float64 )kDevice_RingBufferSize );
3766
+
3758
3767
theHostTickOffset = ((Float64 )(gDevice_NumberTimeStamps + 1 )) * theHostTicksPerRingBuffer ;
3768
+
3759
3769
theNextHostTime = gDevice_AnchorHostTime + ((UInt64 )theHostTickOffset );
3760
3770
3761
3771
// go to the next time if the next host time is less than the current time
@@ -3854,18 +3864,17 @@ static OSStatus BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, Aud
3854
3864
FailWithAction (inDeviceObjectID != kObjectID_Device , theAnswer = kAudioHardwareBadObjectError , Done , "BlackHole_DoIOOperation: bad device ID" );
3855
3865
FailWithAction ((inStreamObjectID != kObjectID_Stream_Input ) && (inStreamObjectID != kObjectID_Stream_Output ), theAnswer = kAudioHardwareBadObjectError , Done , "BlackHole_DoIOOperation: bad stream ID" );
3856
3866
3857
-
3858
3867
/* READ INPUT */
3859
3868
if (inOperationID == kAudioServerPlugInIOOperationReadInput )
3860
3869
{
3861
3870
/* WRITE TO IOBUFFER */
3862
3871
// calculate the ring buffer offset for the first sample INPUT
3863
3872
ringBufferOffset = ((UInt64 )(inIOCycleInfo -> mInputTime .mSampleTime * BYTES_PER_FRAME ) % RING_BUFFER_SIZE );
3864
-
3873
+
3865
3874
// calculate the size of the buffer
3866
3875
inIOBufferByteSize = inIOBufferFrameSize * BYTES_PER_FRAME ;
3867
3876
remainingRingBufferByteSize = RING_BUFFER_SIZE - ringBufferOffset ;
3868
-
3877
+
3869
3878
if (remainingRingBufferByteSize > inIOBufferByteSize )
3870
3879
{
3871
3880
// copy whole buffer if we have space
@@ -3879,13 +3888,13 @@ static OSStatus BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, Aud
3879
3888
// copy 2nd half
3880
3889
memcpy (ioMainBuffer + remainingRingBufferByteSize , ringBuffer , inIOBufferByteSize - remainingRingBufferByteSize );
3881
3890
}
3882
-
3883
-
3891
+
3892
+
3884
3893
/* CLEAR TO RINGBUFFER TRAILING BY 3072 SAMPLES */
3885
3894
// calculate the ring buffer offset for the first sample INPUT
3886
3895
ringBufferOffset = ((UInt64 )(inIOCycleInfo -> mInputTime .mSampleTime * BYTES_PER_FRAME - 3072 ) % RING_BUFFER_SIZE );
3887
3896
remainingRingBufferByteSize = RING_BUFFER_SIZE - ringBufferOffset ;
3888
-
3897
+
3889
3898
if (remainingRingBufferByteSize > inIOBufferByteSize )
3890
3899
{
3891
3900
// clear the internal ring buffer
@@ -3899,7 +3908,7 @@ static OSStatus BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, Aud
3899
3908
memset (ringBuffer , 0 , inIOBufferByteSize - remainingRingBufferByteSize );
3900
3909
}
3901
3910
}
3902
-
3911
+
3903
3912
/* WRITE MIX */
3904
3913
if (inOperationID == kAudioServerPlugInIOOperationWriteMix )
3905
3914
{
@@ -3909,24 +3918,24 @@ static OSStatus BlackHole_DoIOOperation(AudioServerPlugInDriverRef inDriver, Aud
3909
3918
/* WRITE MIX TO RINGBUFFER */
3910
3919
// calculate the ring buffer offset for the first sample OUTPUT
3911
3920
ringBufferOffset = ((UInt64 )(inIOCycleInfo -> mOutputTime .mSampleTime * BYTES_PER_FRAME ) % RING_BUFFER_SIZE );
3912
-
3921
+
3913
3922
// calculate the size of the buffer
3914
3923
inIOBufferByteSize = inIOBufferFrameSize * BYTES_PER_FRAME ;
3915
-
3924
+
3916
3925
// mix the audio
3917
3926
for (UInt64 sample = 0 ; sample < inIOBufferByteSize ; sample += sizeof (Float32 ))
3918
3927
{
3919
3928
// sample from ioMainBuffer
3920
3929
Float32 * ioSample = ioMainBuffer + sample ;
3921
-
3930
+
3922
3931
// sample from ring buffer
3923
3932
Float32 * ringSample = (Float32 * )(ringBuffer + (ringBufferOffset + sample ) % RING_BUFFER_SIZE );
3924
-
3933
+
3925
3934
// mix the two together scale by volume
3926
3935
* ringSample += * ioSample * gVolume_Output_Master_Value * gVolume_Input_Master_Value ;
3927
3936
}
3928
3937
}
3929
-
3938
+
3930
3939
// clear the io buffer
3931
3940
memset (ioMainBuffer , 0 , inIOBufferByteSize );
3932
3941
}
0 commit comments