WebRTC音视频通话-iOS端调用ossrs直播拉流

2023-11-09

WebRTC音视频通话-iOS端调用ossrs直播拉流

之前实现iOS端调用ossrs服务,文中提到了推流。没有写拉流流程,所以会用到文中的WebRTCClient。请详细查看:https://blog.csdn.net/gloryFlow/article/details/132262724

一、iOS播放端拉流效果

在这里插入图片描述

二、实现iOS端调用ossrs拉流

最近有朋友问过,我发现之前少了一块拉流流程,这里补充一下。

2.1、拉流实现时候设置WebRTCClient

拉流实现时候设置WebRTCClient时候初始化,这里isPublish为false

#pragma mark - Lazy
- (WebRTCClient *)webRTCClient {
    if (!_webRTCClient) {
        _webRTCClient = [[WebRTCClient alloc] initWithPublish:NO];
    }
    return _webRTCClient;
}

2.2、设置拉流显示的画面View。

之前的文中摄像头画面显示使用的是startCaptureLocalVideo,但是拉流需要设置remoteRenderView

WebRTCClient中有定义:

/**
 RTCVideoRenderer
 */
@property (nonatomic, weak) id<RTCVideoRenderer> remoteRenderView;

设置拉流显示的画面View

#import "RTCPlayView.h"

@interface RTCPlayView ()

@property (nonatomic, strong) WebRTCClient *webRTCClient;
@property (nonatomic, strong) RTCEAGLVideoView *remoteRenderer;

@end

@implementation RTCPlayView

- (instancetype)initWithFrame:(CGRect)frame webRTCClient:(WebRTCClient *)webRTCClient {
    self = [super initWithFrame:frame];
    if (self) {
        self.webRTCClient = webRTCClient;
        
        self.remoteRenderer = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero];
        self.remoteRenderer.contentMode = UIViewContentModeScaleAspectFit;
        [self addSubview:self.remoteRenderer];
        self.webRTCClient.remoteRenderView = self.remoteRenderer;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.remoteRenderer.frame = self.bounds;
    NSLog(@"self.remoteRenderer frame:%@", NSStringFromCGRect(self.remoteRenderer.frame));
}

@end

这里使用的创建RTCEAGLVideoView,设置self.webRTCClient.remoteRenderView为self.remoteRenderer

2.3、调用ossrs服务play,接口为rtc/v1/play/

实现拉流调用流程和推流类似,这里不再说明,请查看 https://blog.csdn.net/gloryFlow/article/details/132262724

具体方法如下

- (void)playBtnClick {
    __weak typeof(self) weakSelf = self;
    [self.webRTCClient offer:^(RTCSessionDescription *sdp) {
        [weakSelf.webRTCClient changeSDP2Server:sdp urlStr:@"https://192.168.10.102:1990/rtc/v1/play/" streamUrl:@"webrtc://192.168.10.102:1990/live/livestream" closure:^(BOOL isServerRetSuc) {
            NSLog(@"isServerRetSuc:%@",(isServerRetSuc?@"YES":@"NO"));
        }];
    }];
}

完整的Controller代码如下

#import "RTCPlayViewController.h"

@interface RTCPlayViewController ()<WebRTCClientDelegate>

@property (nonatomic, strong) WebRTCClient *webRTCClient;

@property (nonatomic, strong) RTCPlayView *rtcPlayView;

@property (nonatomic, strong) UIButton *playBtn;

@end

@implementation RTCPlayViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    self.rtcPlayView = [[RTCPlayView alloc] initWithFrame:CGRectZero webRTCClient:self.webRTCClient];
    [self.view addSubview: self.rtcPlayView];
    self.rtcPlayView.backgroundColor = [UIColor lightGrayColor];
    self.rtcPlayView.frame = self.view.bounds;
    
    CGFloat screenWidth = CGRectGetWidth(self.view.bounds);
    CGFloat screenHeight = CGRectGetHeight(self.view.bounds);
    self.playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    self.playBtn.frame = CGRectMake(50, screenHeight - 160, screenWidth - 2*50, 46);
    self.playBtn.layer.cornerRadius = 4;
    self.playBtn.backgroundColor = [UIColor grayColor];
    [self.playBtn setTitle:@"publish" forState:UIControlStateNormal];
    [self.playBtn addTarget:self action:@selector(playBtnClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.playBtn];
    
    self.webRTCClient.delegate = self;
}

- (void)playBtnClick {
    __weak typeof(self) weakSelf = self;
    [self.webRTCClient offer:^(RTCSessionDescription *sdp) {
        [weakSelf.webRTCClient changeSDP2Server:sdp urlStr:@"https://192.168.10.102:1990/rtc/v1/play/" streamUrl:@"webrtc://192.168.10.102:1990/live/livestream" closure:^(BOOL isServerRetSuc) {
            NSLog(@"isServerRetSuc:%@",(isServerRetSuc?@"YES":@"NO"));
        }];
    }];
}

