前段時間寫過一個基於VLCKit實現的網易雲音樂播放demo-GKAudioPlayerDemo,以及3篇文章git
iOS-VLCKit實現仿網易雲音樂播放音樂(一)github
有興趣的能夠看看。 基於VLCKit實現的有不少問題,好比不能播放本地音樂、不能獲取播放進度、播放時有不少狀況會被暫停或者閃退(有多是我寫的有問題)。因而通過各類搜索和探尋,最終發現FreeStreamer實現的比較好,因此又從新寫了GKWYMusic這個demo,本次demo的數據所有來自百度音樂,僅供學習使用。bash
GKWYMusic實現的有如下功能:網絡
* 網絡音樂的播放、緩存、下載
* 本地音樂的播放(已下載的音樂)
* 歌詞滾動、音量控制、歌曲切換
* 設置循環類型、上一曲、下一曲、喜歡歌曲等
* 鎖屏控制(播放、暫停、喜歡、上一曲、下一曲、播放條拖動)
* 耳機線控(播放、暫停、上一曲、下一曲、快進、快退)
* 通知監聽(插拔耳機、播放打斷)
複製代碼
本次主要講一下對FreeStreamer的封裝及使用。async
本次對FreeStreamer封裝了一個單例類GKAudioPlayer,可在demo中查看,使用到了FreeStreamer中的FSAudioStream。 一、建立FSAudioStream並監聽播放狀態,以下工具
#pragma mark - 懶加載
- (FSAudioStream *)audioStream {
if (!_audioStream) {
_audioStream = [[FSAudioStream alloc] init];
__weak typeof(self) weakSelf = self;
_audioStream.onCompletion = ^{
NSLog(@"完成");
};
_audioStream.onStateChange = ^(FSAudioStreamState state) {
switch (state) {
case kFsAudioStreamRetrievingURL: // 檢索url
NSLog(@"檢索url");
weakSelf.state = GKAudioPlayerStateLoading;
break;
case kFsAudioStreamBuffering: // 緩衝
NSLog(@"緩衝中。。");
weakSelf.state = GKAudioPlayerStateBuffering;
break;
case kFsAudioStreamSeeking: // seek
NSLog(@"seek中。。");
weakSelf.state = GKAudioPlayerStateLoading;
break;
case kFsAudioStreamPlaying: // 播放
NSLog(@"播放中。。");
weakSelf.state = GKAudioPlayerStatePlaying;
break;
case kFsAudioStreamPaused: // 暫停
NSLog(@"播放暫停");
weakSelf.state = GKAudioPlayerStatePaused;
break;
case kFsAudioStreamStopped: // 中止
NSLog(@"播放中止");
weakSelf.state = GKAudioPlayerStateStopped;
break;
case kFsAudioStreamRetryingFailed: // 檢索失敗
NSLog(@"檢索失敗");
weakSelf.state = GKAudioPlayerStateError;
break;
case kFsAudioStreamRetryingStarted: // 檢索開始
NSLog(@"檢索開始");
weakSelf.state = GKAudioPlayerStateLoading;
break;
case kFsAudioStreamFailed: // 播放失敗
NSLog(@"播放失敗");
weakSelf.state = GKAudioPlayerStateError;
break;
case kFsAudioStreamPlaybackCompleted: // 播放完成
NSLog(@"播放完成");
weakSelf.state = GKAudioPlayerStateEnded;
break;
case kFsAudioStreamRetryingSucceeded: // 檢索成功
NSLog(@"檢索成功");
weakSelf.state = GKAudioPlayerStateLoading;
break;
case kFsAudioStreamUnknownState: // 未知狀態
NSLog(@"未知狀態");
weakSelf.state = GKAudioPlayerStateError;
break;
case kFSAudioStreamEndOfFile: // 緩衝結束
NSLog(@"緩衝結束");
{
// 定時器中止後須要再次調用獲取進度方法,防止出現進度不許確的狀況
[weakSelf bufferTimerAction:nil];
[weakSelf stopBufferTimer];
}
break;
default:
break;
}
[weakSelf setupPlayerState:weakSelf.state];
};
}
return _audioStream;
}
複製代碼
二、緩衝進度的監聽,須要在播放時先建立定時器,當緩衝完成時在關閉定時器學習
// 建立定時器
self.bufferTimer = [GKTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(bufferTimerAction:) userInfo:nil repeats:YES];
複製代碼
// 獲取進度
- (void)bufferTimerAction:(id)sender {
float preBuffer = (float)self.audioStream.prebufferedByteCount;
float contentLength = (float)self.audioStream.contentLength;
// 這裏獲取的進度不能準確地獲取到1
float bufferProgress = contentLength > 0 ? preBuffer / contentLength : 0;
// NSLog(@"緩衝進度%.2f", bufferProgress);
// 爲了能使進度準確的到1,這裏作了一些處理
int buffer = (int)(bufferProgress + 0.5);
if (bufferProgress > 0.9 && buffer >= 1) {
[self stopBufferTimer];
}
if ([self.delegate respondsToSelector:@selector(gkPlayer:bufferProgress:)]) {
[self.delegate gkPlayer:self bufferProgress:bufferProgress];
}
}
複製代碼
三、播放,覺得播放時會將數據緩存到本地,因此作了刪除處理,可根據需求修改。另外作了url的判斷,判斷是網絡仍是本地ui
- (void)setPlayUrlStr:(NSString *)playUrlStr {
if (![_playUrlStr isEqualToString:playUrlStr]) {
// 切換數據,清除緩存
[self removeCache];
_playUrlStr = playUrlStr;
if ([playUrlStr hasPrefix:@"http"] || [playUrlStr hasPrefix:@"https"]) {
self.audioStream.url = [NSURL URLWithString:playUrlStr];
}else {
self.audioStream.url = [NSURL fileURLWithPath:playUrlStr];
}
}
}
複製代碼
四、seek 設置播放進度
- (void)setPlayerProgress:(float)progress {
FSStreamPosition position = {0};
position.position = progress;
dispatch_async(dispatch_get_main_queue(), ^{
[self.audioStream seekToPosition:position];
});
}
複製代碼
##最後 本次的demo裏面抽離出來了許多工具類如:搜索框、定時器、歌詞解析、滑桿、刷新、下載管理等,有須要的可使用。
demo會不斷更新,若是有需求歡迎隨時提出。
另外推薦下個人圖片瀏覽器GKPhotoBrowser