AVAudioCompressedBuffer 到 UInt8 数组,反之亦然

2024-04-08

我想知道如何获取 AVAudioCompressedBuffer 的字节,然后 从字节重建 AVAudioCompressedBuffer。

下面的代码采用 AVAudioPCMBuffer,使用 AVAudioConverter 将其压缩为 AVAudioCompressedBuffer (iLBC) 并获取字节,然后将字节转换回 AVAudioCompressedBuffer (iLBC) 并解压缩回 AVAudioPCMBuffer 并播放缓冲区。将 AVAudioCompressedBuffer 转换为字节并返回时出现问题。如果我跳过此转换,音频将按预期播放。

我什至可以匹配compressedBuffer和compressedBuffer2的内容,这让我相信获取字节的机制并不完全正确。

// Do iLBC Compression
let compressedBuffer: AVAudioCompressedBuffer = self.compress(inBuffer: buffer)
// packetCapacity: 4, maximumPacketSize: 38
// self.player.scheduleBuffer(self.uncompress(inBuffer: compressedBuffer)) // This works perfectly

// Convert Buffer to Byte Array
let pointer1: UnsafeMutablePointer = compressedBuffer.data.bindMemory(to: UInt8.self, capacity: 152)
var audioByteArray = [UInt8](repeating: 0, count: 152)
pointer1.withMemoryRebound(to: UInt8.self, capacity: 152) { srcByteData in
    audioByteArray.withUnsafeMutableBufferPointer {
        $0.baseAddress!.initialize(from: srcByteData, count: 152)
    }
}

// Convert Byte Array to Buffer
let compressedBuffer2: AVAudioCompressedBuffer = AVAudioCompressedBuffer(format: AVAudioFormat.init(streamDescription: &self.descriptor)!, packetCapacity: 4, maximumPacketSize: 38)
let destination = compressedBuffer2.data
audioByteArray.withUnsafeBufferPointer {
    let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: UInt8.self, capacity: 152)
    destination.copyMemory(from: src, byteCount: 152)
}

// Do iLBC Decompression
let uncompressedBuffer: AVAudioPCMBuffer = self.uncompress(inBuffer: compressedBuffer2)
// Works perfectly with inBuffer: compressedBuffer

// Play Buffer
self.player.scheduleBuffer(uncompressedBuffer)
// Plays fine when 'let uncompressedBuffer: AVAudioPCMBuffer = self.uncompress(inBuffer: compressedBuffer)'

压缩和解压缩功能

let format = AVAudioFormat.init(commonFormat: AVAudioCommonFormat.pcmFormatFloat32, sampleRate: 16000, channels: 1, interleaved: false)
var compressedFormatDescriptor = AudioStreamBasicDescription(mSampleRate: 8000, mFormatID: kAudioFormatiLBC, mFormatFlags: 0, mBytesPerPacket: 0, mFramesPerPacket: 0, mBytesPerFrame: 0, mChannelsPerFrame: 1, mBitsPerChannel: 0, mReserved: 0)

func compress(inBuffer : AVAudioPCMBuffer) -> AVAudioCompressedBuffer {
    let inputFormat = inBuffer.format

    let converter = AVAudioConverter(from: inputFormat, to: self.compressedFormat!)

    let outBuffer = AVAudioCompressedBuffer(format: self.compressedFormat!, packetCapacity: 4, maximumPacketSize: 38)
    let inputBlock : AVAudioConverterInputBlock = { inNumPackets, outStatus in
        outStatus.pointee = AVAudioConverterInputStatus.haveData
        return inBuffer
    }
    var error : NSError?
    converter!.convert(to: outBuffer, error: &error, withInputFrom: inputBlock)

    return outBuffer
}

func uncompress(inBuffer : AVAudioCompressedBuffer) -> AVAudioPCMBuffer {
    let inputFormat = inBuffer.format
    let outputFormat = format

    let converter = AVAudioConverter(from: inputFormat, to: outputFormat!)

    let inputBlock : AVAudioConverterInputBlock = { inNumPackets, outStatus in
        outStatus.pointee = AVAudioConverterInputStatus.haveData
        return inBuffer
    }
    var error : NSError?
    let outBuffer: AVAudioPCMBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat!, frameCapacity: 1600)!
    converter!.convert(to: outBuffer, error: &error, withInputFrom: inputBlock)

    return outBuffer
}

