MOBILE

Programming the iPhone : Progressive Enhancement - Audio Support

9/22/2012 9:12:44 PM
Many applications provide support for ambient or event-based audio in the form of background music or sound effects. The use of sound is particularly strong in games— both immersive 3D experiences and tile- or sprite-based 2D games. Audio support makes a lot of sense for Cocoa Touch applications. After all, the iPhone is more a descendant of the iPod than a cellular phone, and the iPod Touch is positioned primarily as a media player.

Users often wear headphones when working with the devices, making the barrier to experience quite low. The media player role of the devices can dissuade developers from adding audio support to their applications—after all, when users are wearing headphones, they are likely listening to music or making a phone call and are thus opening an application for some secondary purpose.

There are two approaches to handling audio with Cocoa Touch. The first approach is to interrupt audio playback by other applications. For example, if you develop an application that records sound using the microphone, you may want to stop playback of music running in the iPod application.

The second approach is to mix audio from your application with audio from other running applications, such as the built-in iPod application. This approach treats audio more as an enhancement than a requirement, and is preferable for applications that don’t focus primarily on audio. Using the sound recorder example, you might allow the iPod to continue to play music so that users can record themselves singing along to a song.

You will notice a recurring theme in deciding how to handle various user experience concerns. User expectation should be a particularly significant consideration. Important questions to ask yourself are:

  • How should my application behave if the phone rings?

  • How should my application treat music that is playing when the application is launched?

  • How should my application treat phone calls occurring when the application is launched?

  • What is the best default behavior where sound effects are concerned?

  • What controls should play sound?

  • Should the application respect global settings regarding sound effects?

  • Does the core function of the application depend on users hearing all audio?

  • Are only some sounds essential for the proper use of the application?

The simplest way to play short audio on the iPhone is to use System Sound Services. All sounds played through System Sound Services will mix with audio from other applications and will obey the standard behavior around the hardware Ring/Silent switch and volume rocker. System Sound Services should be used for playing non-essential audio effects, such as startup or alert sounds.

There are two functions for playing sounds through System Sound Services. They are almost identical in their use and operation. The difference is that one function will trigger a vibration in lieu of playing audio if the phone is silenced, whereas the other will not. When choosing these functions, developers should take care to examine user expectations:


void AudioServicesPlaySystemSound (SystemSoundID inSystemSoundID)

Play a sound resource as identified by a SystemSoundID. If the Ring/Silent switch is set to silence the ringer, the sound will not play. This option is preferable for all short, non-essential sounds, such as sound effects for controls or game feedback sounds.


void AudioServicesPlayAlertSound (SystemSoundID inSystemSoundID)

Play a sound resource as identified by a SystemSoundID. If the Ring/Silent switch is set to silence the ringer, the phone will briefly vibrate. This function should be used only when it’s vital to communicate to the user that an event has occurred, because vibration is a disruptive form of feedback that can’t be ignored. If a user has silenced their phone, they likely want to avoid interruptions. Interruptive errors are a good use of this function.

The following example plays an audio response to a network operation. If there is an error, an alert sound—or vibration, if the device is silenced—is played. In a real application, you would probably cache the SystemSoundID variables in your instance:

// Assumes a declaration of instance variables:
// SystemSoundID successSound, errorSound
- (void)performAudioNotificationForStatus:(BOOL)success
{
	NSString *successPath = [[NSBundle mainBundle]
		pathForResource:@"success" ofType:@"caf"];
	NSString *errorPath = [[NSBundle mainBundle]pathForResource:@"failure"
		ofType:@"caf"];
	OSStatus error;
	if(success){
		if(successSound == nil){
			error = AudioServicesCreateSystemSoundID(
				(CFURLRef)[NSURL fileURLWithPath:errorPath],
				&successSound
			);
		}
		AudioServicesPlaySystemSound(successSound);
	}else{
		if(errorSound == nil){
			error = AudioServicesCreateSystemSoundID(
				(CFURLRef)[NSURL fileURLWithPath:successPath],
				&errorSound
			);
		}
		AudioServicesPlayAlertSound(errorSound);
	}
}

