自定义的音频播放器.PNG是这样一个需求,就是类似于听书功能,你有一整段文字,要通过手机把它以语音的形式播放出来,并且做成网易云音乐的风格,支持后台播放,上一曲,下一曲,循环播放。这是产品经理给的一个需求。
我找到了一个完美符合上述功能并且是免费的SDK,还可以完全自定义播放页面,是不是很爽?哈哈哈... 讯飞语音开放平台
1. 首先进入开发平台集成注册账号,创建应用,下载SDK
- 产品服务-->语音合成-->在线语音合成-->下载SDK
- 功能选择在线语音合成就可以了,也有离线语音合成的,就是手机断网也可以继续语音播放,把音频存放在本地,这种功能貌似是收费的
2. 按照文档集成SDK 文档地址
- 需要注意的是一定不要忘记添加用户权限在info.plist里面
3. 开始我们的代码工作
- 先分析一下,如果你的产品是纯粹的音频播放,也就是说音频不是其中的一个模块,可以把注册APPId信息写在APPdelegate里面。
- 如果这个音频播放只是其中的一个模块,退出这个模块之后,就不再播放音频了,建议写一个单例来注册,这样逻辑比较清晰。
//Appid是应用的身份信息,具有唯一性,初始化时必须要传入Appid。
NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@", @"YourAppid"];
[IFlySpeechUtility createUtility:initString];
- 音频播放要用单例去保存,因为要后台播放,实时暂停,上一曲,下一曲,它跟页面跳转逻辑是没有关系的。
所以,要创建一个单例,留下播放,暂停,上一曲,下一曲...接口
/** 播放音频 */
+ (IFlySpeechSynthesizer *)shareAudioPlay;
/** 获取正在播放的音频信息 暂停的音频信息 景区*/
+ (IFlySpeechSynthesizer *)isPlayingHeaderMessage:(TouristHeaderModel *)headerModel;
/** 获取正在播放的音频信息 暂停的音频信息 景点*/
+ (IFlySpeechSynthesizer *)isPlayingSecondMessage:(NSArray *)secondList andIndexPath:(NSInteger)index;
/** 播放音频 针对首页右侧播放按钮 需要进行初始化 判断 */
+ (IFlySpeechSynthesizer *)shareAudioPlays;
/** 播放时间转换 */
+ (NSString *)stringWithTime:(float)time;
- 我是写了这几个方法,这个可以根据自己项目功能具体来操作
- 然后,实现share方法
//打开输出在console的log开关
[IFlySetting showLogcat:NO];
[IFlySetting setLogFile:LVL_NONE]
//所有服务启动前,需要确保执行createUtility
[IFlySpeechUtility createUtility:initString];
//获取语音合成单例
_iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
//设置合成参数
//设置在线工作方式
[_iFlySpeechSynthesizer setParameter:[IFlySpeechConstant TYPE_CLOUD]
forKey:[IFlySpeechConstant ENGINE_TYPE]];
//设置音量,取值范围 0~100
[_iFlySpeechSynthesizer setParameter:@"100" forKey: [IFlySpeechConstant VOLUME]];
//发音人,默认为”xiaoyan”,可以设置的参数列表可参考“合成发音人列表”
[_iFlySpeechSynthesizer setParameter:@" xiaoyan "forKey: [IFlySpeechConstant VOICE_NAME]];
- 这样就算是配置完了,然后去实现代理
//合成结束
- (void) onCompleted:(IFlySpeechError *) error {}
//合成开始
- (void) onSpeakBegin{}
//合成缓冲进度
- (void) onBufferProgress:(int) progress message:(NSString *)msg{}
//合成播放进度
- (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos{}
- 最重要的是【获取播放进度方法】,可以在这里面实时改变进度条
- OK,功能现在是做完了,播放器还有进度条怎么搞啊?还有后台播放,实时查看正在播放的音频,进度,上一曲,下一曲,对吧?
4. 别急,播放器进度条
- 可以有两种方法来做,准确的说,进度条可以有两种方法,用UISlider也可以用UILabel,这个得看设计图,看看哪个好做一点。
- 首先,自定义一个进度条View,里面有进度条,缓冲条,我是把滑动条和下面的播放按钮分开来放的。
/** 背景色 未填充部分颜色 */
@property (strong,nonatomic) UIColor *progressBackGroundColor;
/** 进度条颜色 填充部分颜色 */
@property (strong,nonatomic) UIColor *progressTintColor;
/** 进度条图片 填充部分图片 */
@property (strong,nonatomic) UIImage *progressTintImage;
/** 进度条进度的值 */
@property (assign,nonatomic) CGFloat progressValue;
/** 进度条圆角 */
@property (assign,nonatomic) NSInteger progressCornerRadius;
/** 进度条边宽度 */
@property (assign,nonatomic) NSInteger progressBorderWidth;
+ (instancetype)initAudioProgressView; //初始化构造方法
- 然后实现方法 (这里先只写进度条值的实现方法吧,用动画去改变label的frame)
- (void)setProgressValue:(CGFloat)progressValue{
_progressValue = progressValue;
[UIView animateWithDuration:1 animations:^{
self.secondImaView.frame = CGRectMake(0, 0, self.frame.size.width * _progressValue, self.frame.size.height);
self.secondView.frame = CGRectMake(0, 0, self.frame.size.width * progressValue, self.frame.size.height);
}];
}
- 然后去刚才那个代理方法里面动态改变label的frame和播放时间
// 播放进度条
_AudioProgress.progressValue = progress * 0.01;
// 播放时间
_PlayingTime.text = [AudioPlayer stringWithTime:_audioText.length * 0.25 * progress * 0.01];
- 这样基本上进度条算是差不多了
5. 后台播放
- 单例启动音频播放的时候,他就会一直播放的,但是怎么获取它的图片,名字还有详情呢
- 讯飞里面有个方法
[[AudioPlayer shareAudioPlay] setParameter:@"0" forKey:TTS_VOICE_BUTTONSTATUS];
// 定义全局变量
#define TTS_VOICE_TEXT @"TTS_VOICE_TEXT" // 正在播放的文字
#define TTS_VOICE_VALUE @"TTS_VOICE_VALUE" // 播放的总时间
- 我们可以直接取到正在播放的内容,当然我们也可以直接保存在本地,不用这个方法,也是可以的。
- 这个方法就是讯飞播放读的内容,我们改变它的text的就行了
[_iFlySpeechSynthesizer startSpeaking:[_iFlySpeechSynthesizer parameterForKey:TTS_VOICE_TEXT]];
- 有个疑问,要如果说刚好点到的就是正在播放的语音呢,那么它就又要重新开始读了,是不是每次点开新的语音它都会重新开始读呢?
A:其实我们可以判断一下,我们可以再写一个方法,来传入点击的这个音频的Model信息,来跟正在播放的内容做比较,如果一样的话,不做任何操作,不一样,就走Model内容
if (![secondLisModel.sceneryDescription isEqualToString:[_iFlySpeechSynthesizer parameterForKey:TTS_VOICE_TEXT]]) {
[_iFlySpeechSynthesizer startSpeaking:secondLisModel.sceneryDescription];
}
5. 上一曲,下一曲
- 播放列表信息应该是在一个数组里面的,我们可以在播放的时候存下正在播放的index,然后点击下一曲的时候取出index
// 获取正在播放的index
NSString *index = [[AudioPlayer shareAudioPlay] parameterForKey:TTS_VOICE_HowMany];
index = [NSString stringWithFormat:@"%d",[index intValue] + 1];
- 然后更改正在播放的文字就行了
[_iFlySpeechSynthesizer startSpeaking:secondLisModel.sceneryDescription];
6. 补充
- 时间转换方法
+ (NSString *)stringWithTime:(float)time {
int minute = time / 60;
int second = (int)time % 60;
return [NSString stringWithFormat:@"%02d:%02d",minute,second];
}
播放圆盘转动.gif
- (void) startAnimation{
// 开转吧
_TouristImage.layer.speed = 0.5;
}
-(void)endAnimation
{
// 别转了,头都给我转晕了
CFTimeInterval currTimeoffset1 = [_TouristImage.layer convertTime:CACurrentMediaTime() fromLayer:nil];
_TouristImage.layer.speed = 0.0;
_TouristImage.layer.timeOffset = currTimeoffset1;
}
- 开始结束调用这两个方法就行了。
网友评论