https://www.jianshu.com/p/714ce954e628

最近接手公司的直播项目,对以前遗留的问题做处理和优化, 于是顺便看了下阿里云直播的文档,在下面写下对直播的理解和遇到的问题, 阿里云售后特别好,一对一解决问题速度很快,如果遇到解决不了的问题可以发工单提问,效率很高产品->视频直播->文档&SDK->联系客服->工单支持然后选择自己遇到问题的产品类型提交工单即可,一般两个小时内可以得到回复


工欲善其事必先利其器,先做准备工作

Step1. 访问 阿里云官网,点左上角 登录
Step2. 登录视频直播控制台
在 视频直播服务产品主页登录控制台。控制台会检查所依赖服务的开通状态,请按页面引导操作。
Step3. 在 域名管理 中,新建域名。
直播域名需要进行备案审核,审核通过后即可使用,未备案的域名请先进行备案,备案流程
Step4. CNAME绑定
将您添加的直播域名的DNS CNAME纪录修改为直播域名管理详情页面上显示的CNAME绑定地址。我们需要把阿里云提供的推流地址和直播域名进行绑定,这样当推流到直播域名时会推流到我们的直播中心。
Step4. 获取推流和播放地址
在 域名管理 中,点击直播加速域名 管理 :获取推流和直播地址
Step5. 鉴权配置
直播流媒体的推送和播放采用同一套鉴权方案,可以在控制台的鉴权配置中进行配置,详细了解鉴权配置。

注意
  • 只有进行鉴权配置后,该加速域名才能正常进行推流和播流,直播业务类型仅支持A类型鉴权方式。
  • 推流和播流地址需要分别进行鉴权签名计算,每一个签名都是严格按照URL计算的,故不可使用推流URL计算得到的签名应用到播流地址,同理每一种播流地址都会对应不同的鉴权计算结果。

推流

Step1. 获取鉴权后的推流地址:
直播控制台 - 域名管理 - 直播域名管理详情页 - 基本信息 取得推流地址如下: rtmp://video-center.alivecdn.com/AppName/StreamName?vhost=live.aliyun.com 使用直播控制台 - 域名管理 - 直播域名管理详情页 - 鉴权配置 页面的鉴权URL计算器计算鉴权URL: 输入推流地址(AppName、StreamName可自行修改)、鉴权KEY、有效时间,点击<生成>按钮即可得到鉴权URL。
Step2. 推流操作
推流地址:rtmp://video-center.alivecdn.com/APPName/StreamName?vhost=live.aliyun.com

说明
  • video-center.alivecdn.com是直播中心服务器,允许自定义,例如您的域名是live.aliyun.com(注意:该域名不可以和你的直播加速域名相同),可以设置DNS,将您的域名CNAME指向video-center.alivecdn.com即可。
  • APPName是应用名称,支持自定义,可以更改。
  • StreamName是流名称,支持自定义,可以更改。
  • vhost参数是最终在边缘节点播放的域名,即你的直播加速域名。
    直播推流操作可使用第三方推流软件,这里介绍 OBS 推流软件的操作方法
    请到OBS官网下载最新软件 Mac版本
    以下面的推流地址为例,参数设置为:FMS URL / URL: rtmp://video-center.alivecdn.com/AppName 播放路径/串码流(如果存在)/ 流秘钥: StreamName?vhost=live.aliyn.com 如您开启了鉴权,则鉴权参数也一并放在 Mac版obs的流密钥与Windows版播放路径/串码流(如果存在)中。

obs设置.png


new_page_1.png


new_page_1-1.png

播放

客户可以根据实际业务场景灵活搭配使用,需要在移动端浏览器、移动H5端进行播放,建议使用HLS(M3U8)方式进行播放,无需集成SDK;非移动端或者已集成SDK的,低并发量并需要有更小的延时,可使用RTMP,高并发量建议使用FLV。
Step1. Web页面后台直接预览
使用OBS等工具使用鉴权URL推流后,可在 直播控制台 - 流管理 - 正在推流 页面查询到正在直播的推流记录,通过 直播地址 可查询播放地址,并可预览播放。
Step2. 通过VLC预览
下载VLC
默认安装后无需做额外设置,文件—>打开网络串流,填写播放地址并点击打开后开始播放。


