当前位置: > > > Swift - 系统声音服务的使用(播放声音,提醒,震动)

Swift - 系统声音服务的使用(播放声音,提醒,震动)

(本文代码已升级至Swift4)

1,系统声音服务介绍:
系统声音服务提供了一个 Api,用于播放不超过 30 秒的声音。它支持的文件格式有限,具体的说只有 CAFAIF 和使用 PCM 或 IMA/ADPCM 数据的 WAV 文件。
但此函数没有提供操作声音和控制音量的功能,因此如果是要为多媒体或游戏创建专门声音,就不要使用系统声音服务。

2,系统声音服务支持如下三种类型
(1)声音:立刻播放一个简单的声音文件。如果手机静音,则用户什么也听不见。
(2)提醒:播放一个声音文件,如果手机设为静音或震动,则通过震动提醒用户。
(3)震动:震动手机,而不考虑其他设置。

3,使用样例(首先类中要引入AudioToolbox)
import AudioToolbox
(1)声音播放
@IBAction func systemSound(_ sender: Any) {
    //建立的SystemSoundID对象
    var soundID:SystemSoundID = 0
    //获取声音地址
    let path = Bundle.main.path(forResource: "msg", ofType: "wav")
    //地址转换
    let baseURL = NSURL(fileURLWithPath: path!)
    //赋值
    AudioServicesCreateSystemSoundID(baseURL, &soundID)
    //播放声音
    AudioServicesPlaySystemSound(soundID)
}

(2)提醒
@IBAction func systemAlert(_ sender: Any) {
    //建立的SystemSoundID对象
    var soundID:SystemSoundID = 0
    //获取声音地址
    let path = Bundle.main.path(forResource: "msg", ofType: "wav")
    //地址转换
    let baseURL = NSURL(fileURLWithPath: path!)
    //赋值
    AudioServicesCreateSystemSoundID(baseURL, &soundID)
    //提醒(同上面唯一的一个区别)
    AudioServicesPlayAlertSound(soundID)
}

(3)振动
@IBAction func systemVibration(sender: AnyObject) {
	//建立的SystemSoundID对象
	let soundID = SystemSoundID(kSystemSoundID_Vibrate)
	//振动
	AudioServicesPlaySystemSound(soundID)
}

4,声音或提醒播放完毕后的回调函数
默认情况下每触发一次声音提醒,系统就会执行一次。不管当前是否有其他的声音提醒未播放完毕。这样如果提醒声音时间比较长,在短时间内多次触发,那么就会造成重音(多个声音叠加在一起)。
我们可以设置个状态变量,播放前先根据它来判断是否要播放。同时使用 AudioServicesAddSystemSoundCompletion() 函数添加个声音播放完毕的回调。在开始播放、播放完毕中修改这个状态变量即可。
import UIKit
import AudioToolbox

class ViewController: UIViewController {
    
    //表示当前是否在播放
    var isPlaying = false

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func btn(_ sender: Any) {
        if !isPlaying {
            //建立的SystemSoundID对象
            var soundID:SystemSoundID = 0
            //获取声音地址
            let path = Bundle.main.path(forResource: "msg", ofType: "wav")
            //地址转换
            let baseURL = NSURL(fileURLWithPath: path!)
            //赋值
            AudioServicesCreateSystemSoundID(baseURL, &soundID)
            
            //添加音频结束时的回调
            let observer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
            AudioServicesAddSystemSoundCompletion(soundID, nil, nil, {
                (soundID, inClientData) -> Void in
                let mySelf = Unmanaged<ViewController>.fromOpaque(inClientData!)
                    .takeUnretainedValue()
                mySelf.audioServicesPlaySystemSoundCompleted(soundID: soundID)
            }, observer)
            
            //播放声音
            AudioServicesPlaySystemSound(soundID)
            isPlaying = true
        }
    }
    
    //音频结束时的回调
    func audioServicesPlaySystemSoundCompleted(soundID: SystemSoundID) {
        print("Completion")
        isPlaying = false
        AudioServicesRemoveSystemSoundCompletion(soundID)
        AudioServicesDisposeSystemSoundID(soundID)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
评论9
  • 9楼
    2017-12-13 22:54
    Peter

    站长你好:
    这一句始终报错,望指点迷津
    AudioServicesAddSystemSoundCompletion(soundID, nil, nil, proc,
    UnsafeMutablePointer(unsafeAddressOf(self)))
    错误提示:
    Cannot invoke initializer for type 'UnsafeMutablePointer<_>' with an argument list of type '(UnsafeRawPointer)'

    站长回复

    文章代码现已更新,你可以再看下。

  • 8楼
    2016-07-14 12:34
    Star

    站长,我想问下有没有播放字符串的框架啊(不传url传的是字符串,传什么播放什么)

    站长回复

    不太确定你的意思。你是指将字符串文本朗读出来吗?

  • 7楼
    2016-05-26 10:00

    謝謝站長花時間寫教學並且分享
    感恩囉^^

    站长回复

    不客气,欢迎常来看看:)

  • 6楼
    2016-03-18 15:15
    jelly

    模拟器有声音,真机没有声音是什么问题..

    站长回复

    是不是因为你手机静音了。我试了下真机是没问题的。

  • 5楼
    2016-02-17 10:52
    linchan

    站长你好,如果不断的触发系统声音,提醒等播放按钮,会出现重音,怎么判断系统声音播放完毕呢?

    站长回复

    AudioServicesAddSystemSoundCompletion()方法可以实现,我在文章的最后写了个样例,你可以参考下。

  • 4楼
    2016-02-05 21:57
    学习

    AudioServicesCreateSystemSoundID(baseURL, &soundID)
    soudID 有错误,求解

    cannot convert value of type 'SystemSoundID'(aka 'Uint32'')

    站长回复

    soundID要使用var定义,文章已修改。

  • 3楼
    2015-12-14 13:44
    action

    嗯,感谢站长回复。可能是我没有设置好。
    WARNING: 998: Failure to setup sound, err = -50
    上面是错误信息
    下面是代码
    button_Shake.addTarget(self, action: Selector("systemVibration"), forControlEvents: UIControlEvents.TouchUpInside)
    func systemVibration() {
    let soundID = SystemSoundID(kSystemSoundID_Vibrate)
    AudioServicesPlaySystemSound(soundID)
    }
    直接写的。是不是在模拟器上不能运行啊,我在模拟器上运行的。

    站长回复

    是的,震动必须使用真机测试。你写的代码是没问题的。

  • 2楼
    2015-12-13 12:42
    action

    点震动报错

    2015-12-13 12:41:45.239 test[2173:101795] -[test.Audio_1 systemVibration]: unrecognized selector sent to instance 0x7fabda522620
    2015-12-13 12:41:45.245 test[2173:101795] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[test.Audio_1 systemVibration]: unrecognized selector sent to instance 0x7fabda522620'
    *** First throw call stack:

    站长回复

    测试了下代码没问题呀。你试试看把震动的两行代码注释掉看还会不会报错,看错误信息像是响应事件有问题

  • 1楼
    2015-11-30 09:50
    邵邵

    很感谢

    站长回复

    不客气^_^