FreeStreamer的单例形式封装
.h 文件如下
#import <Foundation/Foundation.h>
#import "FSAudioStream.h"
@protocol PlayerDelegate <NSObject>
@optional
/**
* 更新播放进度
*
* @param currentPosition 当前位置
* @param endPosition 结束位置(总时长)
*/
- (void)updateProgressWithCurrentPosition:(FSStreamPosition)currentPosition andEndPosition:(FSStreamPosition)endPosition;
@end
@interface FreeStreamerPlayer : FSAudioStream
/**
* 是否为播放状态
*/
@property (assign, nonatomic) BOOL isPlay;
/**
* 是否循环播放
*/
@property (assign, nonatomic) BOOL isLoop;
/**
* 播放文件地址(队列)数组
*/
@property (strong, nonatomic) NSMutableArray * audioArray;
/**
* 播放速率
*/
@property (assign, nonatomic) float rate;
/**
* 代理 用于更新播放进度
*/
@property (weak, nonatomic) id<PlayerDelegate> playerDelegate;
/**
* 获得播放器单例
*
* @return 获得播放器单例
*/
+ (instancetype)defaultPlayer;
/**
* 播放文件队列中的指定文件
*
* @param itemIndex 指定的文件的索引
*/
- (void)playItemAtIndex:(NSUInteger)itemIndex;
@end
.m文件如下
#import "FreeStreamerPlayer.h"
@interface FreeStreamerPlayer ()
@property (assign, nonatomic) NSUInteger currentItemIndex;
@property (strong, nonatomic) NSTimer * progressTimer;
@end
@implementation FreeStreamerPlayer
/**
* 获得播放器单例
*
* @return 播放器单例
*/
+ (instancetype)defaultPlayer
{
static FreeStreamerPlayer * player = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//创建FSAudioStream对象
FSStreamConfiguration *config = [[FSStreamConfiguration alloc] init];
config.httpConnectionBufferSize *= 2;
config.enableTimeAndPitchConversion = YES;
player = [[super alloc] initWithConfiguration:config];
player.onFailure=^(FSAudioStreamError error,NSString *description){
NSLog(@"发生错误:%@",description);
};
player.onCompletion=^(){
NSLog(@"播放完成!");
[player stop];
};
player.onStateChange=^(FSAudioStreamState state){
if (state == kFsAudioStreamPlaying) {
[player setPlayRate:player.rate];
}
if (state == kFsAudioStreamStopped) {
if (player.isSinglePlay && player.isLoop) {
[player playItemAtIndex:player.currentItemIndex];
}
if (!player.isSinglePlay && player.currentItemIndex+1 < player.audioArray.count) {
[player playItemAtIndex:player.currentItemIndex+1];
}
if (!player.isSinglePlay && player.isLoop && player.currentItemIndex+1 >= player.audioArray.count) {
[player playItemAtIndex:0];
}
}
};
[player setVolume:0.5];
player.progressTimer = nil;
player.isSinglePlay = YES;
player.isLoop = NO;
player.rate = 1;
});
return player;
}
/**
* 播放
*/
- (void)play
{
[super play];
if (!_progressTimer) {
_progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
}
_isPlay = YES;
}
/**
* 播放指定地址的文件
*
* @param url 文件地址
*/
- (void)playFromURL:(NSURL *)url
{
[super playFromURL:url];
if (![self.audioArray containsObject:url]) {
[self.audioArray addObject:url];
}
_currentItemIndex = [self.audioArray indexOfObject:url];
if (!_progressTimer) {
_progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
}
_isPlay = YES;
}
/**
* 从指定位置开始播放文件
*
* @param offset 起始偏移量
*/
- (void)playFromOffset:(FSSeekByteOffset)offset
{
[super playFromOffset:offset];
if (!_progressTimer) {
_progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
}
_isPlay = YES;
}
/**
* 播放文件队列中的指定文件
*
* @param itemIndex 指定的文件的索引
*/
- (void)playItemAtIndex:(NSUInteger)itemIndex
{
if (itemIndex < self.audioArray.count) {
_currentItemIndex = itemIndex;
[self playFromURL:[self.audioArray objectAtIndex:itemIndex]];
} else {
NSLog(@"超出列表长度");
}
}
/**
* 暂停
*/
- (void)pause
{
if (_isPlay) {
[super pause];
if (!_progressTimer) {
_progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
}
}
}
/**
* 停止
*/
- (void)stop
{
[super stop];
[_progressTimer invalidate];
_progressTimer = nil;
_isPlay = NO;
}
/**
* 设置播放速率
*
* @param rate 播放速率(0.5~2)
*/
- (void)setRate:(float)rate
{
_rate = rate;
[self setPlayRate:rate];
}
/**
* 更新播放进度
*/
- (void)updateProgress
{
if ([_playerDelegate respondsToSelector:@selector(updateProgressWithCurrentPosition:andEndPosition:)]) {
[_playerDelegate updateProgressWithCurrentPosition:self.currentTimePlayed andEndPosition:self.duration];
}
}
/**
* 播放的文件队列
*
* @return 播放的文件队列
*/
- (NSMutableArray *)audioArray
{
if (!_audioArray) {
_audioArray = [[NSMutableArray alloc] init];
}
return _audioArray;
}
@end
知识摘要
- (FSAudioStream *)audioStream { if (_audioStream == nil) {
_audioStream = [[FSAudioStream alloc] init];
_audioStream.strictContentTypeChecking = NO;
_audioStream.defaultContentType = @"audio/mpeg";
}
return _audioStream;
}
[self.audioStream playFromURL:audioUrl];
[self.audioStream pause];
[self.audioStream stop];
[self.audioStream pause];
FSStreamPosition pos = {0};
pos.position = progress;
[self.audioStream seekToPosition:pos];
FSStreamPosition cur = self.audioStream.currentTimePlayed;
self.controlView.value = cur.position
UInt64 totalBufferedData = self.audioStream.prebufferedByteCount;
float bufferedDataFromTotal = (float)totalBufferedData / self.audioPlayer.audioStream.contentLength;
cacheValue = bufferedDataFromTotal;
FSStreamPosition end = self.audioStream.duration;
totalTime = [NSString stringWithFormat:@"00:%02i:%02i", end.minute, end.second];
FSStreamPosition cur = self.audioStream.currentTimePlayed; currentTime = [NSString stringWithFormat:@"00:%02i:%02i", cur.minute, cur.second];
[self.audioStream setOnStateChange:^(FSAudioStreamState state) {
NSLog(@"状态改变");
}];
[self.audioStream setOnCompletion:^{
NSLog(@"当前音频播放完成");
}];
- 解决资源还未加载完就播放未加载的进度资源出现加载失败的情况
if (value == 0) value = 0.001;
if (value == 1) value = 0.999;
self.audioPlayer.progress = value;