准备工作完成,接下来开始SDK的接入和依赖库的导入

iOS 推流SDK开发包
iOS推流使用说明

     目前SDK的横屏推流需要再推流界面的Controller中将手机竖屏锁定(只允许Portrait一个方向),如果需要横竖屏切换,需要对UI做一套横竖屏的适配,监控手机的状态并作出相应的布局

推流的横竖屏设置为推流的方向,不是手机的方向(下面是推流,直播界面的代码和设置)

注册通知,根据不同情况做不同判断

    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];//监控手机感应状态 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appResignActive) name:UIApplicationWillResignActiveNotification object:nil];//退入后台停止推流 因为iOS后台机制,不能满足充分的摄像头采集和GPU渲染 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];// 回到前台重新推流``` ` #pragma mark - 推流Session 创建 销毁`
  • (void)createSession{

    AlivcLConfiguration *configuration = [[AlivcLConfiguration alloc] init];
    configuration.url = @"rtmp://video-center.alivecdn.com/3b42277fcb90445096dd72d4a11ef420/";
    configuration.videoMaxBitRate = 1500 * 1000;
    configuration.videoBitRate = 600 * 1000;
    configuration.videoMinBitRate = 400 * 1000;
    configuration.audioBitRate = 64 * 1000;
    configuration.videoSize = CGSizeMake(360, 640);// 横屏状态宽高不需要互换
    configuration.fps = 20;
    configuration.preset = AVCaptureSessionPresetiFrame1280x720;
    configuration.screenOrientation =
    // AlivcLiveScreenVertical = 0,
    // AlivcLiveScreenHorizontal = 1,;
    // 重连时长
    configuration.reconnectTimeout = 5;
    // 水印
    configuration.waterMaskImage = [UIImage imageNamed:@"watermask"];
    configuration.waterMaskLocation = 1;
    configuration.waterMaskMarginX = 10;
    configuration.waterMaskMarginY = 10;
    // 摄像头方向
    if (self.currentPosition) {
    configuration.position = self.currentPosition;
    // AVCaptureDevicePositionBack 后置
    // AVCaptureDevicePositionFront 前置
    } else {
    configuration.position = AVCaptureDevicePositionFront;
    self.currentPosition = AVCaptureDevicePositionFront;
    }
    configuration.frontMirror = YES;

    // alloc session
    self.liveSession = [[AlivcLiveSession alloc] initWithConfiguration:configuration];
    self.liveSession.delegate = self;
    // 是否静音推流
    self.liveSession.enableMute = self.muteButton.selected;
    // 开始预览
    [self.liveSession alivcLiveVideoStartPreview];
    // 开始推流
    [self.liveSession alivcLiveVideoConnectServer];

    NSLog(@"开始推流");

    dispatch_async(dispatch_get_main_queue(), ^{
    // 预览view
    [self.view insertSubview:[self.liveSession previewView] atIndex:0];
    });

    self.exposureValue = 0;
    }

  • (void)destroySession{
    [self.liveSession alivcLiveVideoDisconnectServer];
    [self.liveSession alivcLiveVideoStopPreview];
    [self.liveSession.previewView removeFromSuperview];
    self.liveSession = nil;
    NSLog(@"销毁推流");
    }```
    #pragma mark - Notification通知响应

- (void)appResignActive{// 退入后台停止推流 因为iOS后台机制,不能满足充分的摄像头采集和GPU渲染[self destroySession];// 监听电话_callCenter = [[CTCallCenter alloc] init]; _isCTCallStateDisconnected = NO; _callCenter.callEventHandler = ^(CTCall* call) { if ([call.callState isEqualToString:CTCallStateDisconnected]) { _isCTCallStateDisconnected = YES; } else if([call.callState isEqualToString:CTCallStateConnected]) { _callCenter = nil; } }; NSLog(@"退入后台"); } - (void)appBecomeActive{ if (_isCTCallStateDisconnected) { sleep(2); } // 回到前台重新推流 [self createSession]; NSLog(@"回到前台"); } - (void)handleDeviceOrientationDidChange:(UIInterfaceOrientation)interfaceOrientation { UIDevice *device = [UIDevice currentDevice] ; switch (device.orientation) { case UIDeviceOrientationFaceUp: NSLog(@"屏幕朝上平躺"); break; case UIDeviceOrientationFaceDown: NSLog(@"屏幕朝下平躺"); break; case UIDeviceOrientationUnknown: NSLog(@"未知方向"); break; case UIDeviceOrientationLandscapeLeft: { NSLog(@"屏幕向左横置"); [self destroySession];//摧毁推流 _isScreenHorizontal = YES; // 横屏 YES [self createSession]; //重新推流 } break; case UIDeviceOrientationLandscapeRight: NSLog(@"屏幕向右横置"); break; case UIDeviceOrientationPortrait: { NSLog(@"屏幕直立"); [self destroySession]; // 摧毁推流 _isScreenHorizontal = NO; //竖屏为NO [self createSession]; // 重新推流 } break; case UIDeviceOrientationPortraitUpsideDown: NSLog(@" 屏幕直立 上下颠倒"); break; default: NSLog(@"无法辨认"); break; } }``` `//推流代理,根据实际情况做出反应`

