最近在做视频通话,在拨打/接听的时候需要响铃、震动,播放音频的方式有几种,但是最后还是选择了AudioServices来做。
1.因为我们的视频文件时长小于30S,AudioServices只能使用时长为30S之内的音频文件,目前只试过.caf是可行的
2.需求简单,只需要响铃和震动,不用监听各种属性和方法
3.实现方便快捷
实现步骤:
- 1.创建系统声音服务
- 2.注册铃声和震动完成的回调
- 3.开始播放
- 4.结束播放
- 5.循环播放
实现方法解析
使用系统声音服务(AudioService)创建一个实例
/*!
@functiongroup AudioServices
*/
/*!
@function AudioServicesCreateSystemSoundID // 创建一个系统声音
@abstract Allows the application to designate an audio file for playback by the System Sound server.
//允许应用程序指定一个音频文件供系统声音服务器播放
@discussion Returned SystemSoundIDs are passed to AudioServicesPlayAlertSoundWithCompletion()
and AudioServicesPlaySystemSoundWithCompletion() to be played.
The maximum supported duration for a system sound is 30 secs.
@param inFileURL
A CFURLRef for an AudioFile.
@param outSystemSoundID
Returns a SystemSoundID.
*/
extern OSStatus
AudioServicesCreateSystemSoundID( CFURLRef inFileURL,
SystemSoundID* outSystemSoundID)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0))
;
可以看到需要的参数是一个CFURLRef类型的URL,和一个 (SystemSoundID*) ,要什么给什么:
//全局变量
static SystemSoundID sound;
//注意这里的类型,目前只测试过caf类型的可用,其他的自己去测试
NSString *path = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"caf"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &sound);
我们从本地获取的文件路径转成URL之后,用(__bridge CFURLRef)桥接一下,SystemSoundID* 就取&sound就行了。
注册
/*!
This function will be deprecated in a future release. Use AudioServicesPlayAlertSoundWithCompletion
or AudioServicesPlaySystemSoundWithCompletion instead.
@function AudioServicesAddSystemSoundCompletion
@abstract Call the provided Completion Routine when provided SystemSoundID
finishes playing.
@discussion Once set, the System Sound server will send a message to the System Sound client
indicating which SystemSoundID has finished playing.
@param inSystemSoundID
The SystemSoundID to associate with the provided completion
routine.
@param inRunLoop
A CFRunLoopRef indicating the desired run loop the completion routine should
be run on. Pass NULL to use the main run loop.
@param inRunLoopMode
A CFStringRef indicating the run loop mode for the runloop where the
completion routine will be executed. Pass NULL to use kCFRunLoopDefaultMode.
@param inCompletionRoutine
An AudioServicesSystemSoundCompletionProc to be called when the provided
SystemSoundID has completed playing in the server.
@param inClientData
A void* to pass client data to the completion routine.
*/
extern OSStatus
AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID,
CFRunLoopRef __nullable inRunLoop,
CFStringRef __nullable inRunLoopMode,
AudioServicesSystemSoundCompletionProc inCompletionRoutine,
void * __nullable inClientData)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0))
;
inSystemSoundID 系统声音ID
** inRunLoop 一般传NULL**
** inRunLoopMode 一般传NULL**
** inCompletionRoutine 注册完成的回调**
** inClientData 一般传NULL**
//分别注册铃声和震动完后的回调
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, NULL, NULL, vibrationCompleteCallback, NULL);
AudioServicesAddSystemSoundCompletion(sound, NULL, NULL, soundCompleteCallback, NULL);
开始播放系统声音
/*!
This function will be deprecated in a future release. Use AudioServicesPlaySystemSoundWithCompletion instead.
@function AudioServicesPlaySystemSound
@abstract Play the sound designated by the provided SystemSoundID.
@discussion A SystemSoundID indicating the desired System Sound to be played.
@param inSystemSoundID
A SystemSoundID for the System Sound server to play.
*/
extern void
AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0))
;
inSystemSoundID 系统声音ID
//开始震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
//开始播放铃声
AudioServicesPlaySystemSound(sound);
移除回调
/*!
This function will be deprecated in a future release. Use AudioServicesPlayAlertSoundWithCompletion
or AudioServicesPlaySystemSoundWithCompletion instead.
@function AudioServicesRemoveSystemSoundCompletion
@abstract Disassociate any completion proc for the specified SystemSoundID
@discussion Tells the SystemSound client to remove any completion proc associated with the
provided SystemSoundID
@param inSystemSoundID
The SystemSoundID for which completion routines should be
removed.
*/
extern void
AudioServicesRemoveSystemSoundCompletion(SystemSoundID inSystemSoundID)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0))
;
inSystemSoundID 需要移除的系统声音ID
//移除震动回调
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
//移除声音回调
AudioServicesRemoveSystemSoundCompletion(sound);
清除铃声和震动
/*!
@function AudioServicesDisposeSystemSoundID
@abstract Allows the System Sound server to dispose any resources needed for the provided
SystemSoundID.
@discussion Allows the application to tell the System Sound server that the resources for the
associated audio file are no longer required.
@param inSystemSoundID
A SystemSoundID that the application no longer needs to use.
*/
extern OSStatus
AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0))
;
inSystemSoundID 需要清除的系统声音ID
//清除震动
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
//清除铃声
AudioServicesDisposeSystemSoundID(sound);
AudioServices基本上使用就这个流程,更加全面的使用没有尝试过,还请大神指教。
下面放上代码:
#import
NS_ASSUME_NONNULL_BEGIN
@interface AudioServicesPlaySounds : NSObject
- (void)startAudioToolWork;
- (void)stopAudioToolWork;
@end
NS_ASSUME_NONNULL_END
#import "AudioServicesTool.h"
@implementation AudioServicesTool
//全局变量
static SystemSoundID sound;
//开始播放的时候调用
- (void)startAudioToolWork {
NSString *path = [[NSBundle mainBundle] pathForResource:@"music1" ofType:@"caf"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &sound);
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, NULL, NULL, vibrationCompleteCallback, NULL);
AudioServicesAddSystemSoundCompletion(sound, NULL, NULL, soundCompleteCallback, NULL);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(sound);
}
- (void)stopAudioToolWork {
stopRingAndVibration();
}
void stopRingAndVibration() {
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
AudioServicesRemoveSystemSoundCompletion(sound);
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
AudioServicesDisposeSystemSoundID(sound);
}
void vibrationCompleteCallback(SystemSoundID sound,void * clientData) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(800 * NSEC_PER_MSEC)), dispatch_get_global_queue(0, 0), ^{
AudioServicesPlaySystemSound(sound);
});
}
void soundCompleteCallback(SystemSoundID sound,void * clientData) {
// 单次播放
// stopRingAndVibration();
//循环播放
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(sound);
}
@end
使用方式
@interface ViewController()
@property (nonatomic, strong) AudioServicesTool *playSound;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.playSound startAudioToolWork];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.playSound stopAudioToolWork];
}
#pragma mark - Getter
- (AudioServicesTool *)playSound {
if (!_playSound) {
_playSound = ({
AudioServicesTool *sound = [[AudioServicesTool alloc] init];
sound;
});
}
return _playSound;
}
@end