在iOS上录制实时音频流

时间:2016-04-13 05:42:08

标签: c# ios audio xamarin streaming

//Declare string for application temp path and tack on the file extension
string fileName = string.Format ("Myfile{0}.wav", DateTime.Now.ToString ("yyyyMMddHHmmss"));
string audioFilePath = Path.Combine (Path.GetTempPath (), fileName);

Console.WriteLine("Audio File Path: " + audioFilePath);

url = NSUrl.FromFilename(audioFilePath);
//set up the NSObject Array of values that will be combined with the keys to make the NSDictionary
NSObject[] values = new NSObject[]
{
    NSNumber.FromFloat (44100.0f), //Sample Rate
    NSNumber.FromInt32 ((int)AudioToolbox.AudioFormatType.LinearPCM), //AVFormat
    NSNumber.FromInt32 (2), //Channels
    NSNumber.FromInt32 (16), //PCMBitDepth
    NSNumber.FromBoolean (false), //IsBigEndianKey
    NSNumber.FromBoolean (false) //IsFloatKey
};

//Set up the NSObject Array of keys that will be combined with the values to make the NSDictionary
NSObject[] keys = new NSObject[]
{
    AVAudioSettings.AVSampleRateKey,
    AVAudioSettings.AVFormatIDKey,
    AVAudioSettings.AVNumberOfChannelsKey,
    AVAudioSettings.AVLinearPCMBitDepthKey,
    AVAudioSettings.AVLinearPCMIsBigEndianKey,
    AVAudioSettings.AVLinearPCMIsFloatKey
};

//Set Settings with the Values and Keys to create the NSDictionary
settings = NSDictionary.FromObjectsAndKeys (values, keys);

//Set recorder parameters
recorder = AVAudioRecorder.Create(url, new AudioSettings(settings), out error);

//Set Recorder to Prepare To Record
recorder.PrepareToRecord();

This代码效果很好,但是如何将麦克风的记录直接保存到流? 我没有在互联网上找到任何信息,我希望你能帮助我

1 个答案:

答案 0 :(得分:2)

您正在寻找对音频流的缓冲访问(录制或播放),iOS通过Audio Queue Services提供它(AVAudioRecorder太高级别),因此当音频缓冲区被填充时,iOS调用你的callback有一个来自队列的填充缓冲区,你用它做一些事情(将它保存到磁盘,将其写入基于C#的Stream,发送到播放音频队列[发言者]等...)和通常,将其放回队列中以便重复使用。

这样的事情开始录制到queue音频缓冲区:

var recordFormat = new AudioStreamBasicDescription() {
    SampleRate = 8000,
    Format = AudioFormatType.LinearPCM,
    FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | AudioFormatFlags.LinearPCMIsPacked,
    FramesPerPacket = 1,
    ChannelsPerFrame = 1,
    BitsPerChannel = 16,
    BytesPerPacket = 2,
    BytesPerFrame = 2,
    Reserved = 0
};

recorder = new InputAudioQueue (recordFormat);

for (int count = 0; count < BufferCount; count++) {
    IntPtr bufferPointer;
    recorder.AllocateBuffer(AudioBufferSize, out bufferPointer);
    recorder.EnqueueBuffer(bufferPointer, AudioBufferSize, null);
}
recorder.InputCompleted += HandleInputCompleted;
recorder.Start ();

因此,在此示例中假设AudioBufferSize为8k且BufferCount为3,因此一旦填充了三个缓冲区中的第一个,就会调用我们的处理程序HandleInputCompleted(因为有2个仍在queue录音中的缓冲区继续存在。

我们的InputCompleted处理程序:

private void HandleInputCompleted (object sender, InputCompletedEventArgs e)
{
    // We received a new buffer of audio, do something with it....

    // Some unsafe code will be required to rip the buffer...

    // Place the buffer back into the queue so iOS knows you are done with it
    recorder.EnqueueBuffer(e.IntPtrBuffer, AudioBufferSize, null);

    // At some point you need to call `recorder.Stop();`  ;-)
}

(我从处理程序中删除了我们的代码,因为它是一个自定义的音频2文本学习中性网络,因为我们在非常大的队列中使用非常小的缓冲区来减少反馈延迟并在单个TCP / UDP中加载音频数据用于云处理的数据包(想想Siri; - )

在此处理程序中,您可以访问Pointer到当前通过InputCompletedEventArgs.IntPtrBuffer填充的缓冲区,使用该指针可以peek缓冲区中的每个字节poke如果这是你的目标,那么将它们添加到基于C#的Stream中。

Apple有一篇关于音频队列的伟大技术文章:https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/AboutAudioQueues/AboutAudioQueues.html