这就是我最终所做的。
主要的事情是在第二个 AVAudioCompressedBuffer 上设置 byteLength 和 packetCount。

iLBC 具有固定的帧大小(20ms 帧每块 304 位)
304 * 50 = 15200 = 15.2 kbit/s

AVAudioInputNode 的 AVAudioNodeTapBlock 每 100 毫秒触发一次。
字节长度 = 304 位 / 8 = 38 字节
数据包计数 = 5

这将导致 5 * 38 * 10 * 8 = 15200 = 15.2 kbit/s。

下面的代码显示了所写的所有内容。
所以,发生的事情是
1) 将 AVAudioPCMBuffer 从麦克风转换为 AVAudioCompressedBuffer (iLBC)
2) 将 AVAudioCompressedBuffer (iLBC) 转换为 [UInt8](5 * 38 = 190 字节)。
3)将[UInt8]转换为AVAudioCompressedBuffer(iLBC)
4) 将 AVAudioCompressedBuffer (iLBC) 转换为 AVAudioPCMBuffer
5) 播放AVAudioPCMBuffer

// Compress to iLBC
let packetCapacity = 5
let maximumPacketSize = 38
let capacity = packetCapacity * maximumPacketSize // 190

var descriptor = AudioStreamBasicDescription.init(mSampleRate: 8000, mFormatID: kAudioFormatiLBC, mFormatFlags: 0, mBytesPerPacket: 0, mFramesPerPacket: 0, mBytesPerFrame: 0, mChannelsPerFrame: 1, mBitsPerChannel: 0, mReserved: 0)
let ilbcformat = AVAudioFormat.init(streamDescription: &descriptor)

let compressor: AVAudioConverter = AVAudioConverter.init(from: self.format!, to: ilbcformat)!
let inputBlock : AVAudioConverterInputBlock = { inNumPackets, outStatus in
    outStatus.pointee = AVAudioConverterInputStatus.haveData
    return buffer
}
let compressedBuffer: AVAudioCompressedBuffer = AVAudioCompressedBuffer(format: ilbcformat, packetCapacity: 5, maximumPacketSize: 38)
compressor.convert(to: compressedBuffer, error: nil, withInputFrom: inputBlock)

// Convert to Bytes
let compressedBufferPointer = compressedBuffer.data.bindMemory(to: UInt8.self, capacity: 190)
var compressedBytes: [UInt8] = [UInt8].init(repeating: 0, count: 190)
compressedBufferPointer.withMemoryRebound(to: UInt8.self, capacity: 190) { sourceBytes in
    compressedBytes.withUnsafeMutableBufferPointer {
        $0.baseAddress!.initialize(from: sourceBytes, count: 190)
    }
}

// Convert to buffer
let compressedBuffer2: AVAudioCompressedBuffer = AVAudioCompressedBuffer.init(format: ilbcformat, packetCapacity: 5, maximumPacketSize: 38)
compressedBuffer2.byteLength = 190
compressedBuffer2.packetCount = 5
compressedBytes.withUnsafeMutableBufferPointer {
    compressedBuffer2.data.copyMemory(from: $0.baseAddress!, byteCount: 190)
}

// Uncompress to PCM
let uncompressor: AVAudioConverter = AVAudioConverter.init(from: ilbcformat, to: self.format!)!
let inputBlock2 : AVAudioConverterInputBlock = { inNumPackets, outStatus in
    outStatus.pointee = AVAudioConverterInputStatus.haveData
    return compressedBuffer2
}
let uncompressedBuffer: AVAudioPCMBuffer = AVAudioPCMBuffer.init(pcmFormat: self.format!, frameCapacity: 4410)!
uncompressor.convert(to: uncompressedBuffer, error: nil, withInputFrom: inputBlock2)

