Recording with AudioQueue and Monotouch static sou

2019-02-24 14:05发布

问题:

I have written a small program in MonoTouch to record sound from the mic of my iPhone 4s using an InputAudioQueue.

I save the recorded data in an array and feed this buffer to the my audio player for playback (using OutputAudioQueue).

When playing back it's just some stuttering garbage / static sound. I have tried filling the buffer with sin waves before playback and then it sounds good, so I guess the problem is in the recording, not the playback. Can anyone help me see what is wrong? (Code below)

public class AQRecorder
{
    private const int CountAudioBuffers = 3;
    private const int AudioBufferLength = 22050;
    private const int SampleRate = 44100;
    private const int BitsPerChannel = 16;
    private const int Channels = 1;
    private const int MaxRecordingTime = 5;
    private AudioStreamBasicDescription audioStreamDescription;
    private InputAudioQueue inputQueue;
    private short[] rawData;
    private int indexNextRawData;

    public AQRecorder ()
    {
        this.audioStreamDescription.Format = AudioFormatType.LinearPCM;
        this.audioStreamDescription.FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | 
                                                  AudioFormatFlags.LinearPCMIsPacked;
        this.audioStreamDescription.SampleRate = AQRecorder.SampleRate;
        this.audioStreamDescription.BitsPerChannel = AQRecorder.BitsPerChannel;
        this.audioStreamDescription.ChannelsPerFrame = AQRecorder.Channels;
        this.audioStreamDescription.BytesPerFrame = (AQRecorder.BitsPerChannel / 8) * AQRecorder.Channels;
        this.audioStreamDescription.FramesPerPacket = 1;
        this.audioStreamDescription.BytesPerPacket = audioStreamDescription.BytesPerFrame * audioStreamDescription.FramesPerPacket;
        this.audioStreamDescription.Reserved = 0;
    }

    public void Start ()
    {
        int totalBytesToRecord = this.audioStreamDescription.BytesPerFrame * AQRecorder.SampleRate * AQRecorder.MaxRecordingTime;
        this.rawData = new short[totalBytesToRecord / sizeof(short)];
        this.indexNextRawData = 0;
        this.inputQueue = SetupInputQueue (this.audioStreamDescription);
        this.inputQueue.Start ();
    }

    public void Stop ()
    {
        if (this.inputQueue.IsRunning)
        {
            this.inputQueue.Stop (true);
        }
    }

    public short[] GetData ()
    {
        return this.rawData;;
    }

    private InputAudioQueue SetupInputQueue (AudioStreamBasicDescription audioStreamDescription)
    {
        InputAudioQueue inputQueue = new InputAudioQueue (audioStreamDescription);

        for (int count = 0; count < AQRecorder.CountAudioBuffers; count++)
        {
            IntPtr bufferPointer;
            inputQueue.AllocateBuffer(AQRecorder.AudioBufferLength, out bufferPointer);
            inputQueue.EnqueueBuffer(bufferPointer, AQRecorder.AudioBufferLength, null);
        }
        inputQueue.InputCompleted += HandleInputCompleted;
        return inputQueue;
    }

    private void HandleInputCompleted (object sender, InputCompletedEventArgs e)
    {
        unsafe
        {
            short* shortPtr = (short*)e.IntPtrBuffer;

            for (int count = 0; count < AQRecorder.AudioBufferLength; count += sizeof(short))
            {
                if (indexNextRawData >= this.rawData.Length)
                {
                    this.inputQueue.Stop (true);
                    return;
                }
                this.rawData [indexNextRawData] = *shortPtr;
                indexNextRawData++;
                shortPtr++;
            }
        }
        this.inputQueue.EnqueueBuffer(e.IntPtrBuffer, AQRecorder.AudioBufferLength, null);
    }
}

回答1:

ok, this might be too late, but I had the same problem with hearing garbage sound only and found the solution.

You cannot read the audio data directly from e.IntPtrBuffer. This pointer is a pointer to a AudioQueueBuffer object and not to the audio data itself. So to read the audio data you can make use of the e.UnsafeBuffer which gives you the access to this object and use its AudioData pointer. This is a IntPtr which you can cast (in unsafe context) to a byte* or short* and you have your audio data.

Best regards

Alex