- (void)dealloc
{
	AudioServicesDisposeSystemSoundID(successSound);
	AudioServicesDisposeSystemSoundID(errorSound);
	[super dealloc];
}

					  

If an application needs to play sounds longer than 30 seconds or play non-trivial audio, you can take advantage of several more advanced audio playback frameworks and tools:


OpenAL

Used especially for spatial sound programming. OpenAL is popular in game programming or in applications used for playing audio with spatial variation. The OpenAL FAQ for iPhone OS, bundled with the iPhone SDK documentation, is a good starting point for learning about OpenAL.


Audio Queue Services

Used as a straightforward way to record or play audio. The Audio Queue Services Programming Guide, bundled with the iPhone SDK documentation, is an excellent resource for learning more about Audio Queue Services.


AVAudioPlayer class

The AVAudioPlayer class, bundled with a delegate protocol, was added to iPhone OS 2.2 as part of the AVFoundation framework. The AVAudioPlayer class provides robust functionality around playing audio files. Developers can use the class to play multiple sounds, play sounds with distinct levels, loop sounds, seek through files during playback, and gather data that can be used in visualizing the power levels of audio channels. The AVAudioPlayerDelegate protocol defines methods used for handling interruptions to playback, such as from an incoming phone call, along with expected error, start, and stop events.


Audio units

Audio units are audio processing plug-ins. You can read about audio units in the Audio Unit Component Services Reference in the iPhone SDK documentation.

When using any of these more complex audio programming resources, you can control the way your sounds mix with other applications using audio sessions. The Audio Session Services Reference documentation, included with the iPhone SDK, describes the use of audio sessions. Audio sessions are used to define the conditions of operation for audio handling on the iPhone OS. Each application is given an audio session object that acts as an intermediary between the application and the operating system. Developers set properties of the audio session for their application to define how the iPhone OS should make decisions about audio playback in response to the myriad conditions that affect the mobile user experience. Typical events with consequences for audio playback are:

  • Incoming phone calls

  • Terminating phone calls

  • Playing music with the iPod application

  • User interaction with the Ring/Silence switch

  • Users switching between the headphone jack output and the built-in speaker

  • Users interacting with the Sleep/Wake button

  • The auto-sleep timer expires and the device goes to sleep

There are lots of ways to customize audio sessions, and Apple has provided several preset collections of settings—called categories—that solve the most common use cases. Though only one category can be assigned to an audio session at any given time, the category is mutable and can be changed for different circumstances. The audio session categories and the corresponding UInt32 constant used to set the category are:


UserInterfaceSoundEffects

Used for applications that provide simple, short, user-initiated sound effects, such as keyboard taps or startup sounds. Sounds will mix with audio from other applications and will obey the Ring/Silent switch. Identified by kAudioSessionCate⁠gory_UserInterfaceSoundEffects.


AmbientSound

Used for slightly longer sounds that can safely obey the Ring/Silent switch without hindering the core functionality of the application. Sounds will mix with audio from other applications and will obey the Ring/Silent switch. Identified by kAudioSessionCategory_AmbientSound.


SoloAmbientSound

Used similarly to the AmbientSound category, except that the audio does not mix with audio from other applications. Identified by kAudioSessionCategory_SoloAmbientSound.


MediaPlayback

Used for audio or audio/video playback. All other applications are silenced. MediaPlayback sounds do not obey the Ring/Silent switch. Identified by kAudioSessionCategory_MediaPlayback.


LiveAudio

Used for applications that simulate music instruments, audio generators, or signal processors. All other applications are silenced. LiveAudio sounds do not obey the Ring/Silent switch. Identified by kAudioSessionCategory_LiveAudio.


RecordAudio

Used for applications that record audio. All other applications are silenced. RecordAudio sounds do not obey the Ring/Silent switch. Identified by kAudioSessionCate⁠gory_RecordAudio.


PlayAndRecord

Used for applications that both play and record audio. All other applications are silenced. PlayAndRecord sounds do not obey the Ring/Silent switch. Identified by kAudioSessionCategory_PlayAndRecord.

Setting a category isn’t difficult. This example sets a session to the AmbientSound category:

