如何使用Swift在iOS设备生成20kHz特定频率超声波?
嘿,刚好我对iOS音频这块熟,给你一套用Swift生成20kHz超声波的现代方案——那些旧的gist早就跟不上iOS的API更新了,咱用当前iOS推荐的AVAudioEngine来实现,靠谱得多!
用Swift在iOS生成20kHz超声波的实现方案
核心思路
iOS现在处理自定义音频生成,首选AVFoundation框架里的AVAudioEngine,它比旧API更稳定,适配所有主流iOS版本。我们会通过自定义音频源节点实时生成20kHz的正弦波,再通过设备扬声器输出。
步骤1:配置权限与导入框架
首先得搞定权限和基础配置:
- 在
Info.plist里添加音频权限描述:新增NSAudioUsageDescription键,值填类似“需要生成超声波用于设备测试”的说明(iOS 10+强制要求)。 - 在代码文件顶部导入框架:
import AVFoundation
步骤2:实现超声波生成核心代码
下面是完整的可运行代码,我加了详细注释帮你理解:
class UltrasonicGenerator { private let engine = AVAudioEngine() private let targetFrequency: Double = 20000 // 目标20kHz频率 private let sampleRate: Double = 48000 // 选48kHz采样率,更适配高频信号输出 func startGenerating() throws { // 1. 配置音频会话为播放模式 let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playback, mode: .default) try audioSession.setActive(true) // 2. 创建自定义音频源节点,实时生成正弦波 let sourceNode = AVAudioSourceNode { [weak self] _, _, frameCount, audioBufferList -> OSStatus in guard let self = self else { return noErr } let bufferList = UnsafeMutableAudioBufferListPointer(audioBufferList) let totalSamples = Int(frameCount) // 遍历每个音频缓冲区,填充采样数据 for buffer in bufferList { guard let channelData = buffer.mData else { continue } let dataPointer = channelData.assumingMemoryBound(to: Float.self) // 生成20kHz正弦波的每个采样点 for sampleIndex in 0..<totalSamples { let time = Double(sampleIndex) / self.sampleRate let sineValue = sin(2 * .pi * self.targetFrequency * time) dataPointer[sampleIndex] = Float(sineValue) * 0.5 // 降低音量避免高频失真 } } return noErr } // 3. 将源节点添加到引擎并连接到主混音器 engine.attach(sourceNode) let outputFormat = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1) engine.connect(sourceNode, to: engine.mainMixerNode, format: outputFormat) // 4. 启动音频引擎 try engine.start() } func stopGenerating() { engine.stop() do { try AVAudioSession.sharedInstance().setActive(false) } catch { print("停止音频会话失败: \(error.localizedDescription)") } } }
步骤3:在界面中调用生成器
在你的ViewController里可以这样快速测试:
class ViewController: UIViewController { let ultrasonicGenerator = UltrasonicGenerator() override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 先请求音频权限 AVAudioSession.sharedInstance().requestRecordPermission { [weak self] granted in DispatchQueue.main.async { if granted { do { try self?.ultrasonicGenerator.startGenerating() print("已开始输出20kHz超声波") } catch { print("启动失败: \(error.localizedDescription)") } } else { print("需要授予音频权限才能生成超声波") } } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) ultrasonicGenerator.stopGenerating() } }
关键注意事项
- 硬件限制:不是所有iOS设备都能输出20kHz!比如部分旧款iPhone/iPad的扬声器频率上限在18kHz左右,一定要在目标设备上实际测试。
- 无声音提示:20kHz属于超声波,人类耳朵基本听不到,播放时你不会有听觉反馈,可以用频谱分析仪验证输出。
- 后台播放:如果需要在后台持续生成,要在
Info.plist里添加UIBackgroundModes并勾选audio选项。 - 音量调整:代码里把音量降到了0.5倍,是为了避免高频信号导致的音频失真,你可以根据需求微调。
内容的提问来源于stack exchange,提问作者Jonas0000
相关产品推荐
相关产品推荐

