AudioQueueを使って m4a (AAC) で録音する Swift 3.0 のサンプルコード
現在の仕事で作ってるiOSアプリの中に、マイクからの音をm4a (AAC) で録音する機能が必要なので、
適当なサンプルコードはネット上に在るだろうと思い探したのですが、案外みつかりませんでした。
なぜ見つからないかというと
- 今回はいろいろな理由から、安易な AVFoundation ではなく AudioQueueを使う必要があった
- Objective.c のサンプルは見つかるが、Swiftは少ない、さらに Swift 3.0 のコードは絶望的
- また録音フォーマットが PCMのものばかり
- オーディオ周りが好きなiOS(mac OS)プログラマーは少ないの?
- 私もオーディオ周りの知識は極めて低い
Google先生が教えてくれたのは以下でした
- Appleの Audio Queue Services公式ドキュメント コードは Objective.c ですが、確実に信頼できる情報
- Swift で Audio Queue Services を使って再生する 再生、Swift 2.2 だけど参考になった
- 音声の記録 公式ドキュメントの翻訳?
絶望の中、GitHubを検索するとAudioQueueTutorial という探していたものを見つけました。 Swift 3.0 です!
しかし、録音フォーマットは PCM ・・・・
そこで、いろいろ調べて少しずつ試しながら、遂に m4a(AAC) で録音できるサンプルが出来ました。完全なコードは AudioQueueTutorialのfork に置きました (m4aブランチ)。
変更か所は
録音フォーマットの設定
info.mDataFormat.mFormatID = kAudioFormatMPEG4AAC info.mDataFormat.mSampleRate = 44100.0 info.mDataFormat.mChannelsPerFrame = 2 info.mDataFormat.mBitsPerChannel = 0 info.mDataFormat.mFramesPerPacket = 1024 info.mDataFormat.mBytesPerFrame = 0 info.mDataFormat.mBytesPerPacket = 0 info.mDataFormat.mFormatFlags = 0
バッファローサイズ計算の追加
func DeriveBufferSize(seconds: Double) -> UInt32 { let maxBufferSize: UInt32 = 0x50000 // 320 KB var maxPacketSize: UInt32 = info.mDataFormat.mBytesPerPacket var outBufferSize: UInt32 = 0 if maxPacketSize == 0 { var maxVBRPacketSize = UInt32(MemoryLayout<UInt32>.size) AudioQueueGetProperty ( info.mQueue!, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize, &maxVBRPacketSize ) } let numBytesForTime = info.mDataFormat.mSampleRate * Double(maxPacketSize) * seconds outBufferSize = numBytesForTime < Double(maxBufferSize) ? UInt32(numBytesForTime) : maxBufferSize return outBufferSize }
MagicCookie設定の追加
func SetMagicCookieForFile() { var cookieSize = UInt32(MemoryLayout<UInt32>.size) var st = AudioQueueGetPropertySize(info.mQueue!, kAudioQueueProperty_MagicCookie, &cookieSize) if st == noErr { let magicCookie: UnsafeMutablePointer<CChar> = UnsafeMutablePointer<CChar>.allocate(capacity: Int(cookieSize)) st = AudioQueueGetProperty(info.mQueue!, kAudioQueueProperty_MagicCookie, magicCookie, &cookieSize) if st != noErr { print("---- AudioQueueGetProperty error \(st)") return } st = AudioFileSetProperty(info.mAudioFile!, kAudioFilePropertyMagicCookieData, cookieSize, magicCookie) magicCookie.deallocate(capacity: Int(cookieSize)) if st != noErr { print("---- AudioFileSetProperty error \(st)") return } } else { print("---- AudioQueueGetPropertySize error \(st)") } }
ファイル作成、バッファー確保コードで上のメソッドを呼び出すようにした
// create file let path = (NSTemporaryDirectory() as NSString).appendingPathComponent("audio.m4a") outputUrl = URL(fileURLWithPath: path) st = AudioFileCreateWithURL(outputUrl as CFURL, kAudioFileM4AType, &info.mDataFormat, .eraseFile, &info.mAudioFile) if st != noErr { print("---- AudioFileCreateWithURL error \(st)") return nil } SetMagicCookieForFile() // allocate buffer info.bufferByteSize = DeriveBufferSize(seconds: 10.0) for _ in 0..<kNumberBuffers { var buffer: AudioQueueBufferRef? st = AudioQueueAllocateBuffer(queue!, info.bufferByteSize, &buffer) if st != noErr { print("---- AudioQueueAllocateBuffer error \(st)") return nil } info.mBuffers.append(buffer!) AudioQueueEnqueueBuffer(queue!, buffer!, 0, nil) }
以上です、
tomisacat (tomisacat) · GitHub さんありがとうございます! それから参考にさえて頂いた情報を書いた人ありがとうございます。