0

I have a conundrum:

I'm using BlackHole try to capture system output audio on macOS, BlackHole drive can create an virtual audio device, like BlackHole 2ch, which supports 2 channels.
when I select this virtual device as audio output device, I do really can capture system output audio through a corresponding virtual input device created by BlockHole at the same time with virtual output device.

But, there is no sound playback from virtual output device, I cannot hear any voice from speaker or headphone.
I know it must be write some lines of code in BlackHole_DoIOOperation() function, but I don't know any direction, can anyone give me some suggestion? Thanks

This is virtual output device created by BlackHole This is virtual output device created by BlackHole

This is virtual input device created by BlackHole This is virtual input device created by BlackHole


here is BlackHole_DoIOOperation() function source code:
I suspect caused by this line of code, so I removed it, but still doesn't work.
// memset(ioMainBuffer, 0, inIOBufferFrameSize * NUMBER_OF_CHANNELS * sizeof(Float32));

static OSStatus BlackHole_DoIOOperation(AudioServerPlugInDriverRef          inDriver,
                                        AudioObjectID                       inDeviceObjectID,
                                        AudioObjectID                       inStreamObjectID,
                                        UInt32                              inClientID,
                                        UInt32                              inOperationID,
                                        UInt32                              inIOBufferFrameSize,
                                        const AudioServerPlugInIOCycleInfo* inIOCycleInfo,
                                        void*                               ioMainBuffer,
                                        void*                               ioSecondaryBuffer)
{
    //  This is called to actuall perform a given operation. For this device, all we need to do is
    //  clear the buffer for the ReadInput operation.
    DebugMsg("BlackHole DoIOOperation()");
    #pragma unused(inClientID, inIOCycleInfo, ioSecondaryBuffer)
    
    //  declare the local variables
    OSStatus theAnswer = 0;
    
    //  check the arguments
    FailWithAction(inDriver != gAudioServerPlugInDriverRef, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad driver reference");
    FailWithAction(inDeviceObjectID != kObjectID_Device, theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad device ID");
    FailWithAction((inStreamObjectID != kObjectID_Stream_Input) && (inStreamObjectID != kObjectID_Stream_Output), theAnswer = kAudioHardwareBadObjectError, Done, "BlackHole_DoIOOperation: bad stream ID");
    
    // IO Lock
    pthread_mutex_lock(&gDevice_IOMutex);

    // From BlackHole to Application
    if(inOperationID == kAudioServerPlugInIOOperationReadInput)
    {

        Float32* buffer = (Float32*)ioMainBuffer;
        UInt64 mSampleTime = inIOCycleInfo->mInputTime.mSampleTime;

        for (UInt32 frame = 0; frame < inIOBufferFrameSize; frame++)
        {
            for (int channel = 0; channel < NUMBER_OF_CHANNELS; channel++)
            {
                // don't do anything if muted
                if (!gMute_Output_Master_Value)
                {
                    // write to the ioMainBuffer
                    buffer[frame*NUMBER_OF_CHANNELS+channel] = ringBuffer[((mSampleTime+frame)%kDevice_RingBufferSize)*NUMBER_OF_CHANNELS+channel];
                }
                else
                {
                    buffer[frame*NUMBER_OF_CHANNELS+channel] = 0;
                }
                
                // clear ring buffer after 8192 samples.
                ringBuffer[((mSampleTime+frame-8192)%kDevice_RingBufferSize)*NUMBER_OF_CHANNELS+channel] = 0;

            }
        }
    }
    
    // From Application to BlackHole
    if(inOperationID == kAudioServerPlugInIOOperationWriteMix)
    {
        DebugMsg("output...");
        Float32* buffer = (Float32*) ioMainBuffer;
        UInt64 mSampleTime = inIOCycleInfo->mOutputTime.mSampleTime;
        for (UInt32 frame = 0; frame < inIOBufferFrameSize; frame++)
        {
            for (int channel = 0; channel < NUMBER_OF_CHANNELS; channel++)
            {
                // don't do anything if muted
                if (!gMute_Output_Master_Value)
                {
                    // write to internal ring buffer
                    DebugMsg("channel: %d", channel);
                    ringBuffer[((mSampleTime + frame) % kDevice_RingBufferSize) * NUMBER_OF_CHANNELS + channel] += buffer[frame * NUMBER_OF_CHANNELS + channel] * gVolume_Output_Master_Value;
                }
                else
                {
                    buffer[frame * NUMBER_OF_CHANNELS + channel] = 0;
                }
                
                // clear ring buffer after 8192 samples.
                ringBuffer[((mSampleTime + frame - 8192) % kDevice_RingBufferSize) * NUMBER_OF_CHANNELS + channel] = 0;
            }
        }
        theAnswer = kAudioHardwareBadObjectError;
        
        // clear the io buffer
        // memset(ioMainBuffer, 0, inIOBufferFrameSize * NUMBER_OF_CHANNELS * sizeof(Float32));
    }
    
    pthread_mutex_unlock(&gDevice_IOMutex);

Done:
    return theAnswer;
}
4

0 回答 0