Reputation: 2273
I have an app that uses the AudioServicesPlaySystemSound(1104) method to play a sound on certain tap events. It responds to the state of silent mode vs non-silent mode, and mutes itself accordingly.
However, AudioServicesPlaySystemSound(1150) will play regardless of what state the vibrate switch is in.
How can I check the state of vibrate mode so I can silence the sounds when the user expects it?
Thanks
Upvotes: 2
Views: 1616
Reputation: 31045
There seems to be an open source project that does this. See here for the code and a sample project. The RBDMuteSwitch
is the key class here. You use it (as a singleton), and set your class as a delegate of the RDBMuteSwitch
to get notified of the switch's status. You'll be notified on switch changes, or the first time you call [[RBDMuteSwitch sharedInstance] detectMuteSwitch]
. Tested working on iOS 9.
Here's the important content of the RBDMuteSwitch.m, in case the github link ever dies:
- (void)playbackComplete {
if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
// If playback is far less than 100ms then we know the device is muted
if (soundDuration < 0.010) {
[delegate isMuted:YES];
}
else {
[delegate isMuted:NO];
}
}
[playbackTimer invalidate];
}
static void soundCompletionCallback (SystemSoundID mySSID, void* myself) {
AudioServicesRemoveSystemSoundCompletion (mySSID);
[[RBDMuteSwitch sharedInstance] playbackComplete];
}
- (void)incrementTimer {
soundDuration = soundDuration + 0.001;
}
- (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 __IPHONE_5_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
// 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;
SystemSoundID soundFileObject;
// Get the main bundle for the app
CFBundleRef 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*) self);
// Start the playback timer
playbackTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(incrementTimer) userInfo:nil repeats:YES];
// Play the sound
AudioServicesPlaySystemSound(soundFileObject);
return;
#else
// This method doesn't work under iOS 5+
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if(CFStringGetLength(state) > 0) {
if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
[self.delegate isMuted:NO];
}
}
if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
[self.delegate isMuted:YES];
}
return;
#endif
}
Essentially, what the code does is call AudioServicesPlaySystemSound()
for a silent sound clip of known duration, and tests how long it took to play. If the duration of playback is less than the expected time, that indicates that the Mute switch is on.
Upvotes: 2