// Play Buffer
self.player.scheduleBuffer(uncompressedBuffer)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AVAudioCompressedBuffer 到 UInt8 数组,反之亦然 的相关文章

  • 如何获得包含大量图像(50-200)的快速 UICollectionView?

    我在用着UICollectionView在一个显示大量照片 50 200 的应用程序中 我在让它变得活泼 例如像照片应用程序一样活泼 时遇到问题 我有一个习惯UICollectionViewCell with a UIImageView因为
  • Javascript JSON stringify 没有要包含在数据中的数字索引

    我正在尝试通过 JSON 传递非数字索引值 但没有获取数据 var ConditionArray new Array ConditionArray 0 1 ConditionArray 1 2 ConditionArray 2 3 Cond
  • 从两个相交的多边形创建新的 MKPolygon

    我知道确实有一个具体的问题讨论了这一点 但它有点老了 如果可能的话 我想了解更多技术性的知识 首先看一下这个截图 https www dropbox com s f94q3qaxrog0ec9 intersections png https
  • Google Analytics Pod 安装了太多依赖项

    我刚刚添加了 Google Analytics Pod 如中所述他们的 iOS 开发者指南 https developers google com analytics devguides collection ios v3 with pod
  • 检查文本字段是否为空会导致 Swift 2 错误

    我正在尝试检查文本框是否没有值 当我这样做时 if userEmail isEmpty userPassword isEmpty userPasswordRepeat isEmpty I get the following error I
  • 如何从我的应用程序打开 ios Native dialer 应用程序

    我想打开本机拨号器应用程序并允许用户在那里输入电话号码 我想要这个的原因是因为在我的应用程序中 用户需要使用 USSD 代码才能拨打电话 但使用下面的代码没有任何反应 没有任何启动 NSString phoneNumber tel stri
  • 导航栏的横向视图问题

    默认导航栏高度为 64 但更改后 其横向导航栏高度的方向更改为 28 我想设置修复所有方向的导航栏大小 您可以添加方向观察者 NotificationCenter default addObserver self selector sele
  • Swift AVCaptureSession 关闭打开按钮错误:当前不支持多个音频/视频 AVCaptureInputs

    我有一个可用的条形码扫描仪代码 当我点击openCamera按钮 第一次一切都很好 当我点击closeCamera按钮 很好 但是如果我再次点击openCamera按钮给出致命错误 代码和错误如下 事实上 是否可以一键切换相机视图 Barc
  • 在 iOS8.3 上显示警报视图时不必要地触发 iOS 键盘通知

    我们正在观察 iOS 8 3 上键盘将显示和隐藏通知的异常行为 视图控制器 监听键盘通知 有一个文本字段 单击并点击提交按钮后 该方法首先从文本字段中退出第一响应者 并显示一条警报以通知警告 一切正常 它会关闭键盘并按预期显示警报 也调用
  • 如何将预编译头文件添加到我的 ios 项目中?

    我希望创建一个预编译头文件 以避免在项目中的每个头文件中包含相同的调试和跟踪库 我创建了一个名为 Prefix pch 的文件 ifdef OBJC import Blah h import Blarg h endif 并将其添加到项目中
  • 协议扩展,不符合协议

    我正在创建一个名为MyFramework含有LoginProtocol swift它有一些默认行为 import UIKit public protocol LoginProtocol func appBannerImage gt UIIm
  • 检查 NSIndexPath 的行和部分的开关

    我想设置一个 switch 语句来检查值 ifNSIndexPath NSIndexPath是一个类 它由 除其他外 部分和行组成 indexPath row indexPath section 这就是我如何制定 if 语句来同时检查行和部
  • 用于 RSS feed 解析的 Objective-C 库?

    我正在为 iOS 应用程序寻找一个 Objective C 库 该库将解析并显示 RSS 提要中的文章 具体来说 我正在寻找为新闻网站制作一个应用程序 如果可能的话 该框架应该能够使用各种 RSS XML 结构 嗯 有两个不同的新闻网站 一
  • 检查indexPath处的单元格在屏幕UICollectionView上是否可见

    我有一个CollectionView向用户显示图像 我在后台下载这些 下载完成后 我调用以下函数来更新collectionViewCell并显示图像 func handlePhotoDownloadCompletion notificati
  • 如何在Python中一次比较二维数组的2列与另一个数组的列

    我有两个字符串数组 每个数组有三列 我想比较两个二维数组的前两列 有 3 列和 4000 行 如果它们匹配 那么我需要那些匹配的值 但是我的代码不起作用 这是一个示例 array1 1stcolumn 2ndColumn 3rdColumn
  • 应用内购买导致偶尔崩溃

    我在互联网上搜索了这方面的帮助 但没有结果 我的应用程序已在应用程序商店中上线 少数用户报告应用程序在进行应用内购买后冻结并崩溃 我的游戏中唯一的 IAP 它基本上解锁了完整版本 即使他们重新启动设备并尝试继续 设备也会再次崩溃 我无法重现
  • 为什么 NSOrderedSet 不继承 NSSet?

    当然 有序集是集合的更具体的情况 那么为什么NSOrderedSet继承自NSObject而不是NSSet 我通过了界面NSSet你是对的 有序集似乎满足里氏替换原则 http en wikipedia org wiki Liskov su
  • iOS 10 和 swift 2.3 中支持的InterfaceOrientations

    我正在使用 Xcode 8 GM 并且有一个旧项目需要更新为 iOS 10 我发现我当前使用 Swift 2 2 版本的应用商店构建在 iOS 10 上运行时不支持所需的界面方向功能 简而言之 当我重写supportedInterfaceO
  • 迭代 NSDictionary 时保持顺序

    我有一个 NSDictionary 它正在迭代并将数据保存到核心数据 如下所示 NSDictionary details valueDict objectForKey shipment master for NSDictionary res
  • Data.Array 有多快?

    The 文档 http haskell org ghc docs latest html libraries array 0 3 0 3 Data Array html of Data Array reads Haskell 提供了可索引数

