JRTP实时音视频传输(2)-使用TCP通信的案例

news2024/11/27 0:45:20

1.创建自己的demo

先将example1拷贝为myclienttcp.cpp和myservertcp.cpp
cp example1.cpp myclienttcp.cpp
cp example1.cpp myservertcp.cpp

改写jrtplib/JRTPLIB/examples/CMakeLists.txt,添加myclienttcp和myservertcp编译
image.png
重新生成Makefile并编译

sudo cmake CMakeLists.txt
sudo make

可以看到成功编译了myclienttcp和myservertcp源文件
image.png
编译通过,这里就去实现demo就行

2.demo源码-客户端

#include <iostream>
#include <arpa/inet.h>
#include "rtptcpaddress.h"
#include "rtpsession.h"
#include "rtpsessionparams.h"
#include "rtptcptransmitter.h"
#include "rtpipv4address.h"
#include "rtptimeutilities.h"
#include "rtppacket.h"
#include "rtpabortdescriptors.h"

using namespace jrtplib;

#define SERVER_IP    "127.0.0.1"
#define SERVER_PORT  58008

int main()
{
    RTPSession session;
    RTPAbortDescriptors m_descriptors;

    RTPSessionParams sessionparams;
    sessionparams.SetAcceptOwnPackets(true);
    sessionparams.SetOwnTimestampUnit(1.0/10.0);

    m_descriptors.Init();

    RTPTCPTransmissionParams transparams;
    transparams.SetCreatedAbortDescriptors(&m_descriptors);
    int status = session.Create(sessionparams,&transparams,RTPTransmitter::TCPProto);

    if (status < 0)
    {
        printf("my client session create failed\n");
        return -1;
    }

    //初始化socket
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in addrSrv;
    addrSrv.sin_addr.s_addr = inet_addr(SERVER_IP);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(SERVER_PORT);

    printf("my client prepare to connect\n");

    //连接服务器
    connect( sock, (sockaddr*)&addrSrv, sizeof(sockaddr));

    RTPTCPAddress addr(sock);

    status = session.AddDestination(addr);
    if (status < 0)
    {
        printf("my client session add destination failed\n");
        return -1;
    }

    session.SetDefaultPayloadType(96);
    session.SetDefaultMark(false);
    session.SetDefaultTimestampIncrement(160);

    for (int i = 0; i < 50 ; i++)
        {
            std::string str("123456");
            //发送数据
            session.SendPacket((void *)str.c_str(), str.length(),0,false,10);

            printf("my client send packet:%s, len:%d, idx:%d\n", str.c_str(), str.length(), i);
            RTPTime::Wait(RTPTime(10, 0));
        }

    RTPTime delay(0.020);
    session.BYEDestroy(delay,"Client End",9);
}

3.demo源码-服务端

