基于UDP的流媒体实现 您所在的位置:网站首页 网络收音机开发 基于UDP的流媒体实现

基于UDP的流媒体实现

2023-12-26 05:43| 来源: 网络整理| 查看: 265

基于UDP的流媒体实现 项目简介原理图头文件的定义资源解析模块节目单发送线程模块频道发送模块流量控制模块 客户端实现客户端头文件服务端头文件

项目简介

我们通过UDP来进行流媒体的传输,主要实现音乐的发送,通过UDP来进行组播,可以对应多个客户端,客户端方面,采用mpg123来进行音月资源的解析。

原理图

在这里插入图片描述 服务端采用多线程来实现节目单和节目资源的发送,客户端采用多进程,父进程接收资源,和显示节目单,在选择节目后,将资源发送给子进程,子进程来实现资源的解析。 在server端主要需要解析文件资源模块,节目单发送线程,节目资源发送线程和流量控制模块来控制资源发送的速率,接下来我将分模块讲解一下它的实现。

头文件的定义

先看一下代码吧

#ifndef _PROTO_H_ #define _PROTO_H_ #include #define DEFAULT_MGPPOUP "239.0.0.2" //广播地址 #define DEFAULT_RCVPORT "9000" //端口 #define CHNNUM 100 //节目最大数 #define LISTCHNID 0 //节目单的id #define MINCHNID 1 //最小节目号 #define MAXCHNID (MINCHNID+CHNNUM-1) //最大节目号 #define MSG_CHANNEL_MAX (65536-20-8) //资源最大发送量 #define MAX_DATA (MSG_CHANNEL_MAX-sizeof(uint8_t)) #define MSG_LIST_MAX (65536-20-8) #define MAX_ENTRY (MSG_LIST_MAX-sizeof(uint8_t)) struct msg_channel_st //频道信息 { uint8_t chnid; //节目id uint8_t data[1]; //传输的数据 }__attribute__((packed)); //不需要对齐 struct msg_listentry_st //节目单信息 { uint8_t chnid; //节目id uint16_t len; //长度 char desc[1]; //节目单内容 }__attribute__((packed)); struct msg_list_st //节目单 { uint8_t chnid; struct msg_listentry_st entry[1]; }__attribute__((packed)); #endif // !_PROTO_H_

在这里我们定义了发送节目单的结构体,发送频道信息的结构体,来实现资源发送的实现,同时也方便文件的解析,我们主要通过变参的形式保存资源,因为我们不知道资源文件的大小。在这里我们也设置里一些必要条件的宏,因为这个头文件,会被所以的模块所包含,所以在这里定义一些,必要的参数,比如,组播的地址和端口和结构体的参数。

资源解析模块

我们来先看一下代码

/*medialib.h*/ typedef void* mytbf_t; struct mlib_listentry_st { uint8_t chnid; char* desc; }; int mlib_getchnlist(struct mlib_listentry_st**,int*); //获取节目资源 int mlib_freechnlist(struct mlib_listentry_st*); //释放文件资源 int mlib_readchn(uint8_t, void*, size_t); //读取指定的节目资源

这是解析资源文件的头文件,主要就是访问资源文件夹,将节目资源的简介和节目号读取,通过在主线程传入mli_listentry_st的指针,在获取文件资源的函数中,来实现传入参数的赋值,所以获取文件资源的函数中,我们传入里结构体指针的指针,同时,我们也要获取到资源的数量,通过要发送资源的数量,我们来指定资源线程的数量。

节目单发送线程模块

先上代码

/*thr_list.h*/ #pragma once #include "medialib.h" //创建发送线程 int thr_list_create(struct mlib_listentry_st*,int); //线程的销毁 int thr_list_destroy(void);

节目单发送线程就比较简单了,主要在主线程,我们将解析出来的文件结构体传入,之后我们创建线程,来实现节目单的定时发送,就可以了将节目单资源发送过去了。

频道发送模块

频道发送模块和节目单发送线程在定义的头文件上是差不多的,但是在这里我们增加了线程的指定销毁。因为我们要调用资源解析中用到的函数,所以我们才包含了mediali.h的头文件。

#pragma once #include "medialib.h" int thr_channel_create(struct mlib_listentry_st*); int thr_channel_destroy(struct mlib_listentry_st*); int thr_channel_destroyall(void); 流量控制模块 /*mytbf.h*/ #pragma once #define MYTBF_MAX 1024 typedef void* mytbf_t; mytbf_t* mytbf_init(int cps, int burst); //速率和上限 int mytbf_fetchtoken(mytbf_t*,int); //获取令牌 int mytbt_returntoken(mytbf_t*,int); //归还令牌 int mytbf_destroy(mytbf_t*); //销毁

流量控制,就是控制发送的速率,我们可以通过mytbf_init来设置每次发送的速率,通过获取令牌,来获得发送的权限,实现资源发送的速率,因为发送流媒体资源,我们要控制资源的发送的速率,来实现音乐的播放。

客户端实现 客户端头文件 #ifndef _CLIENT_H_ #define _CLIENT_H_ #define DEFAULT_PLAYERCMD "/usr/bin/mpg123 - > /dev/null" struct client_conf_st { const char* rcvport; const char* mgroup; const char* player_cmd; }; int writen(int fd, const void* vptr, int n); extern struct client_conf_st client_conf; #endif // !_CLIENT_H_

我们来创建一个客户端的结构体,来指定接收端口,组播地址和媒体解析器,同时我们会在客户端fork出子进程,来调用解析器,解析父进程发送过来的资源文件,父进程主要的功能就是,接收节目单资源和频道资源,并且选择指定的频道资源,将资源发送个子进程。

服务端头文件 #pragma once #define DEFAULT_MEDIADIR "/var/media" #define DEFAULT_IF "ens33" #include #include enum { run_daemon = 1, run_foregrounp }; static int daemonize(); struct server_conf_st { const char* rcvport; //绑定的ip const char* mgroup; //广播地址 const char* media_dir; //资源文件 const char* runmode; //运行模式 const char* ifname; //网卡信息 }; extern int listenfd; extern struct sockaddr_in clientaddr; extern socklen_t clientaddr_len;

在后续我会将我的项目发送到github中,在这里就不在多说了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有