Skip to main content
 首页 » 编程设计

c#之在 iOS 上录制实时音频流

2024年04月30日28xing901022

//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代码运行良好,但如何将麦克风的记录直接保存到流中? 我在网上没有找到任何资料,希望你能帮助我

请您参考如下方法:

您正在寻找对音频流(录音或播放)的缓冲访问,iOS 通过Audio Queue Services 提供它(AVAudioRecorder 级别太高),那么当音频缓冲区已满时,iOS 使用队列中已填充的缓冲区调用您的 callback,您可以对其执行一些操作(将其保存到磁盘,将其写入基于 C# 的 Stream,发送到播放音频queue [speakers], etc...),通常将其放回队列中以供重用。

像这样的事情开始记录到音频缓冲区的队列:

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 被调用(因为 queue 中仍有 2 个缓冲区,记录继续到它们。

我们的 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();`  ;-) 
} 

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

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

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