pragma mark - AlivcLiveVideo Delegate

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session error:(NSError *)error{

    dispatch_async(dispatch_get_main_queue(), ^{
    NSString *msg = [NSString stringWithFormat:@"%zd %@",error.code, error.localizedDescription];
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Live Error" message:msg delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"重新连接", nil];
    alertView.delegate = self;
    [alertView show];
    });

    NSLog(@"liveSession Error : %@", error);
    }

  • (void)alivcLiveVideoLiveSessionNetworkSlow:(AlivcLiveSession *)session {

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"当前网络环境较差" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    [alertView show];
    self.textView.text = @"网速过慢,影响推流效果,拉流端会造成卡顿等,建议暂停直播";
    NSLog(@"网速过慢");

}

  • (void)alivcLiveVideoLiveSessionConnectSuccess:(AlivcLiveSession *)session {

    NSLog(@"推流 connect success!");
    }

  • (void)alivcLiveVideoReconnectTimeout:(AlivcLiveSession *)session error:(NSError *)error {
    dispatch_async(dispatch_get_main_queue(), ^{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:@"重连超时-error:%ld", error.code] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];

      [alertView show];

    });
    NSLog(@"重连超时");
    }

  • (void)alivcLiveVideoOpenAudioSuccess:(AlivcLiveSession *)session {
    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:@"麦克风打开成功" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });
    }

  • (void)alivcLiveVideoOpenVideoSuccess:(AlivcLiveSession *)session {
    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:@"摄像头打开成功" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });
    }

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session openAudioError:(NSError *)error {
    dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"麦克风获取失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    });
    }

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session openVideoError:(NSError *)error {

    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"摄像头获取失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });
    }

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session encodeAudioError:(NSError *)error {
    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"音频编码初始化失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });

}

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session encodeVideoError:(NSError *)error {
    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"视频编码初始化失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });
    }

  • (void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session bitrateStatusChange:(ALIVC_LIVE_BITRATE_STATUS)bitrateStatus {

    // dispatch_async(dispatch_get_main_queue(), ^{
    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:[NSString stringWithFormat:@"ALIVC_LIVE_BITRATE_STATUS = %ld", bitrateStatus] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
    // [alertView show];
    // });
    NSLog(@"码率变化 %ld", bitrateStatus);
    }

  • (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (buttonIndex != alertView.cancelButtonIndex) {
    [self.liveSession alivcLiveVideoConnectServer];
    } else {
    [self.liveSession alivcLiveVideoDisconnectServer];
    }
    }


>    视频播放
>> AlivcMediaPlayer
`iOS媒体播放器SDK是在iOS平台上使用的软件开发工具包(Software Developement Kit),为iOS开发者提供简单易用的接口,帮助开发者实现iOS平台上的媒体播放应用开发。该SDK对目前主流的视频格式都提供了良好的支持,支持本地和网络媒体的播放,弥补了系统播放器在媒体格式上的不足。(记得添加AliyunPlayerSDK.framework)
如果需要适配横竖屏要对UI做适配,只做横屏的话可以将页面旋转90度即可  `###### 播放器通知定义:AliVcMediaPlayerLoadDidPreparedNotification:播放器初始化视频文件完成通知,调用prepareToPlay函数,会发送该通知,代表视频文件已经准备完成,此时可以在这个通知中获取到视频的相关信息,如视频分辨率,视频时长等。AliVcMediaPlayerPlaybackDidFinishNotification:播放完成通知。当视频播放完成后会收到此通知。播放完成会有几种情况,1. 当用户调用stop后视频结束完成。2. 视频正常播放结束。
`  AliVcMediaPlayerStartCachingNotification:播放器开始缓冲视频时发送该通知,当播放网络文件时,网络状态不佳或者调用seekTo时,此通知告诉用户网络下载数据已经开始缓冲。AliVcMediaPlayerEndCachingNotification:播放器结束缓冲视频时发送该通知,当数据已经缓冲完,告诉用户已经缓冲结束,来更新相关UI显示。AliVcMediaPlayerPlaybackErrorNotification:播放器播放失败发送该通知,并在该通知中可以获取到错误码。AliVcMediaPlayerSeekingDidFinishNotification:播放器位置改变完成后发送该通知。AliVcMediaPlayerFirstFrameNotification:播放器状态首帧显示后发送的通知。`播放器通知发送逻辑:1. 调用prepareToPlay成功后发送AliVcMediaPlayerLoadDidPreparedNotification通知,失败则会发送AliVcMediaPlayerPlaybackErrorNotification。 2. 调用play、pause、stop、prepareToPlay、seekTo失败后发送AliVcMediaPlayerPlaybackErrorNotification通知。 3. 调用stop/reset成功后播放视频结束发送AliVcMediaPlayerPlaybackDidFinishNotification通知,播放器自动播放结束也会发送AliVcMediaPlayerPlaybackDidFinishNotification通知。 4. 调用seekTo成功后发送AliVcMediaPlayerSeekingDidFinishNotification通知。 5. AliVcMediaPlayerStartCachingNotification和AliVcMediaPlayerEndCachingNotification通知,这个是在网络视频缓冲数据不足以够播放后会发送此通知,一般网络视频在调用seekTo后会发送此通知。` ` //初始化播放器的类`

-(void) playVideo
{

player = [[AliVcMediaPlayer alloc] init];
//创建播放器,传入显示窗口
/**

  • 功能:创建播放器,并设置播放器显示窗口。播放器内部会新建各个播放器变量并初始化,并启动播放器内部流水线线程等。
  • 参数:UIView* view,播放器显示窗口
  • 备注:如果创建播放器的时候view没有,则可以传递nil,可以在后续需要设置view。
    */
    [player create:mShowView];
    //注册准备完成通知
    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(OnVideoPrepared:) name:AliVcMediaPlayerLoadDidPreparedNotification object:player];
    //注册错误通知
    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(OnVideoError:) name:AliVcMediaPlayerPlaybackErrorNotification object:player];
    //传入播放地址,准备播放
    [player prepareToPlay:mUrl];
    //开始播放
    [player play];
    }

