播放iPod中的音乐

Media Player既然叫做“Player”那必然是提供播放媒体的功能的,实际上其既可以播放视频也可以播放音频,Media Player提供的“MPMusicPlayerController”实现了一个传统播放的基本功能。比如:

player_music_player

图中可以看到有:

  • 当前播放曲目
  • 当前播放时间
  • 声音
  • 下一曲
  • 播放/暂停
  • 循环方式

1.使用MPMusicPlayerController播放音乐列表

创建MPMusicPlayerController对象

MPMusicPlayerController分成两种类型:

  • 应用级别(application music player):应用独立的,不会影响其他音乐播放App的播放
  • 系统级别(system music player):调用系统的“音乐” App来播放,不会出界面

通过调用+ applicationMusicPlayer创建一个应用级别的“MPMusicPlayerController”;通过调用+ systemMusicPlayer获取系统内建的“MPMusicPlayerController”也就是系统的“音乐”App。

设置播放列表

获得了“MPMusicPlayerController”之后,就可以设置播放列表了。还记得之前2.1 获取iPod资源信息中介绍的“MPMediaQuery”和“MPMediaItemCollection”,分别是通过系统选择界面和查询条件查询的方式得到的结果。这里设置播放列表有两种方法,分别对应上面的两种结果:

    • (void)setQueueWithQuery:(MPMediaQuery *)query : 直接传入一个过滤后的查询结果
    • (void)setQueueWithItemCollection:(MPMediaItemCollection *)itemCollection : 传入一个MPMediaItem的集合

设置播放属性

在播放之前我们还可以通过一些属性值来控制播放行为

  • playbackState 播放状态,只读属性
枚举 模式
MPMusicPlaybackStateStopped 停止
MPMusicPlaybackStatePlaying 正在播放
MPMusicPlaybackStatePaused 暂停
MPMusicPlaybackStateInterrupted 被挂起,比如打电话来了
MPMusicPlaybackStateSeekingForward 前进
MPMusicPlaybackStateSeekingBackward 后退
  • repeatMode 循环模式
枚举 模式
MPMusicRepeatModeDefault 默认模式,上次的模式记忆
MPMusicRepeatModeNone 不循环
MPMusicRepeatModeOne 单曲循环
MPMusicRepeatModeAll 全部循环
  • shuffleMode 随机模式
枚举 模式
MPMusicShuffleModeDefault 默认模式,上次记忆模式
MPMusicShuffleModeOff 不随机
MPMusicShuffleModeSongs 所有歌曲
MPMusicShuffleModeAlbums 按照专辑

播放控制

MPMusicPlayerController实际上是实现了协议“MPMediaPlayback”:

@protocol MPMediaPlayback

// Prepares the current queue for playback, interrupting any active (non-mixible) audio sessions.
// Automatically invoked when -play is called if the player is not already prepared.
- (void)prepareToPlay;

// Returns YES if prepared for playback.
@property(nonatomic, readonly) BOOL isPreparedToPlay;

// Plays items from the current queue, resuming paused playback if possible.
- (void)play;

// Pauses playback if playing.
- (void)pause;

// Ends playback. Calling -play again will start from the beginnning of the queue.
- (void)stop;

// The current playback time of the now playing item in seconds.
@property(nonatomic) NSTimeInterval currentPlaybackTime;

// The current playback rate of the now playing item. Default is 1.0 (normal speed).
// Pausing will set the rate to 0.0. Setting the rate to non-zero implies playing.
@property(nonatomic) float currentPlaybackRate;

// The seeking rate will increase the longer scanning is active.
- (void)beginSeekingForward;
- (void)beginSeekingBackward;
- (void)endSeeking;

@end

这些接口主要就是用来控制播放流程的:

  • play : 开始播放
  • pause : 暂停
  • stop : 停止
  • beginSeekingForward : 快进
  • beginSeekingBackward : 快退
  • currentPlaybackRate: 播放速率、快进/快退速率

除此之外MPMusicPlayerController还扩展了三个控制接口:

    • skipToNextItem : 下一曲
    • skipToBeginning : 第一曲
    • skipToPreviousItem : 上一曲

2. 使用MPVolumeView设置音量

本来MPMusicPlayerController是提供一个volume的属性接口来控制音量的,但是在iOS7之后,这个就被“Deprecated”(如今微信/QQ都是要求iOS7及以上的时代,这个volume真可以寿终正寝了)。现在实现这个功能的是“MPVolumeView”这个工具。