- (void)prepareAmbientAudio
{
	OSStatus result = AudioSessionInitialize(NULL, NULL, NULL, self);
	if(result){
		NSLog(@"Ambient audio could not be prepared. Consider this suspicious.");
	}else {
		UInt32 category = kAudioSessionCategory_AmbientSound;
		result = AudioSessionSetProperty(
			kAudioSessionProperty_AudioCategory,
			sizeof(category),
			&category
		);
		if(result){
			NSLog(@"Could not set audio session category. This is no good. Fix it!");
		}else {
			result = AudioSessionSetActive(true);
			if(result){
				NSLog(@"Could not set audio session to active status. Fix it!");
			}
		}
	}
}


					  

Audio programming possibilities on the iPhone are shockingly robust for a mobile device. Of course, with great power comes great responsibility—so be considerate of user expectations when adding audio to applications, but don’t hesitate to create innovative applications. Let users decide how and when audio should contribute to their experience.

NOTE

Like sound, vibration can be either an excellent enhancement or an annoying deal breaker for users of an application. The mobile HIG describes user expectations as they relate to vibration, and Apple advises developers to use vibration only when appropriate. You can trigger vibration by calling the AudioServicesPlaySystemSound function and passing a constant SystemSoundID called kSystemSoundID_Vibrate:

- (void)vibrate
{
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
Other  
  •  Programming the iPhone : Progressive Enhancement - Accelerometer Support, Rotation Support
  •  Emergency Phone : Spareone
  •  Ipad : Wireless Sync Using the MobileMe Service (part 4) - Using MobileMe After Setup, How to Cancel Your MobileMe Account
  •  Ipad : Wireless Sync Using the MobileMe Service (part 3) - Set Up Your iPad to Access Your MobileMe Account
  •  Ipad : Wireless Sync Using the MobileMe Service (part 2) - Set Up MobileMe on Your Windows PC
  •  Ipad : Wireless Sync of Your Google or Exchange Information (part 2) - Working With the Google or Exchange Contacts and Calendar on your iPad
  •  Ipad : Wireless Sync of Your Google or Exchange Information (part 1) - Set Up your iPad to Access Your Google or Exchange Account
  •  Microsoft Surface and Its Competitors
  •  The Differences Between Samsung Galaxy Note 10.1 And Galaxy Tab
  •  The Life After MobileMe (Part 2) - How to choose a new webhost once MobileMe has been closed
  •  
    Most View
    Too Close To Call
    What Can You Buy For Under $160? (Part 2)
    Lifestyle – Access All Areas: Apple and Its Assistive Technologies
    Zotac GeForce GTX TITAN AMP! Edition 6 GB And TITAN Graphics Cards (Part 3)
    Introducing UEFI BIOS (Part 2)
    Choice Exotica Well Tempered Versalex Turntable (Part 2)
    Ultimate Guide To Nexus (Part 2)
    Sharepoint 2013 : Visio Graphics Services (part 1) - Configure the Unattended Service Account, Create a New Safe Data Provider
    Windows Server 2003 : Administering Software Update Services (part 3) - Synchronizing SUS, Approving Updates
    Desktop Speaker Test - Rockin’ 9 to 5 (Part 1) : AQ Audio SmartSpeaker A1
    Top 10
    Mitsubishi Hybrids – One Direction
    Race To The Clouds – Honda R&D’S ’91 NSX (Part 2)
    Race To The Clouds – Honda R&D’S ’91 NSX (Part 1)
    Volkswagen Plug-In Hybrid Up – Double Act
    Pre/Power Amplifier Marantz SA8005/PM8005 Review (Part 2)
    Pre/Power Amplifier Marantz SA8005/PM8005 Review (Part 1)
    Smart TV Finlux 50FME242B-T Review (Part 2)
    Smart TV Finlux 50FME242B-T Review (Part 1)
    The Best Money Can Buy: Motherboards (Part 2) - Asus Rampage IV Black Edition, Asus Crosshair V Formula-Z
    The Best Money Can Buy: Motherboards (Part 1) - ASRock X79 Extreme 11, Asus Intel Z97 ROG Bundle, Gigabyte Z97X-GAMING G1