#pragma mark - WebRTCClientDelegate
- (void)webRTCClient:(WebRTCClient *)client didDiscoverLocalCandidate:(RTCIceCandidate *)candidate {
    NSLog(@"webRTCClient didDiscoverLocalCandidate");
}

- (void)webRTCClient:(WebRTCClient *)client didChangeConnectionState:(RTCIceConnectionState)state {
    NSLog(@"webRTCClient didChangeConnectionState");
    /**
     RTCIceConnectionStateNew,
     RTCIceConnectionStateChecking,
     RTCIceConnectionStateConnected,
     RTCIceConnectionStateCompleted,
     RTCIceConnectionStateFailed,
     RTCIceConnectionStateDisconnected,
     RTCIceConnectionStateClosed,
     RTCIceConnectionStateCount,
     */
    UIColor *textColor = [UIColor blackColor];
    BOOL openSpeak = NO;
    switch (state) {
        case RTCIceConnectionStateCompleted:
        case RTCIceConnectionStateConnected:
            textColor = [UIColor greenColor];
            openSpeak = YES;
            break;
            
        case RTCIceConnectionStateDisconnected:
            textColor = [UIColor orangeColor];
            break;
            
        case RTCIceConnectionStateFailed:
        case RTCIceConnectionStateClosed:
            textColor = [UIColor redColor];
            break;
            
        case RTCIceConnectionStateNew:
        case RTCIceConnectionStateChecking:
        case RTCIceConnectionStateCount:
            textColor = [UIColor blackColor];
            break;
            
        default:
            break;
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *text = [NSString stringWithFormat:@"%ld", state];
        [self.playBtn setTitle:text forState:UIControlStateNormal];
        [self.playBtn setTitleColor:textColor forState:UIControlStateNormal];
        
        if (openSpeak) {
            [self.webRTCClient speakOn];
        }
//        if textColor == .green {
//            self?.webRTCClient.speakerOn()
//        }
    });
}

- (void)webRTCClient:(WebRTCClient *)client didReceiveData:(NSData *)data {
    NSLog(@"webRTCClient didReceiveData");
}


#pragma mark - Lazy
- (WebRTCClient *)webRTCClient {
    if (!_webRTCClient) {
        _webRTCClient = [[WebRTCClient alloc] initWithPublish:NO];
    }
    return _webRTCClient;
}

@end

至此,可以实现iOS端调用的ossrs视频通话拉流

其他
之前搭建ossrs服务,可以查看:https://blog.csdn.net/gloryFlow/article/details/132257196
之前实现iOS端调用ossrs音视频通话,可以查看:https://blog.csdn.net/gloryFlow/article/details/132262724
之前WebRTC音视频通话高分辨率不显示画面问题,可以查看:https://blog.csdn.net/gloryFlow/article/details/132240952
修改SDP中的码率Bitrate,可以查看:https://blog.csdn.net/gloryFlow/article/details/132263021
GPUImage视频通话视频美颜滤镜,可以查看:https://blog.csdn.net/gloryFlow/article/details/132265842
RTC直播本地视频或相册视频,可以查看:https://blog.csdn.net/gloryFlow/article/details/132267068

三、小结

WebRTC音视频通话-iOS端调用ossrs直播拉流。用到了WebRTC调用ossrs实现推拉流效果。内容较多,描述可能不准确,请见谅。

https://blog.csdn.net/gloryFlow/article/details/132417602

学习记录,每天不停进步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebRTC音视频通话-iOS端调用ossrs直播拉流 的相关文章