作者:daihz
链接:https://www.jianshu.com/p/714ce954e628
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/sundaysgarden/p/10878587.html

iOS直播集成和问题总结(阿里云直播)相关推荐

  1. 【Android】使用阿里云直播实现手机直播功能

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.阿里云视频直播流程 二.录制直播推流步骤 1. 集成说明 通过本地依赖方式集成SDK 通过Maven依赖方式集成S ...

  2. PHP+阿里云直播功能

    前提条件 已注册阿里云账号,注册流程请参见注册阿里云账号. 账号已进行实名认证,实名认证流程请参见个人实名认证或企业实名认证. 准备2个已完成备案的域名,备案流程请参见备案. 若您要添加的推流域名和播 ...

  3. 聚焦2022阿里云直播峰会,洞察直播技术创新应用未来

    当前,直播经济快速发展,为用户带来新消费体验,催生出新模式与新业态.直播应用场景持续拓展,可承载的内容越来越丰富.随着越来越多的传统场景线上化,直播与各行各业的联动日益紧密,市场规模扩大的同时需求进一 ...

  4. 云上“视界” 创新无限 | 2022阿里云直播峰会正式上线

    简介:7月8日,2022阿里云直播峰会正式上线! 当前,随着技术迭代升级.商业体系成熟,直播产业从娱乐游戏.电商购物逐渐渗透至教育培训.人文旅游.企业服务等更多行业领域."直播+" ...

  5. 首帧秒开+智能鉴黄+直播答题,阿里云直播系统背后技术大起底

    摘要: 想要快速实现直播能力,并对原有业务不产生任何影响,依托如阿里云一样的直播平台,来搭建移动直播系统,将技术难题交给阿里云,把更多的精力放在核心业务的本身,是最为稳妥和高效的选择.本文介绍阿里云直 ...

  6. 微信小程序接入阿里云直播

    小程序接入阿里云直播 前言:最近工作中遇到了小程序接入阿里云直播的需求(暂时只做播流,也就是播放端),于是打开阿里云直播文档发现居然没有小程序的相关文档,sdk也没有小程序的版本,网上也没搜到相关案例 ...

  7. 基于阿里云直播实现视频推流(ffmpeg)/拉流(Django2.0)以及在线视频直播播放(支持http/https)功能

    由于5g网络的光速推广,视频业务又被推上了风口浪尖,在2019年初我们还在谈论照片,短视频等关键字,而进入2020年,我们津津乐道的就只有视频,视频,还是视频,普通人拿起手机做直播早已不是奢望,去年我 ...

  8. 如何使用PHP对接阿里云直播?

    配置阿里云直播的推流地址和播放地址 使用阿里云直播功能前,首先需要在阿里云控制台中创建直播应用,然后获取推流地址和播放地址. 推流地址一般格式为: rtmp://{Domain}/{AppName}/ ...

  9. 猫晚流量再创记录,阿里云直播方案护航优酷2500万用户体验

    对"剁手党而言,天猫双11早已经超越了简单的"买买买",更是一场边看边玩的狂欢盛宴.今年的天猫双11狂欢夜晚会(简称"猫晚")在上海举办,这台兼具年轻 ...

