IOSでグループ用のビデオチャットアプリを作成しました。さまざまな参加者のオーディオボリュームを個別に制御する方法をいくつか探しています。 isPlaybackEnabled
でRemoteAudioTrack
を使用してミュートおよびミュート解除する方法を見つけましたが、音量を制御する方法はありませんでした。
AVAudioPlayer
で使用できるかどうかも考えました。 addSink
が見つかりました。これは私が試したものです here :
_class Audio: NSObject, AudioSink {
var a = 1
func renderSample(_ audioSample: CMSampleBuffer!) {
print("audio found", a)
a += 1
var audioBufferList = AudioBufferList()
var data = Data()
var blockBuffer : CMBlockBuffer?
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(audioSample, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: 0, blockBufferOut: &blockBuffer)
let buffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers))
for audioBuffer in buffers {
let frame = audioBuffer.mData?.assumingMemoryBound(to: UInt8.self)
data.append(frame!, count: Int(audioBuffer.mDataByteSize))
}
let player = try! AVAudioPlayer(data: data) //crash here
player.play()
}
}
_
しかし、それはlet player = try! AVAudioPlayer(data: data)
でクラッシュしました。
編集:
これはエラーです:Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSOSStatusErrorDomain Code=-39 "(null)": file
。
これはdata
なので、変換されていないと思います。
_▿ 0 bytes
- count : 0
▿ pointer : 0x000000016d7ae160
- pointerValue : 6131736928
- bytes : 0 elements
_
そして、これがaudioSample
です。
_<CMAudioFormatDescription 0x2815a3de0 [0x1bb2ef830]> {
mediaType:'soun'
mediaSubType:'lpcm'
mediaSpecific: {
ASBD: {
mSampleRate: 16000.000000
mFormatID: 'lpcm'
mFormatFlags: 0xc
mBytesPerPacket: 2
mFramesPerPacket: 1
mBytesPerFrame: 2
mChannelsPerFrame: 1
mBitsPerChannel: 16 }
cookie: {(null)}
ACL: {(null)}
FormatList Array: {(null)}
}
extensions: {(null)}
}
_
CMSampleBufferから完全なデータバッファーを取得し、Dataに変換できます:
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer)
let blockBufferDataLength = CMBlockBufferGetDataLength(blockBuffer!)
var blockBufferData = [UInt8](repeating: 0, count: blockBufferDataLength)
let status = CMBlockBufferCopyDataBytes(blockBuffer!, atOffset: 0, dataLength: blockBufferDataLength, destination: &blockBufferData)
guard status == noErr else { return }
let data = Data(bytes: blockBufferData, count: blockBufferDataLength)
また、 AVAudioPlayer 概要も参照してください:
ネットワークストリームからキャプチャされたオーディオを再生する場合や、非常に低いI/Oレイテンシが必要な場合を除き、このクラスをオーディオ再生に使用します。
だから私はそれがあなたのために働くとは思いません。 AVAudioEngine または Audio Queue Services を使用することをお勧めします。
あなたの方法しないが機能する理由はわかりませんが、CMSampleBuffer
を使用して他のData
sを編集しました。これを試して:
class Audio: NSObject {
func renderSample(_ sampleBuffer: CMSampleBuffer!) {
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
let height = CVPixelBufferGetHeight(imageBuffer!)
let src_buff = CVPixelBufferGetBaseAddress(imageBuffer!)
let data = Data(bytes: src_buff!, count: bytesPerRow * height)
CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
doSomething(data: Data)
}
func doSomething(data:Data)
{
print(data.count) //Make sure isn't 0
}
}
これは単にバッファからData
を作成し、他の人がロックしないかロックしないようにロックとロック解除を確実にします。テストするオーディオバッファーがないので、これは暗闇の中でのショットです。お知らせ下さい!