/*
   Here's a small IPv4 example: it asks for a portbase and a destination and 
   starts sending packets to that destination.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include "rtppacket.h"
#include "rtptcpaddress.h"
#include "rtptcptransmitter.h"
#include "rtpsession.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtplibraryversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace jrtplib;

#define SERVER_PORT  58008

void checkerror(int rtperr)
{
	if (rtperr < 0)
	{
		std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
		exit(-1);
	}
}

int main(void)
{
    int   nListener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (nListener == -1)
	{
		return  -1;
	}
 
	sockaddr_in   serverAddr;
	memset(&serverAddr, 0, sizeof(sockaddr_in));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = INADDR_ANY;
	serverAddr.sin_port = htons(SERVER_PORT);
	int  nRet = bind(nListener, (sockaddr*)&serverAddr, sizeof(serverAddr));
	if (nRet == -1)
	{
		return  -1;
	}
	if (listen(nListener, 1) == -1)
	{
		return  -1;
	}
 
	printf("my server is listen ready, wait for connect\n");

	sockaddr_in   clientAddr;
	int  nLen = sizeof(sockaddr_in);
	int   nServer = -1;
	while (true)
	{
		nServer = accept(nListener, (sockaddr*)&clientAddr, (socklen_t *)&nLen);
		if (nServer == -1)
		{
			continue;
		}
		else
		{
			break;
		}
	}
	printf("my server connect new client\n");

	int status = -1;
	int  nPackSize = 45678;
	RTPSessionParams   sessparams;
	RTPSession m_RTPTCPSession;

	sessparams.SetProbationType(RTPSources::NoProbation);
	sessparams.SetOwnTimestampUnit(90000.0 / 25.0);
	sessparams.SetMaximumPacketSize(nPackSize + 64);

	RTPTCPTransmitter    *pTransparams =  new RTPTCPTransmitter(NULL);
	status = pTransparams->Init(false);
	if (status < 0)
	{
		printf("my server trans param init failed, reason:%s\n", RTPGetErrorString(status).c_str());
        return -1;		
	}
	status = pTransparams->Create(65535, NULL);
	if (status < 0)
	{
        printf("my server trans param create failed, reason:%s\n", RTPGetErrorString(status).c_str());
        return -1;		
	}

	status = m_RTPTCPSession.Create(sessparams, pTransparams);
	if (status < 0)
	{
        printf("my server trans session create failed, reason:%s\n", RTPGetErrorString(status).c_str());
        return -1;		
	}
	status = m_RTPTCPSession.AddDestination(RTPTCPAddress(nServer));
	if (status < 0)
	{
        printf("my server trans session add failed, reason:%s\n", RTPGetErrorString(status).c_str());
        return -1;		
	}

	while (1)
	{	
		m_RTPTCPSession.BeginDataAccess();
		
		// check incoming packets
		if (m_RTPTCPSession.GotoFirstSourceWithData())
		{
			do
			{
				RTPPacket *pack;
				
				while ((pack = m_RTPTCPSession.GetNextPacket()) != NULL)
				{
					// You can examine the data here
					printf("myserver recv packet buf:%s, len:%d\n", pack->GetPayloadData(), pack->GetPayloadLength());
					
					// we don't longer need the packet, so
					// we'll delete it
					m_RTPTCPSession.DeletePacket(pack);
				}
			} while (m_RTPTCPSession.GotoNextSourceWithData());
		}
		
		m_RTPTCPSession.EndDataAccess();

#ifndef RTP_SUPPORT_THREAD
		status = m_RTPTCPSession.Poll();
		checkerror(status);
#endif // RTP_SUPPORT_THREAD
		
		RTPTime::Wait(RTPTime(1,0));
	}
	
	m_RTPTCPSession.BYEDestroy(RTPTime(10,0),0,0);

	return 0;
}


4.demo运行测试

分别运行client和server ,可以看到数据正常传输到server端
image.png
用netstat查看连接端口信息,也能看到该端口目前的状态,属于TCP连接,实验成功
image.png

对环境搭建不清楚的可以看这篇博客~
JRTP实时音视频传输(1)-必做的环境搭建与demo测试

5.源码下载

哈喽~我是Embedded-Xin,沪漂嵌入式开发工程师一枚,立志成为嵌入式全栈开发工程师,成为优秀博客创作者,共同学习进步。
以上代码全部放在我私人的github地址,其中有许多自己辛苦敲的例程源码,供大家参考、批评指正,有兴趣还可以直接提patch修改我的仓库~:
https://github.com/Xuzhangxin/study_linux_project.git
觉得不错的话可以点个收藏和star~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1393207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

powershell脚本 判断NLB是否已安装

bat脚本&#xff1a;456.bat REM REM 解决下载的时候字符乱码的问题 chcp 65001 echo offREM 管理员运行powershell脚本 PUSHD %~DP0 & cd /d "%~dp0" %1 %2 mshta vbscript:createobject("shell.application").shellexecute("%~s0","…

白山云基于StarRocks数据库构建湖仓一体数仓的实践

背景 随着每天万亿级别的业务数据流向数据湖&#xff0c;数据湖的弊端也逐渐凸显出来&#xff0c;例如&#xff1a; 数据入湖时效性差&#xff1a;数据湖主要依赖于离线批量计算&#xff0c;通常不支持实时数据更新&#xff0c;因此无法保证数据的强一致性&#xff0c;造成数…

<软考高项备考>《论文专题 - 73 风险管理(5)》

5 过程4-实施定量风险分析 5.1 问题 4W1H过程做什么是就已识别的单个项目风险和不确定性的其他来源对整体项目目标的影响进行定量分析的过程。作用:1、量化整体项目风险最大可能性;2、提供额外的定量风险信息&#xff0c;以支持风险应对规划。为什么做了解风险对项目整体目标…

【STM32调试】寄存器调试不良问题记录持续版

STM32寄存器调试不良问题记录 NVIC&#xff08;内嵌的中断向量控制器&#xff09;EXTI&#xff08;外部中断/事件&#xff09; 记录一些stm32调试过程中&#xff1a;不易被理解、存在使用误区、不清不楚、是坑、使用常识等方面的一些记录。本记录只包含stm32的内核以及外设等寄…

node.js(express.js)+mysql实现注册功能

文章目录 实现步骤一、获取客户端提交到服务器的用户信息&#xff0c;对表单中的数据&#xff0c;进行合法性的效验 代码如下:二、检测用户名是否被占用三、对密码进行加密四、插入新用户&#xff08;完整代码&#xff09;总结 实现步骤 一、获取客户端提交到服务器的用户信息…

社交商业革命:Facebook Shops的崛起

近年来&#xff0c;社交媒体逐渐演变为不仅仅是社交的平台&#xff0c;更是商业活动的重要场所。在这个潮流的浪潮中&#xff0c;Facebook Shops的崛起正引领着一场社交商业的革命&#xff0c;为企业和消费者带来了全新的体验。 点击添加图片描述&#xff08;最多60个字&#x…

0间隔24h采集线报+源码的资源网

一款网站程序零间隔24h采集线报源码的资源网&#xff0c;更新下载类目的采集 及 导入&#xff0c;这款网站程序&#xff1a;jizhiCMS 高仿新版某刀资源网模板进行自动采集。 安装方法&#xff1a; 将根目录文件上传服务器 将根目录文件的sql.sql导入mysql数据库 环境需要支…

Vue-19、Vue监测数据的原理_对象

1、数据代理 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>vue监测数据改变的的原理</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist…

在线App封装技术:HTML5的新生命

HTML5封装的魅力所在HTML5带来了丰富的多媒体功能、地理位置服务、离线存储等特性&#xff0c;使得Web应用的体验更加接近原生App。封装HTML5到App中&#xff0c;可以大大缩短开发周期&#xff0c;降低开发成本&#xff0c;并且一次编写&#xff0c;多平台运行&#xff0c;极大…

西瓜书读书笔记整理(十一) —— 第十一章 特征选择与稀疏学习

第十一章 特征选择与稀疏学习 11.1 子集搜索与评价11.1.1 基本概念11.1.2 为什么要进行特征选择11.1.3 特征选择的两个关键环节11.1.4 常见的特征选择方法11.1.5 其他问题 11.2 过滤式选择11.2.1 什么是过滤式选择方法11.2.2 过滤式选择的优缺点 11.3 包裹式选择11.3.1 什么是包…

Spring 中 HttpServletRequest 作为成员变量是安全的吗?

在使用spring框架开发的时候&#xff0c;经常会在controller类中看到 HttpServletRequest 对象参数&#xff0c;一般我们都是直接使用&#xff0c;但是它是何时、怎么注入到 spring 容器的呢 &#xff1f;另外以成员变量注入的 request 是线程安全的吗 ? Controller public c…

Tuxera NTFS2024下载使用详细操作教程

你是否还在为Mac不能正常读写NTFS格式分区而感到苦恼呢&#xff1f;想要适合Mac系统使用来回转换磁盘格式又十分麻烦&#xff0c;这该怎么办呢&#xff0c;有了这款软件Tuxera ntfs就能马上帮你解决目前遇到的问题。 Tuxera NTFS2024最新免费版下载如下&#xff1a; https://…

mysql从库重新搭建的流程

背景 生产环境上的主从集群&#xff0c;因为一些异常原因&#xff0c;导致主从同步失败。现记录下通过重做mysql从库的方式来解决&#xff0c;重做过程不影响主库。 步骤 1、在主库上的操作步骤 备份主库所有数据&#xff0c;并将dump.sql文件拷贝到从库/tmp目录 mysqldump …

Verilog刷题笔记17

题目&#xff1a; For hardware synthesis, there are two types of always blocks that are relevant: Combinational: always (*) Clocked: always (posedge clk) Clocked always blocks create a blob of combinational logic just like combinational always blocks, but …

SQL-窗口函数

什么是窗口函数 可以像聚合函数一样对一组数据进行分析并返回结果&#xff0c;二者的不同之处在于&#xff0c;窗口函数不是将一组数据汇总成单个结果&#xff0c;而是为每一行数据都返回一个结果。 窗口函数组成部分 1.创建数据分区 窗口函数OVER子句中的PARTITION BY选项用…

顶顶通呼叫中心中间件自动外呼来电转人工显示被叫号码而不是显示路由条件 :一步步配置(mod_cti基于FreeSWITCH)

介绍 顶顶通呼叫中心中间件自动外呼来电转人工显示被叫号码而不是显示自动外呼的路由条件&#xff0c;可以是默认的被叫号码也可以改为显示指定的号码 一、显示默认被叫 1、配置拨号方案 打开ccadmin-》点击拨号方案-》找到进入排队-》配置跟图中一样的通道变量。修改了拨号…

一篇综述洞悉医学大型语言模型的原理,应用和挑战

在过去的一年中&#xff0c;随着 GPT-4、LLaMA、Mistral&#xff0c;PaLM 等先进技术的突飞猛进&#xff0c;大型语言模型&#xff08;Large Language Models&#xff09;已经引领全球人工智能进入了一个全新的基础模型时代&#xff0c;这一时代不仅开启了技术创新的新篇章&…

7.5 MySQL对数据的增改删操作(❤❤❤)

7.5 MySQL对数据的基本操作 1. 提要2. 数据添加2.1 insert语法2.2 insert 子查询2.3 ignore关键字 3. 数据修改3.1 update语句3.2 update表连接 4. 数据删除4.1 delete语句4.2 delete表连接4.3 快速删除数据表全部数据 1. 提要 2. 数据添加 2.1 insert语法 2.2 insert 子查询 …

【文档数据库】ES和MongoDB的对比

目录 1.由文档存储牵出的问题 2.什么是MongoDB&#xff1f; 3.ES和MongoDB的对比 1.由文档存储牵出的问题 本文或者说关于mongodb的这个系列文章的源头&#xff1a; 前面我们聊过了分布式链路追踪系统&#xff0c;在基于日志实现的分布式链路追踪的方式seluthzipkin中为了…

selenium爬虫爬取当当网书籍信息 | 最新!

如果对selenium不了解的话可以到下面的链接中看基础内容&#xff1a; selenium爬取有道翻译-CSDN博客 废话不多说了下面是代码并且带有详细的注释&#xff1a; 爬取其他类型的书籍和下面基本上是类似的可以自行更改。 # 导入所需的库 from selenium import webdriver from …