随机推荐

  • 在加载页面的所有元素之前加载 Chrome 扩展

    我想在页面的所有元素加载之前 而不是之后 加载我的 Chrome 扩展 这可能吗 谢谢 如果通过扩展你的意思是内容脚本那么你最多可以做的是设置 run at document start 清单中的财产意味着 内容脚本 文件是在 css 中的
  • 使用 PHP 的交互式 shell

    是否可以单独使用 PHP 创建交互式 shell 我的意思是像数据库一样 Python https en wikipedia org wiki Python 28programming language 29等等 如果是的话 怎么样 是的
  • Github 下载页面/按钮不再可见

    我曾经使用存储库中文件选项卡上的下载 添加下载 按钮上传二进制文件 这个功能好像没有了 有人知道为什么吗 临时 Github 问题 浏览器问题 GitHub 上传已于 12 月 11 日停止 请参阅博客文章 https github com
  • "rdtsc": "=a" (a0), "=d" (d0) 这是做什么的? [复制]

    这个问题在这里已经有答案了 我是 C 和基准测试的新手 我不明白这部分代码的作用是什么 所以我发现了一些关于 edx eax 寄存器的信息 但我不完全理解它是如何在代码中发挥作用的 所以我理解这段代码本质上返回了CPU周期的当前滴答声 那么
  • 如何在 Playgrounds 中设置 ViewController?

    在 Swift Playgrounds 中 如何设置视图控制器并使用它 我之前用 UIView 做过 但是当方向不同时 UI 会被剪切 所以我想尝试使用视图控制器 我有let view UIViewController 但在那之后我该如何设
  • Office-js Excel:获取新保存文件的文件名

    如何获取新保存文件的文件名 通常 我可以使用以下方式获取文件名 Office context document url 然而 当用户打开一个新工作簿时 它实际上没有文件名 而且奇怪的是 即使保存后 这行代码也不起作用 相反 他们必须保存它
  • 在 UIImage iOS 6.0 的所有四个面上添加阴影

    我正在尝试向 imageView 的所有四个侧面添加阴影 我看到 self shadowView layer shadowOffset CGSizeMake 10 20 在两侧添加阴影 如何在四个面上都添加阴影 刚刚设置shadowOffs
  • 从列表创建变量并全局访问

    我正在编写一个程序 从数据库中提取部门列表 我想避免对此进行硬编码 因为列表可能会发生变化 我想为每个部门创建一个变量 将问题填充到 GUI 中 我遇到的问题是我可以使用 vars 函数从数据库列表中创建变量 然后 我存储变量名称列表 以便
  • Java 相当于 C++ 加密 [重复]

    这个问题在这里已经有答案了 我有以下用于加密的 C 代码片段 EVP CIPHER CTX ctx const EVP CIPHER cipher EVP des ede3 cbc unsigned char iv EVP MAX IV L
  • 如何通过直接链接将 WebCal/iCalendar 添加到 Google 日历

    您可以通过直接链接将 Google 托管的日历添加到您的 Google 日历帐户 例如澳大利亚假期 https www google com calendar embed src en australian 23holiday 40grou
  • 在 makefile 中,目录名是假目标还是“真实”目标?

    根据我所读到的有关 makefile 的内容 虚假目标是指与实际文件名不对应的任何目标 我的直觉表明 作为目标的目录将被视为与文件相同 为什么这很重要 我的 makefile 中有一个目录作为目标 当我将其作为主要可执行文件的先决条件时 无
  • 如何以编程方式访问 NIB 中的 UI 元素而不“连接”它们?

    我正在考虑编写一些辅助函数 以便更轻松地对 iPhone NIB 中的 UI 元素进行简单的更改 主要是 我想通过 Interface Builder 中的名称访问 UILabel 或其他元素 这可能吗 有更聪明的方法吗 Example 假
  • 用于旋转 QWidget 的 QPropertyAnimation

    我是 Qt 新手 遇到一些问题QWidget回转 我在 QLabel 中有一个 QPixmap 我想要的是让它连续旋转 90 度 I know QPropertyAnimation我知道如何使用它 但我正在努力解决如何使用它来旋转QWidg
  • 向下滑动动画Angular 4

    我正在尝试为我的页面添加动画效果 但遇到以下问题 我的页面上有内容 div 以及一个可在内容上方打开另一个 div 的按钮 我希望该 div 淡出并滑入 并且下面的 div 也向下 向上滑动 我为上面的 div 创建了我想要的动画 该动画在
  • 如何删除 JavaScript 数组元素并重置键

    我有一个如下所示的数组 var fields name mark age 23 name smith age 28 name kelvin age 25 name micheal age 22 我知道字段现在将具有索引 键 0 1 2 3
  • 找出哪些超类包含属性或方法实现

    如果我已经正确记录了方法或属性 我可以通过键入找到它的定义位置help class method 这会告诉我Help for class method is inherited from superclass otherclass 通常 这
  • 为什么 Android 中的 Loader 很糟糕

    我读过几条推文和评论 说装载机很糟糕 使用它们是 朝自己脸上开枪 的好方法 还普通人宣布他将停止他的图书馆的任何工作 Loaderex 平民还说 加载器是一个失败的抽象 我显然在这里遗漏了一些东西 我想了解更多信息并了解为什么装载机不好以及
  • 如何删除具有相同imageID的多个docker镜像?

    我创建了一个本地 Docker 注册表 https docs docker com registry deploying 然后从 docker hub 中提取一些 docker 镜像 然后将它们推送到本地注册表 现在我想删除我的本地图像 但
  • QT - 将按钮放在右下角

    我正在尝试放置一组按钮 以便它们固定在屏幕的右下角 我的问题是 每当我调整屏幕大小时 按钮都不会固定在右下角 而是保留在当前位置 我在水平布局中放置了两个按钮 然后 我将此布局放置在网格布局内 其中包含水平和垂直间隔符 我已将网格布局的la
  • AVAudioCompressedBuffer 到 UInt8 数组,反之亦然

    我想知道如何获取 AVAudioCompressedBuffer 的字节 然后 从字节重建 AVAudioCompressedBuffer 下面的代码采用 AVAudioPCMBuffer 使用 AVAudioConverter 将其压缩为