Simplest way to capture raw audio from audio input

2020-02-26 12:26发布

What is the simplest way to capture audio from the built in audio input and be able to read the raw sampled values (as in a .wav) in real time as they come in when requested, like reading from a socket.

Hopefully code that uses one of Apple's frameworks (Audio Queues). Documentation is not very clear, and what I need is very basic.

2条回答
够拽才男人
2楼-- · 2020-02-26 13:07

Try the AudioQueue Framework for this. You mainly have to perform 3 steps:

  1. setup an audio format how to sample the incoming analog audio
  2. start a new recording AudioQueue with AudioQueueNewInput()
  3. Register a callback routine which handles the incoming audio data packages

In step 3 you have a chance to analyze the incoming audio data with AudioQueueGetProperty()

It's roughly like this:

static void HandleAudioCallback (void                               *aqData,
                                 AudioQueueRef                      inAQ,
                                 AudioQueueBufferRef                inBuffer, 
                                 const AudioTimeStamp               *inStartTime, 
                                 UInt32                             inNumPackets, 
                                 const AudioStreamPacketDescription *inPacketDesc) {
    // Here you examine your audio data
}

static void StartRecording() {
    // now let's start the recording
    AudioQueueNewInput (&aqData.mDataFormat,  // The sampling format how to record
                        HandleAudioCallback,  // Your callback routine
                        &aqData,              // e.g. AudioStreamBasicDescription
                        NULL,
                        kCFRunLoopCommonModes, 
                        0, 
                        &aqData.mQueue);      // Your fresh created AudioQueue
    AudioQueueStart(aqData.mQueue,
                    NULL);
}

I suggest the Apple AudioQueue Services Programming Guide for detailled information about how to start and stop the AudioQueue and how to setup correctly all ther required objects.

You may also have a closer look into Apple's demo prog SpeakHere. But this is IMHO a bit confusing to start with.

查看更多
Animai°情兽
3楼-- · 2020-02-26 13:07

It depends how ' real-time ' you need it

if you need it very crisp, go down right at the bottom level and use audio units. that means setting up an INPUT callback. remember, when this fires you need to allocate your own buffers and then request the audio from the microphone.

ie don't get fooled by the presence of a buffer pointer in the parameters... it is only there because Apple are using the same function declaration for the input and render callbacks.

here is a paste out of one of my projects:

OSStatus dataArrivedFromMic(
                    void                        * inRefCon, 
                    AudioUnitRenderActionFlags  * ioActionFlags, 
                    const AudioTimeStamp        * inTimeStamp, 
                    UInt32                      inBusNumber, 
                    UInt32                      inNumberFrames, 
                    AudioBufferList             * dummy_notused )
{    
    OSStatus status;

    RemoteIOAudioUnit* unitClass = (RemoteIOAudioUnit *)inRefCon;

    AudioComponentInstance myUnit = unitClass.myAudioUnit;

    AudioBufferList ioData;
    {
        int kNumChannels = 1; // one channel...

        enum {
            kMono = 1,
            kStereo = 2
        };

        ioData.mNumberBuffers = kNumChannels;

        for (int i = 0; i < kNumChannels; i++) 
        {
            int bytesNeeded = inNumberFrames * sizeof( Float32 );

            ioData.mBuffers[i].mNumberChannels = kMono;
            ioData.mBuffers[i].mDataByteSize = bytesNeeded;
            ioData.mBuffers[i].mData = malloc( bytesNeeded );
        }
    }

    // actually GET the data that arrived
    status = AudioUnitRender( (void *)myUnit, 
                             ioActionFlags, 
                             inTimeStamp, 
                             inBusNumber, 
                             inNumberFrames, 
                             & ioData );


    // take MONO from mic
    const int channel = 0;
    Float32 * outBuffer = (Float32 *) ioData.mBuffers[channel].mData;

    // get a handle to our game object
    static KPRing* kpRing = nil;
    if ( ! kpRing )
    {
        //AppDelegate *  appDelegate = [UIApplication sharedApplication].delegate;

        kpRing = [Game singleton].kpRing;

        assert( kpRing );
    }

    // ... and send it the data we just got from the mic
    [ kpRing floatsArrivedFromMic: outBuffer
                            count: inNumberFrames ];

    return status;
}
查看更多
登录 后发表回答