Detecting iPhone/iPod Touch Accessories - iphone

Is it possible to detect if the iPod Touch/iPhone has any headphones or other accessories connected to it?
I'm building an app that requires a microphone, and need to know if the "iSomething" has one connected or not, either via the dock connection, or using the headphone port, such as with the inline headphone/microphone accessory from Apple.

Finally found it - After initializing the Audio Session object, - AudioSessionInitialize() - you can make a call to AudioSessionGetProperty, and get the value of kAudioSessionProperty_AudioInputAvailable.
AudioSessionInitialize(NULL, NULL, NULL, NULL);
UInt32 propertySize, micConnected;
AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &propertySize, &micConnected);
[self updateMicStatus:micConnected]; // user-created method
According to the docs for Audio Session Services, this should be used rather than using the device model (iPhone vs. iPod Touch) to determine if an audio input is available to use. You can also set up a callback function to monitor changes to this property via AudioSessionAddPropertyListener().
Not sure yet if this property also applies to devices connected via the Dock connector, but it appears to work for the headphone jack.

Or you could use:
if (![[AVAudioSession sharedInstance] inputIsAvailable]) {
// your code here for no audio input available
}

In IOS 6 inputIsAvailable is deprecated. In the future we need to use inputAvailable:
BOOL audioHWAvailable = audioSession.inputAvailable;

To determine if the device has a built in microphone you can just go by [UIDevice currentDevice].model to see if it's an iPhone or a 2nd generation iPod Touch. As far as a third-party microphone plugged into the dock connector, this is not possible in the current 2.2.1 SDK, but it may be in a later version :)

