接入环信音视频聊天时,安卓的demo上有来电铃声功能而iOS的demo上并没提供此功能,所以就诞生了本文。
主要看文末的参考文章吧, 懒得重复去描述了。
GitHub:https://github.com/Gamin-fzym/GACallSoundDemo
Demo:https://download.csdn.net/download/u012881779/12084810
[ViewController]
接入铃声功能
#import "ViewController.h"
#import "RBDMuteSwitch.h"
#import "GAMsgBell.h"
@interface ViewController () <RBDMuteSwitchDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[RBDMuteSwitch sharedInstance] setDelegate:self];
}
- (IBAction)callAction:(id)sender {
// 检测”静音模式“是否开启
[[RBDMuteSwitch sharedInstance] detectMuteSwitch];
}
- (IBAction)linkAction:(id)sender {
GAMsgBell *bell = [GAMsgBell sharedMsgBellMethod];
[bell stop];
}
#pragma mark - RBDMuteSwitchDelegate
- (void)isMuted:(BOOL)muted {
if (muted) {
// 当前是[静音模式]
// 若在“设置-声音-开启了静音模式震动”手机才会震动,未开启静音模式震动时手机是静音的,这里就是设置了震动去播放仍然设备是静音的。
NSLog(@"[静音模式]");
GAMsgBell *bell = [GAMsgBell sharedMsgBellMethod];
[bell setupSystemShake];
[bell setupCompletion:soundCompleteCallback];
[bell play];
} else {
// 当前是[响铃模式]
NSLog(@"[响铃模式]");
GAMsgBell *bell = [GAMsgBell sharedMsgBellMethod];
[bell setupSystemSoundWithName:@"iphone6dx" SoundType:@"caf"];
[bell setupCompletion:soundCompleteCallback];
[bell play];
}
}
/**
* 播放完成回调函数
*
* @param soundID 系统声音ID
* @param clientData 回调时传递的数据
*/
void soundCompleteCallback(SystemSoundID soundID, void * clientData) {
NSLog(@"播放完成...");
GAMsgBell *bell = [GAMsgBell sharedMsgBellMethod];
[bell play];
}
@end
[GAMsgBell]
设置震动、系统声音或自定义声音,控制播放和停止。
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import "RBDMuteSwitch.h"
@interface GAMsgBell : NSObject {
SystemSoundID sound; // 系统声音的id 取值范围为:1000-2000
}
+ (id)sharedMsgBellMethod;
// 系统 震动
- (void)setupSystemShake;
// 初始化系统声音、自定义声音
- (void)setupSystemSoundWithName:(NSString *)soundName SoundType:(NSString *)soundType;
// 设置播放完成回调
- (void)setupCompletion:(AudioServicesSystemSoundCompletionProc)completeBlock;
// 停止回调、停止播放
- (void)stop;
// 播放
- (void)play;
@end
#import "GAMsgBell.h"
static GAMsgBell *sharedMsgBell = nil;
@implementation GAMsgBell
+ (id)sharedMsgBellMethod {
@synchronized (self){
if (!sharedMsgBell) {
sharedMsgBell = [[GAMsgBell alloc] init];
}
return sharedMsgBell;
}
return sharedMsgBell;
}
- (void)setupSystemShake {
[self stop];
sound = kSystemSoundID_Vibrate; // 震动
}
- (void)setupSystemSoundWithName:(NSString *)soundName SoundType:(NSString *)soundType {
[self stop];
//NSString *path1 = [NSString stringWithFormat:@"/System/Library/Audio/UISounds/%@.%@",soundName,soundType];
//NSString *path2 = [[NSBundle bundleWithIdentifier:@"com.apple.UIKit" ] pathForResource:soundName ofType:soundType];// 得到苹果框架资源UIKit.framework ,从中取出所要播放的系统声音的路径
//[[NSBundle mainBundle] URLForResource:@"tap" withExtension: @"aif"]; // 获取自定义的声音
NSString *path = [[NSBundle mainBundle] pathForResource:soundName ofType:soundType];
if (path) {
OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path],&sound);
if (error != kAudioServicesNoError) {
// 获取的声音的时候,出现错误
sound = nil;
}
}
}
- (void)setupCompletion:(AudioServicesSystemSoundCompletionProc)completeBlock {
// 如果需要在播放完之后执行某些操作,可以调用如下方法注册一个播放完成回调函数
AudioServicesAddSystemSoundCompletion(sound, NULL, NULL, completeBlock, NULL);
}
- (void)play {
// 铃声静音仍然可播放声音
// [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
AudioServicesPlaySystemSound(sound);
}
- (void)stop {
[[RBDMuteSwitch sharedInstance] stop];
[self stopCompletion];
[self stopPlay];
}
- (void)stopCompletion {
AudioServicesRemoveSystemSoundCompletion(sound);
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}
- (void)stopPlay {
AudioServicesDisposeSystemSoundID(sound);
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
}
@end
[RBDMuteSwitch]
监听iOS设备静音按钮的状态
#import <Foundation/Foundation.h>
#include <AudioToolbox/AudioToolbox.h>
@class RBDMuteSwitch;
@protocol RBDMuteSwitchDelegate
@required
- (void)isMuted:(BOOL)muted;
@end
@interface RBDMuteSwitch : NSObject {
@private
NSObject<RBDMuteSwitchDelegate> *delegate;
float soundDuration;
NSTimer *playbackTimer;
SystemSoundID soundFileObject;
}
/**
Your delegate
*/
@property (readwrite, retain) NSObject<RBDMuteSwitchDelegate> *delegate;
/** Creates a shared instance
*/
+ (RBDMuteSwitch *)sharedInstance;
/** Determines if the device is muted, wait for delegate callback using isMuted: on your delegate.
*/
- (void)detectMuteSwitch;
- (void)stop;
@end
#import "RBDMuteSwitch.h"
static RBDMuteSwitch *_sharedInstance;
@implementation RBDMuteSwitch
@synthesize delegate;
+ (RBDMuteSwitch *)sharedInstance {
if (!_sharedInstance) {
_sharedInstance = [[[self class] alloc] init];
}
return _sharedInstance;
}
- (id)init {
self = [super init];
if (self) {
}
return self;
}
- (void)playbackComplete {
if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
// NSLog(@"playbackComplete >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nsoundDuration %f",soundDuration);
// If playback is far less than 100ms then we know the device is muted
if (soundDuration < 0.001) {
[delegate isMuted:YES];
} else {
[delegate isMuted:NO];
}
}
[playbackTimer invalidate];
playbackTimer = nil;
}
static void soundCompletionCallback (SystemSoundID mySSID, void* myself) {
AudioServicesRemoveSystemSoundCompletion (mySSID);
AudioServicesDisposeSystemSoundID(mySSID);
[[RBDMuteSwitch sharedInstance] playbackComplete];
}
- (void)stop {
AudioServicesRemoveSystemSoundCompletion (soundFileObject);
AudioServicesDisposeSystemSoundID(soundFileObject);
if (playbackTimer) {
[playbackTimer invalidate];
playbackTimer = nil;
}
}
- (void)incrementTimer {
soundDuration = soundDuration + 0.001;
// NSLog(@"incrementTimer>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nsoundDuration %f",soundDuration);
}
- (void)detectMuteSwitch {
#if TARGET_IPHONE_SIMULATOR
// The simulator doesn't support detection and can cause a crash so always return muted
if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
[self.delegate isMuted:YES];
}
return;
#endif
#if !TARGET_IPHONE_SIMULATOR
// iOS 5+ doesn't allow mute switch detection using state length detection
// So we need to play a blank 100ms file and detect the playback length
soundDuration = 0.0;
CFURLRef soundFileURLRef;
// Get the main bundle for the app
CFBundleRef mainBundle;
mainBundle = CFBundleGetMainBundle();
// Get the URL to the sound file to play
soundFileURLRef = CFBundleCopyResourceURL(
mainBundle,
CFSTR ("detection"),
CFSTR ("aiff"),
NULL
);
// Create a system sound object representing the sound file
AudioServicesCreateSystemSoundID (soundFileURLRef,
&soundFileObject
);
AudioServicesAddSystemSoundCompletion (soundFileObject,NULL,NULL,
soundCompletionCallback,
(void*) CFBridgingRetain(self));
// Start the playback timer
playbackTimer = [NSTimer scheduledTimerWithTimeInterval:0.010 target:self selector:@selector(incrementTimer) userInfo:nil repeats:YES];
// NSLog(@"playbackTimer>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nsoundDuration %f",soundDuration);
// Play the sound
AudioServicesPlaySystemSound(soundFileObject);
return;
#endif
}
@end
TO:
iOS开发 AudioServices(音效播放)的使用
https://blog.csdn.net/wgl_happy/article/details/77452716
IOS成长之路-使用系统默认声音、震动
https://blog.csdn.net/like7xiaoben/article/details/9001806
如何监听iOS设备静音按钮的状态
https://www.jianshu.com/p/6db6065b6b3d
【iOS知识学习】_如何判断手机是否为静音模式
https://blog.csdn.net/weasleyqi/article/details/11593313
iOS检测手机是否为振动模式(非铃声模式)
https://blog.csdn.net/hanhailong18/article/details/88313733
iOS中声音播放的各种方法总结
https://www.jianshu.com/p/548afbe49e67
iOS 音频-AVAudioSession
https://www.jianshu.com/p/fb0e5fb71b3c