这是可能的 AVPlayer 从 MPMusicPlayerController 的 ipodlibrary 获取音乐并播放吗,因为 avplayer 无法从 MPMusicPlayerController 访问 iPodMusicPlayer,因为 AVPlayer 支持后台播放和访问 remoteEvents。下面显示的代码来自 addMusic 项目。所以任何帮助将不胜感激。谢谢
void audioRouteChangeListenerCallback (
void *inUserData,
AudioSessionPropertyID inPropertyID,
UInt32 inPropertyValueSize,
const void *inPropertyValue
) {
// ensure that this callback was invoked for a route change
if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;
// This callback, being outside the implementation block, needs a reference to the
// MainViewController object, which it receives in the inUserData parameter.
// You provide this reference when registering this callback (see the call to
// AudioSessionAddPropertyListener).
MainViewController *controller = (MainViewController *) inUserData;
// if application sound is not playing, there's nothing to do, so return.
if (controller.appSoundPlayer.playing == 0 ) {
NSLog (@"Audio route change while application audio is stopped.");
return;
} else {
// Determines the reason for the route change, to ensure that it is not
// because of a category change.
CFDictionaryRef routeChangeDictionary = inPropertyValue;
CFNumberRef routeChangeReasonRef =
CFDictionaryGetValue (
routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_Reason)
);
SInt32 routeChangeReason;
CFNumberGetValue (
routeChangeReasonRef,
kCFNumberSInt32Type,
&routeChangeReason
);
// "Old device unavailable" indicates that a headset was unplugged, or that the
// device was removed from a dock connector that supports audio output. This is
// the recommended test for when to pause audio.
if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
[controller.appSoundPlayer pause];
NSLog (@"Output device removed, so application audio was paused.");
UIAlertView *routeChangeAlertView =
[[UIAlertView alloc] initWithTitle: NSLocalizedString (@"Playback Paused", @"Title for audio hardware route-changed alert view")
message: NSLocalizedString (@"Audio output was changed", @"Explanation for route-changed alert view")
delegate: controller
cancelButtonTitle: NSLocalizedString (@"StopPlaybackAfterRouteChange", @"Stop button title")
otherButtonTitles: NSLocalizedString (@"ResumePlaybackAfterRouteChange", @"Play button title"), nil];
[routeChangeAlertView show];
// release takes place in alertView:clickedButtonAtIndex: method
} else {
NSLog (@"A route change occurred that does not require pausing of application audio.");
}
}
}
@implementation MainViewController
@synthesize artworkItem;
@synthesize userMediaItemCollection;
@synthesize playBarButton;
@synthesize pauseBarButton;
@synthesize musicPlayer;
@synthesize navigationBar;
@synthesize noArtworkImage; item has no associated artwork
@synthesize backgroundColorTimer;
@synthesize nowPlayingLabel;
@synthesize appSoundButton;
@synthesize addOrShowMusicButton;
@synthesize appSoundPlayer;
@synthesize soundFileURL;
@synthesize interruptedOnPlayback;
@synthesize playedMusicOnce;
@synthesize playing;
@implementation MainViewController
@synthesize artworkItem; // the now-playing media item's artwork image, displayed in the Navigation bar
@synthesize userMediaItemCollection; // the media item collection created by the user, using the media item picker
@synthesize playBarButton; // the button for invoking Play on the music player
@synthesize pauseBarButton; // the button for invoking Pause on the music player
@synthesize musicPlayer; // the music player, which plays media items from the iPod library
@synthesize navigationBar; // the application's Navigation bar
@synthesize noArtworkImage; // an image to display when a media item has no associated artwork
@synthesize backgroundColorTimer; // a timer for changing the background color -- represents an application that is
// doing something else while iPod music is playing
@synthesize nowPlayingLabel; // descriptive text shown on the main screen about the now-playing media item
@synthesize appSoundButton; // the button to invoke playback for the application sound
@synthesize addOrShowMusicButton; // the button for invoking the media item picker. if the user has already
// specified a media item collection, the title changes to "Show Music" and
// the button invokes a table view that shows the specified collection
@synthesize appSoundPlayer; // An AVAudioPlayer object for playing application sound
@synthesize soundFileURL; // The path to the application sound
@synthesize interruptedOnPlayback; // A flag indicating whether or not the application was interrupted during
// application audio playback
@synthesize playedMusicOnce; // A flag indicating if the user has played iPod library music at least one time
// since application launch.
@synthesize playing; // An application that responds to interruptions must keep track of its playing/
// not-playing state.
#pragma mark Music control
- (IBAction) AddMusicOrShowMusic: (id) sender {
// if the user has already chosen some music, display that list
if (userMediaItemCollection) {
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: @"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
} else {
MPMediaPickerController *picker =
[[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
picker.delegate = self;
picker.allowsPickingMultipleItems = YES;
picker.prompt = NSLocalizedString (@"Add songs to play", "Prompt in media item picker");
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleDefault animated: YES];
[self presentModalViewController: picker animated: YES];
[picker release];
}
}
- (void) updatePlayerQueueWithMediaCollection: (MPMediaItemCollection *) mediaItemCollection {
// Configure the music player, but only if the user chose at least one song to play
if (mediaItemCollection) {
if (userMediaItemCollection == nil) {
[self setUserMediaItemCollection: mediaItemCollection];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
[self setPlayedMusicOnce: YES];
[musicPlayer play];
} else {
BOOL wasPlaying = NO;
if (musicPlayer.playbackState == MPMusicPlaybackStatePlaying) {
wasPlaying = YES;
}
MPMediaItem *nowPlayingItem = musicPlayer.nowPlayingItem;
NSTimeInterval currentPlaybackTime = musicPlayer.currentPlaybackTime;
NSMutableArray *combinedMediaItems = [[userMediaItemCollection items] mutableCopy];
NSArray *newMediaItems = [mediaItemCollection items];
[combinedMediaItems addObjectsFromArray: newMediaItems];
[self setUserMediaItemCollection: [MPMediaItemCollection collectionWithItems: (NSArray *) combinedMediaItems]];
[combinedMediaItems release];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
musicPlayer.nowPlayingItem = nowPlayingItem;
musicPlayer.currentPlaybackTime = currentPlaybackTime;
if (wasPlaying) {
[musicPlayer play];
}
}
navigationBar.topItem.leftBarButtonItem.enabled = YES;
[addOrShowMusicButton setTitle: NSLocalizedString (@"Show Music", @"Alternate title for 'Add Music' button, after user has chosen some music")
forState: UIControlStateNormal];
}
}
- (void) restorePlaybackState {
if (musicPlayer.playbackState == MPMusicPlaybackStateStopped && userMediaItemCollection) {
[addOrShowMusicButton setTitle: NSLocalizedString (@"Show Music", @"Alternate title for 'Add Music' button, after user has chosen some music")
forState: UIControlStateNormal];
if (playedMusicOnce == NO) {
[self setPlayedMusicOnce: YES];
[musicPlayer play];
}
}
}
#pragma mark Media item picker delegate methods________
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
[self dismissModalViewControllerAnimated: YES];
[self updatePlayerQueueWithMediaCollection: mediaItemCollection];
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque animated: YES];
}
- (void) mediaPickerDidCancel: (MPMediaPickerController *) mediaPicker {
[self dismissModalViewControllerAnimated: YES];
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque animated: YES];
}
#pragma mark Music notification handlers__________________
- (void) handle_NowPlayingItemChanged: (id) notification {
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
UIImage *artworkImage = noArtworkImage;
MPMediaItemArtwork *artwork = [currentItem valueForProperty: MPMediaItemPropertyArtwork];
// Obtain a UIImage object from the MPMediaItemArtwork object
if (artwork) {
artworkImage = [artwork imageWithSize: CGSizeMake (30, 30)];
}
// Obtain a UIButton object and set its background to the UIImage object
UIButton *artworkView = [[UIButton alloc] initWithFrame: CGRectMake (0, 0, 30, 30)];
[artworkView setBackgroundImage: artworkImage forState: UIControlStateNormal];
// Obtain a UIBarButtonItem object and initialize it with the UIButton object
UIBarButtonItem *newArtworkItem = [[UIBarButtonItem alloc] initWithCustomView: artworkView];
[self setArtworkItem: newArtworkItem];
[newArtworkItem release];
[artworkItem setEnabled: NO];
[navigationBar.topItem setRightBarButtonItem: artworkItem animated: YES];
[nowPlayingLabel setText: [
NSString stringWithFormat: @"%@ %@ %@ %@",
NSLocalizedString (@"Now Playing:", @"Label for introducing the now-playing song title and artist"),
[currentItem valueForProperty: MPMediaItemPropertyTitle],
NSLocalizedString (@"by", @"Article between song name and artist name"),
[currentItem valueForProperty: MPMediaItemPropertyArtist]]];
if (musicPlayer.playbackState == MPMusicPlaybackStateStopped) {
[nowPlayingLabel setText: [
NSString stringWithFormat: @"%@",
NSLocalizedString (@"Music-ended Instructions", @"Label for prompting user to play music again after it has stopped")]];
}
}
- (void) handle_PlaybackStateChanged: (id) notification {
MPMusicPlaybackState playbackState = [musicPlayer playbackState];
if (playbackState == MPMusicPlaybackStatePaused) {
navigationBar.topItem.leftBarButtonItem = playBarButton;
} else if (playbackState == MPMusicPlaybackStatePlaying) {
navigationBar.topItem.leftBarButtonItem = pauseBarButton;
} else if (playbackState == MPMusicPlaybackStateStopped) {
navigationBar.topItem.leftBarButtonItem = playBarButton;
// Even though stopped, invoking 'stop' ensures that the music player will play
// its queue from the start.
[musicPlayer stop];
}
}
- (void) handle_iPodLibraryChanged: (id) notification {
]
}
#pragma mark Application playback control_________________
- (IBAction) playAppSound: (id) sender {
[appSoundPlayer play];
playing = YES;
[appSoundButton setEnabled: NO];
}
- (void) alertView: routeChangeAlertView clickedButtonAtIndex: buttonIndex {
if ((NSInteger) buttonIndex == 1) {
[appSoundPlayer play];
} else {
[appSoundPlayer setCurrentTime: 0];
[appSoundButton setEnabled: YES];
}
[routeChangeAlertView release];
}
#pragma mark AV Foundation delegate methods____________
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) appSoundPlayer successfully: (BOOL) flag {
playing = NO;
[appSoundButton setEnabled: YES];
}
- (void) audioPlayerBeginInterruption: player {
NSLog (@"Interrupted. The system has paused audio playback.");
if (playing) {
playing = NO;
interruptedOnPlayback = YES;
}
}
- (void) audioPlayerEndInterruption: player {
NSLog (@"Interruption ended. Resuming audio playback.");
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (interruptedOnPlayback) {
[appSoundPlayer prepareToPlay];
[appSoundPlayer play];
playing = YES;
interruptedOnPlayback = NO;
}
}
#pragma mark Table view delegate methods
- (void) musicTableViewControllerDidFinish: (MusicTableViewController *) controller {
[self dismissModalViewControllerAnimated: YES];
[self restorePlaybackState];
}
#pragma mark Application setup
- (void) setupApplicationAudio {
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"sound"
ofType: @"caf"];
NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
self.soundFileURL = newURL;
[newURL release];
[[AVAudioSession sharedInstance] setDelegate: self];
// [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
UInt32 doSetProperty = 0;
AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (doSetProperty),
&doSetProperty
);
// Registers the audio route change listener callback function
AudioSessionAddPropertyListener (
kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
self
);
// Activates the audio session.
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
// Instantiates the AVAudioPlayer object, initializing it with the sound
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error: nil];
self.appSoundPlayer = newPlayer;
[newPlayer release];
[appSoundPlayer prepareToPlay];
[appSoundPlayer setVolume: 1.0];
[appSoundPlayer setDelegate: self];
}
- (void) registerForMediaPlayerNotifications {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self
selector: @selector (handle_NowPlayingItemChanged:)
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[notificationCenter addObserver: self
selector: @selector (handle_PlaybackStateChanged:)
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer beginGeneratingPlaybackNotifications];
}
- (BOOL) useiPodPlayer {
if ([[NSUserDefaults standardUserDefaults] boolForKey: PLAYER_TYPE_PREF_KEY]) {
return YES;
} else {
return NO;
}
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self togglePlayPause];
break;
case UIEventSubtypeRemoteControlPlay:
[self playAudio];
break;
case UIEventSubtypeRemoteControlPause:
[self pauseAudio];
break;
default:
break;
}
}
}
- (IBAction) playOrPauseMusic: (id)sender {
[self togglePlayPause];
}
- (void)playAudio {
[musicPlayer play];
}
- (void)pauseAudio {
[musicPlayer pause];
}
- (void)togglePlayPause {
MPMusicPlaybackState playbackState = [musicPlayer playbackState];
if (playbackState == MPMusicPlaybackStateStopped || playbackState == MPMusicPlaybackStatePaused) {
[musicPlayer play];
} else if (playbackState == MPMusicPlaybackStatePlaying) {
[musicPlayer pause];
}
}
// Configure the application.
- (void) viewDidLoad {
[super viewDidLoad];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self setupApplicationAudio];
[self setPlayedMusicOnce: NO];
[self setNoArtworkImage: [UIImage imageNamed: @"no_artwork.png"]];
[self setPlayBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay
target: self
action: @selector (playOrPauseMusic:)]];
[self setPauseBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPause
target: self
action: @selector (playOrPauseMusic:)]];
[addOrShowMusicButton setTitle: NSLocalizedString (@"Add Music", @"Title for 'Add Music' button, before user has chosen some music")
forState: UIControlStateNormal];
[appSoundButton setTitle: NSLocalizedString (@"Play App Sound", @"Title for 'Play App Sound' button")
forState: UIControlStateNormal];
[nowPlayingLabel setText: NSLocalizedString (@"Instructions", @"Brief instructions to user, shown at launch")];
if ([self useiPodPlayer]) {
[self setMusicPlayer: [MPMusicPlayerController iPodMusicPlayer]];
if ([musicPlayer nowPlayingItem]) {
navigationBar.topItem.leftBarButtonItem.enabled = YES;
[self handle_NowPlayingItemChanged: nil];
if ([musicPlayer playbackState] == MPMusicPlaybackStatePaused) {
navigationBar.topItem.leftBarButtonItem = playBarButton;
}
}
} else {
[self setMusicPlayer: [MPMusicPlayerController applicationMusicPlayer]];
[musicPlayer setShuffleMode: MPMusicShuffleModeOff];
[musicPlayer setRepeatMode: MPMusicRepeatModeNone];
}
[self registerForMediaPlayerNotifications];
[self setBackgroundColorTimer: [NSTimer scheduledTimerWithTimeInterval: 3.5
target: self
selector: @selector (updateBackgroundColor)
userInfo: nil
repeats: YES]];
}
// Invoked by the backgroundColorTimer.
- (void) updateBackgroundColor {
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration: 3.0];
CGFloat redLevel = rand() / (float) RAND_MAX;
CGFloat greenLevel = rand() / (float) RAND_MAX;
CGFloat blueLevel = rand() / (float) RAND_MAX;
self.view.backgroundColor = [UIColor colorWithRed: redLevel
green: greenLevel
blue: blueLevel
alpha: 1.0];
[UIView commitAnimations];
}
#pragma mark Application state management_____________
- (void) didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void) viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer endGeneratingPlaybackNotifications];
[musicPlayer release];
[artworkItem release];
[backgroundColorTimer invalidate];
[backgroundColorTimer release];
[navigationBar release];
[noArtworkImage release];
[nowPlayingLabel release];
[pauseBarButton release];
[playBarButton release];
[soundFileURL release];
[userMediaItemCollection release];
[super dealloc];
}
@end