最新文章

  1. C# Winform 启动和停止进程
  2. WCF 4.0 REST Service JSON跨域调用
  3. 纸飞机html,Flyaway.css-炫酷纯CSS3纸飞机动画特效
  4. Graves of the Internet - 互联网坟墓
  5. java pdf水印排布问题_Java实现pdf文件添加水印,铺满全页。
  6. 2021年,脸皮“厚“点儿
  7. twitter数据集_大数据周报-201925
  8. nginx:启动、重启、关闭、版本查看、安装目录获取
  9. “玲珑杯”ACM比赛 Round #24: C. この戦いが終わったら(BFS+bitset优化暴力)
  10. 2018.10.01 NOIP模拟 卡牌游戏(贪心)
  11. vue中对话框关闭以后清空对话框中input,select内容
  12. UITextfiled 的属性注释简介
  13. jqGrid Pager、Navigator和自定义按钮(转)
  14. Ant Design学习——TimePicker
  15. html js css 简明教程,HTML+CSS+JavaScript网页制作简明教程
  16. 如何将Mac设置为热点?
  17. if(男深圳集体户口女非深圳户口)深圳准生证办理材料及流程
  18. 计算机研究生院校全国排名2015,2018年武书连中国大学排行榜(完整版)_计算机考研院校...
  19. 无线网络攻击类型及防范
  20. [C]C语言基本语句(1/7)→固定格式

热门文章

  1. NYOJ64 - 鸡兔同笼
  2. 同一个ip服务器comcat下部署第二个项目怎么设置,用nginx在同一服务器端口下部署多个项目,第二个项目打开后页面空白?...
  3. Python入门--元组的创建,(),tuple()
  4. hdu 6397 Character Encoding
  5. poj1700快速渡河问题(贪心策略,详细解析)
  6. 2018蓝桥C++B:煤球数目;生日蜡烛(枚举年龄和枚举次数)
  7. bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序(置换)
  8. opencv 图像傅里叶变换
  9. 回文问题‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬
  10. python机器学习库sklearn——参数优化(网格搜索GridSearchCV、随机搜索RandomizedSearchCV、hyperopt)