随机推荐

  • 配置SSH服务器使用证书登录

    服务器端配置 https www cnblogs com gyjerry p 7275242 html 客户端公钥对生成 https docs github com en github ae latest authentication co
  • python中length用法_为什么Python代码使用len()函数而不是length方法?

    为什么Python代码使用len 函数而不是length方法 我知道python有一个 len 函数 用于确定字符串的大小 但我想知道为什么它不是字符串对象的方法 更新 好吧 我意识到我很尴尬 len 实际上是一个字符串对象的方法 使用字符
  • python连接hive kerberos_JDBC 连接Hive 简单样例(开启Kerberos)

    今天在移动的云平台上通过jdbc连接hive 发现云平台使用了 kerberos的认证 与宁波实验环境不同 发现一文解决了问题 转载如下
  • IBM刀片服务器虚拟化方案

    一 IBM eServer x系列服务器的虚拟化解决方案 在IBM eServer x系列服务器上的虚拟化采用了VMware软件解决方案 通过VMware软件 搭建在操作系统和应用 以及物理平台之间的抽象层 使得每个物理系统上可运行多个虚拟
  • console.log打印结果是 [object Object] 的解决方案

    学习笔记使用 自己看的 下图是前端打印data数据的 console log data 6666666666666111 打印的时候 不能用 号 要用 使用 号的话 在控制台就会发现 输出的是 object Object console l
  • haproxy-keepalived-centos7.9相关功能实现

    nginx和haproxy的异同点 不同点 nginx可工作在四层和七层 haproxy一般工作在四层 haproxy作为负载均衡器性能比nginx优秀 如果有条件建议四层单独跑haproxy 二者的定位不同 ha定位就是负载均衡器 而ng
  • windows编译ffmpeg,并开启png的编解码器

    废话不多说了 先上下载链接 ffmpeg官方网站 http ffmpeg org download html ffmpeg源码下载链接 https ffmpeg org releases ffmpeg 3 4 13 tar gz 如果需要其
  • uniapp开发微信小程序腾讯地图功能,生成地点云的sig签名

  • 深度学习模型压缩与优化加速(Model Compression and Acceleration Overview)

    1 简介 深度学习 Deep Learning 因其计算复杂度或参数冗余 在一些场景和设备上限制了相应的模型部署 需要借助模型压缩 系统优化加速 异构计算等方法突破瓶颈 即分别在算法模型 计算图或算子优化以及硬件加速等层面采取必要的手段 模
  • HDU--1062:Text Reverse (字符串)

    1 题目源地址 http acm hdu edu cn showproblem php pid 1062 2 解题思路 这道题算是字符串中的水题 题意很简单 输入一行字符串 每个单词按照逆序输出 很容易想到利用空格来控制输出 3 解题代码
  • GO--Hello workd

    Go是一门编译型语言 Go语言的工具链将源代码及其依赖转换成计算机的机器指令 译注 静态编译 Go语言提供的工具都通过一个单独的命令go调用 go命令有一系列子命令 最简单的一个子命令就是run 这个命令编译一个或多个以 go结尾的源文件
  • 七夕要到了,快用Python比心表白吧biubiubiu

    每到各种节日 不少小伙伴们都会遇到这样一个世纪问题 怎么给心仪的女生 女朋友 老婆一个与众不同的节日惊喜 这不马上就又要到七夕了嘛 我们可以尝试用python给女朋友比心表白 就像下面这这样 下面就带大家来领略一下用Python表白的方式
  • Qt实现Http通信

    Qt学习需要http传值 研究了好几天终于可以了这里只是一个最简单的通信 我的Qt是5 7 1 在Pro内添加 QT network widget h中的源码 ifndef WIDGET H define WIDGET H include
  • sql group_contact()、concat()、concat_ws函数

    2019 08 12同事给我上了一课 以前从来没有注意过这group contact 函数 感谢同事兄弟 一 CONCAT 函数 CONCAT 函数用于将多个字符串连接成一个字符串 1 语法及使用特点 CONCAT str1 str2 返回
  • vscode代码行数显示与关闭

    vscode代码行数显示与关闭 在设置里搜索 editor lineNumbers即可
  • 毕业设计-基于深度卷积神经网络的焊缝图像滤波系统

    目录 前言 课题背景和意义 实现技术思路 一 优化网络结构 二 WIF CNN的建立与训练 三 结果与讨论 四 总结 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业
  • 【前端】Vue项目:旅游App-(10)city:以indexBar的形式显示数据

    文章目录 目标 过程与代码 分析数据并展示 封装到一个组件 添加indexBar 样式修改 优化tab栏的切换 效果 总代码 修改或新增的文件 common css city vue currentGroupCity vue main js
  • 主线程和子线程结束的关系

    一 Main线程是个非守护线程 不能设置成守护线程 原因 main线程是由java虚拟机在启动的时候创建的 main方法开始执行的时候 主线程已经创建好并在运行了 对于运行中的线程 调用Thread setDaemon 会抛出异常Excep
  • 推荐:互联网思维必读十本书

    最近在商界最流行的词汇 莫过于 互联网思维 了 互联网思维 就像一部让人垂涎的武林秘籍 得之可化腐朽为神奇 无论是小米 阿芙精油 或是卖煎饼的黄太吉 都宣称自己用互联网思维取得了巨大的胜利 那 互联网思维 究竟是什么呢 有人认为互联网思维就
  • WebRTC音视频通话-iOS端调用ossrs直播拉流

    WebRTC音视频通话 iOS端调用ossrs直播拉流 之前实现iOS端调用ossrs服务 文中提到了推流 没有写拉流流程 所以会用到文中的WebRTCClient 请详细查看 https blog csdn net gloryFlow a