“MPVolumeView”从其名称可以看出来他是一个带有既定UI的工具组件,外形是一个表示音量的SliderBar,可以认为是系统的音量键。

player_mp_volume_view

MPVolumeView作为一个完整的组件,如果是简单的使用,上面图中的一个Slider就可以控制音量的高低了。拖一个UIView到storyborard上,然后设置类型为"MPVolumeView"即可。

MPVolumeView的可用接口非常少,也就是其定制化非常有限。也就是能定制下滚轮的图片和背景形状。 首先来看两个控制显示的属性接口:

  • showsVolumeSlider : 是否显示Slider
  • showsRouteButton : 是否显示滑动轮

正常情况肯定都是显示啦。关键是不想用系统的那个滚轮和背景。"MPVolumeView"提供了- setRouteButtonImage:forState:来设置滑动轮的图片。接口很简单,就是对enalbed/disabled/highlighted等状态设置一个UIImage 对象。

使用自己的View

但是有时时候这样任然不能满足我们的需求(设想下QQ音乐里面的音量按钮)。那怎么办呢?

这时可以考虑一些黑科技,通过OC的class.description可以获得类名。MPVolumeView有三个subview,其中私有类(无法手动创建,也无法使用isKindOfClass方法)MPVolumeSlider用来控制音量大小,继承自UISlider,通过修改Slider的值就等同于设置系统的音量了。

for (UIView *view in [mpVolumeView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;
        break;
    }
}

// retrieve system volume
float systemVolume = volumeViewSlider.value;

// change system volume, the value is between 0.0f and 1.0f
[volumeViewSlider setValue:1.0f animated:NO];

// reset system volume
[volumeViewSlider setValue:systemVolume animated:NO];

这样,我们可以按照策划需求绘制一个自己的音量控制View,然后在创建一个MPVolumeView但是不显示他,或者放到屏幕外面去。当用户调整音量时,设置这个slider的值就可以实现调整音量了。

获取下一曲、音量等变化信息

上面的MPMusicPlayerController在播放音乐列表的时候,如何获得当前播放的曲目来显示其播放信息呢?MPMusicPlayerController提供了属性方法:

  • nowPlayingItem : 当前正在播放的MPMediaItem
  • indexOfNowPlayingItem : 当前正在播放的MPMediaItem的

通过这两个方法可以获取当前播放音乐的信息,但是如何知道当前歌曲切换了呢?MPMusicPlayerController还为我们提供了三个通知:

  • MPMusicPlayerControllerPlaybackStateDidChangeNotification : 当播放状态改变时,如停止、正在播放
  • MPMusicPlayerControllerNowPlayingItemDidChangeNotification : 当切换歌曲时
  • MPMusicPlayerControllerVolumeDidChangeNotification : 当音量改变时

如:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

[notificationCenter  addObserver: self
                        selector: @selector (onVolumeChange:)
                            name: MPMusicPlayerControllerVolumeDidChangeNotification
                          object: _appMusicPlayer];
[notificationCenter  addObserver: self
                        selector: @selector (onStateChange:)
                            name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
                          object: _appMusicPlayer];
[notificationCenter  addObserver: self
                        selector: @selector (onNowPlaying:)
                            name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
                          object: _appMusicPlayer];

  // take of this
[_appMusicPlayer beginGeneratingPlaybackNotifications];

  #pragma mark Notifaction
    - (void) onStateChange: (NSNotification*) notification {
        NSLog(@"onStateChange");
    }

    - (void) onNowPlaying: (NSNotification*) notification {
        NSLog(@"onNowPlaying");
        MPMusicPlayerController *player = notification.object;
        MPMediaItem *item = [player nowPlayingItem];
        NSLog(@"now playing %@", [item valueForKey:MPMediaItemPropertyTitle]);
    }

    - (void) onVolumeChange: (NSNotification*) notification {
        NSLog(@"onVolumeChange");
    }

注意,这里需要调用MPMusicPlayerController的`

  • beginGeneratingPlaybackNotifications才能在需要的时候发送通知。当不需要的时候调用- endGeneratingPlaybackNotifications`进行取消,同时也需要调用NSNotificationCenter的removeObserver。

文中Demo可以在GitHub找到。

results matching ""

    No results matching ""