Here is the solution, you may like it or it is helpful to you.
Before using below method please write this two line also
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
- (void)isHeadsetPluggedIn {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route);
//NSLog(#"Error >>>>>>>>>> :%#", error);
/* Known values of route:
* "Headset"
* "Headphone"
* "Speaker"
* "SpeakerAndMicrophone"
* "HeadphonesAndMicrophone"
* "HeadsetInOut"
* "ReceiverAndMicrophone"
* "Lineout"
*/
NSString* routeStr = (NSString*)route;
NSRange headsetRange = [routeStr rangeOfString : #"Headset"];
NSRange receiverRange = [routeStr rangeOfString : #"Receiver"];
if(headsetRange.location != NSNotFound) {
// Don't change the route if the headset is plugged in.
NSLog(#"headphone is plugged in ");
}
else if (receiverRange.location != NSNotFound) {
// Change to play on the speaker
NSLog(#"play on the speaker");
}
else {
NSLog(#"Unknown audio route.");
}
}

Related

How to check if sound off on iphone [duplicate]

I am developing an application. In that i want to detect through coding that "is iPhone on silent mode or not?". I am developing it by using cocoa with Objective-C.
If anyone knows it kindly reply.
The reason Pirripli's code does not work is that the simulator does not support the test and the code does not check for errors. Corrected code would look like:
CFStringRef state = nil;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if (status == kAudioSessionNoError)
{
return (CFStringGetLength(state) == 0); // YES = silent
}
return NO;
It's possible by testing for a NULL audio route using AudioToolBox:
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
AudioSessionGetProperty (
kAudioSessionProperty_AudioRoute,
&routeSize,
&route
);
if (route == NULL) {
NSLog(#"Silent switch is on");
}
If route is NULL then there's no available audio outputs. If it's "Headset" or "Headphones" then the silent ringer switch could still be on. However, it will never be on when it's set to "Speaker".
You're probably best testing for this in your audio route change property listener, which is set below:
AudioSessionAddPropertyListener (
kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
self
);
Note: If you're doing anything funky like overriding audio routes, then this answer may not apply.
Setting up and tearing down an audio session in its entirety is probably beyond the scope of this answer.
For completeness, building off this link from Dan Bon, I implement the following method to solve this problem in my apps. One thing to note is that the code checks for the iPhone simulator first - executing the below code will crash the simulator. Anyone know why?
-(BOOL)silenced {
#if TARGET_IPHONE_SIMULATOR
// return NO in simulator. Code causes crashes for some reason.
return NO;
#endif
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if(CFStringGetLength(state) > 0)
return NO;
else
return YES;
}
Declaring this right in the view controller, you'd simply check
if ([self silenced]) {
NSLog(#"silenced");
else {
NSLog(#"not silenced");
}
Or, obviously, you could declare it in some kind of helper class. A more elegant solution might be a category addition on UIApplication or some such other class...
You can use Audio Route property as suggested by the previous answers, but keep in mind that:
- It works only if the Audio Category is AmbientSound
- You should not initialize Audio Session more than once in your app (see Audio Session Programming Guide)
- You should release those CFStringRef to avoid mem leaks
In case the current audio category is not AmbientSound though, you can think of changing it temporarily, perform the check on Audio Route property, and then restoring the original Audio Category.
Note that changing Audio Category will restore the default Audio Route for that category, given the current hardware configuration (i.e. whether there are headphones plugged in or not, etc).

How can I mute incoming iPhone text messages programmatically?

I'm currently trying to use the AVSystemController private framework to mute system noises based on the user's selection. I'm currently muting phone calls by calling: [(AVSystemController object) setVolumeTo:0.0 forCategory:#"Ringtone"];
Is there a command to do that for incoming text messages? I imagine it would be based on a change in the category identified in that call. However, I can't find a list of categories to reference. Of the 10 I've been able to find (Alert, Audio/Video, Ringtone, Voicemail, VoicemailGreeting, PhoneCall, TTYCall, RingtonePreview, Alarm, Record), none of them govern text message sounds. Is there a category to do this? If not, is there any other way to mute the sound from incoming texts?
I realize this goes against Apple's no-private-frameworks policy, but this app won't go up on the app store so that's no problem. I'm developing it using the latest version of Xcode for the latest version of IOS, so any method to accomplish this would be doable.
#Jessica, You can't do that, bcos it's restricted. if you want to try it in your application, then your app might be Rejected in App store.
So, Using public APIs, it is not possible.
The link you found is using private APIs, which aren't documented or guaranteed to work the way you'd expect. If you tried to release an App Store app that called a private API, it would be automatically rejected.
if you want to Check , whether is silent or not, then use below code,
-(BOOL)silenced {
#if TARGET_IPHONE_SIMULATOR
// return NO in simulator. Code causes crashes for some reason.
return NO;
#endif
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if(CFStringGetLength(state) > 0)
return NO;
else
return YES;
}
For completeness, building off this link from Dan Bon, I implement the following method to solve this problem in my apps. One thing to note is that the code checks for the iPhone simulator first - executing the below code will crash the simulator. Anyone know why?
-(BOOL)silenced {
#if TARGET_IPHONE_SIMULATOR
// return NO in simulator. Code causes crashes for some reason.
return NO;
#endif
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if(CFStringGetLength(state) > 0)
return NO;
else
return YES;
}
Declaring this right in the view controller, you'd simply check
if ([self silenced]) {
NSLog(#"silenced");
else {
NSLog(#"not silenced");
}

Can I determine / how, if a device has vibration or not?

I have some settings that enable/disable vibration for certain actions, but I find it pointless to display them if the device doesn't have the ability to vibrate. Is there a way to check if the person is using an iPod touch and if it has vibration?
I'm not sure there is a way to do this other than doing model checks which is probably not a great approach. I do know that apple provides:
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
If the device can vibrate, it will. On devices without vibration, it will do nothing. There is another call:
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
This one will vibrate the device if it hash the capability or the device will beep.
It might be better to just have the settings and have some explanation around the setting because a user may want the beep when they do not have a vibrating device. Maybe call the setting something other than "Vibration Alert On/Off".
This code should do it - be aware it 'assumes' the iPhone is the only device with Vibration capability. Which it is for the moment...
- (NSString *)machine
{
static NSString *machine = nil;
// we keep name around (its like 10 bytes....) forever to stop lots of little mallocs;
if(machine == nil)
{
char * name = nil;
size_t size;
// Set 'oldp' parameter to NULL to get the size of the data
// returned so we can allocate appropriate amount of space
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
// Allocate the space to store name
name = malloc(size);
// Get the platform name
sysctlbyname("hw.machine", name, &size, NULL, 0);
// Place name into a string
machine = [[NSString stringWithUTF8String:name] retain];
// Done with this
free(name);
}
return machine;
}
-(BOOL)hasVibration
{
NSString * machine = [self machine];
if([[machine uppercaseString] rangeOfString:#"IPHONE"].location != NSNotFound)
{
return YES;
}
return NO;
}
Just edited to stop the machine call from doing lots of small mallocs each time its called.

How do you force audio to come out of the iPhone speaker when a headset is attached?

I'm trying to add a loudspeaker feature to one of my iPhone apps. I already created the recording functionality, but when I play the recorded audio it only plays to the phone headset.
What I need is the recorded file to be played on the loudspeaker, even if there is a headset attached. How could I reroute the audio to do this?
You need to override the default audio properties using AudioSessionSetProperty. Look at something like this to force all audio to go to the speaker (note that this will even happen if headphones are plugged in).
OSStatus err = 0;
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
err = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute,sizeof(audioRouteOverride),&audioRouteOverride);
To detect the headphones, try this (this is literally copy/paste code off of another SO post, so caveat emptor, but it works for me):
/**
* Tells us if the headset is plugged in
*/
- (BOOL) headsetIsPluggedIn
{
BOOL returnVal = NO;
UInt32 routeSize = sizeof(CFStringRef);
CFStringRef route = NULL;
OSStatus error = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route);
if (!error && (route != NULL) && ([(NSString*)route rangeOfString:#"Head"].location != NSNotFound))
{
CFRelease(route);
returnVal = YES;
}
return returnVal;
}
EDIT: There is a bit of a discussion in the comments about whether the CFRelease is appropriate or not. Any hardcore Core Foundation experts care to weigh in?

How can I detect if headphones are connected to an iPod touch G1?

There are many articles on how to detect if a microphone is connected to an iPod touch G2 via AudioSessionGetProperty / kAudioSessionProperty_AudioInputAvailable, but I have not seen any articles related to detection of headphones connected to an iPod touch G1.
To review:
iPod touch G2 hardware differs from iPod touch G1 hardware in the following ways:
iPod touch G2 has an internal speaker
iPod touch G2 is able to use microphone off of headphone port
I have an app that needs to play sound to be useful and I want to be nice and have a detector that shows that the app is useful once they connect up some headphones.
My initial trials show that the AudioSession APIs (and specifically the AudioSessionGetProperty with the kAudioSessionProperty_AudioRoute constant) always reports back 'Headphone' even if headphones are not connected to an iPod touch G1.
Am I missing something? Do I have something cross wired with my AudioSession calls? If anyone has tried this on an iPod touch G1 and got a different result? Is there another way to weave through AudioSession APIs and get what I am after?
This is all against iPhone OS 3.0 and the iPhone OS 3.0 SDK on real iPod touch G1 hardware.
Thanks in advance,
--Batgar
you can easily get with this method:
- (BOOL)isHeadsetPluggedIn {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route);
if (!error && (route != NULL) && ([route isEqual:#"HeadsetInOut"])) {
return YES;
}
return NO;
}
Check it.
http://developer.apple.com/iphone/library/samplecode/SpeakHere/index.html#//apple_ref/doc/uid/DTS40007802
Here is the source code of sound recording which have support for pausing playback when headphones are removed, this may help you.
The kAudioSessionProperty_AudioRoute will always return headphones in the 1st gen since there are no other routes. The 2nd gen and iphone and above all will support another route (speaker) when the headphones are unplugged, but there's note another route in the 1st gen.
At least with this documented API call you are using, you will not be able to detect the 1st gen ipod headphone state.
From SpeakHere
error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable);
if (error) printf("ERROR GETTING INPUT AVAILABILITY! %d\n", error);
btn_record.enabled = (inputAvailable) ? YES : NO;
Above answer does not work as it Does not compile , So i am posting this as this might help some one . All you need to do is to find the audio route . Following are the possible routes for the audio
Known values of route:
"Headset"
"Headphone"
"Speaker"
"SpeakerAndMicrophone"
"HeadphonesAndMicrophone"
"HeadsetInOut"
"ReceiverAndMicrophone"
"Lineout"
Hope this helps
- (BOOL)isHeadsetPluggedIn {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route);
if (!error && (route != NULL)) {
NSString* routeStr = (__bridge NSString*)route; //Convert CFStringRef to NSString
NSRange routeRange = [routeStr rangeOfString:#"Head"];
if (routeRange.location != NSNotFound){
return YES;
}
}
return NO;
}