> 技术文档 > 【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器

【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器


😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍怎么实现最简单的传输H264的RTSP服务器🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰: 2025-06-30

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、实现步骤、实现细节
    • ✨2.1、使用RTSP服务的TCP套接字并监听
    • ✨2.2、接收客户端请求并处理RTSP命令
    • ✨2.3、读取AAC音频帧并发送
  • 🎄三、传输AAC的RTSP服务器的实现源码
  • 🎄四、总结

在这里插入图片描述

前面系列文章回顾:
【RTSP从零实践】1、根据RTSP协议实现一个RTSP服务
【RTSP从零实践】2、使用RTP协议封装并传输H264
【RTSP从零实践】3、实现最简单的传输H264的RTSP服务器
【RTSP从零实践】4、使用RTP协议封装并传输AAC

【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器

🎄一、概述

这篇文章主要就是介绍怎么通过RTSP协议通信,将AAC音频数据封装成RTP包并发送的,目的是写一个最简单的RTSP服务器,熟悉RTSP协议处理、AAC数据的RTP封包。

包含了下面知识点:
1、RTSP协议的内容;
2、实现TCP协议实现RTSP;
3、RTP协议;
4、怎么实现RTP协议;
5、AAC音频数据格式;
6、AAC的RTP封包格式。

这些知识点都可以从上面 【RTSP从零实践】系列文章学习到,这篇文章不再赘述,只介绍步骤和代码。


【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器

🎄二、实现步骤、实现细节

这个小写介绍怎么实现的步骤、细节,下个小节会提供源码,可以结合着源码看帮助理解消化。

✨2.1、使用RTSP服务的TCP套接字并监听

RTSP协议是基于TCP作为传输层协议去实现的。

// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){ perror(\"socket failed\"); return -1;}// 设置套接字选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))){ perror(\"setsockopt\"); return -1;}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(RTSP_PORT);// 绑定端口if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0){ perror(\"bind failed\"); return -1;}// 开始监听if (listen(server_fd, MAX_CLIENTS) < 0){ perror(\"listen\"); return -1;}

✨2.2、接收客户端请求并处理RTSP命令

RTSP通信不直接传输音视频码流,会先进行一些命令通信,所以第二个步骤就是处理这些命令:

char response[1024] = {0}; // 构造响应if (strcmp(method, \"OPTIONS\") == 0){ rtsp_handle_OPTION(response, cseq);}else if (strcmp(method, \"DESCRIBE\") == 0){ rtsp_handle_DESCRIBE(response, cseq);}else if (strcmp(method, \"SETUP\") == 0){ rtsp_handle_SETUP(response, cseq, rtpPort);}else if (strcmp(method, \"PLAY\") == 0){ rtsp_handle_PLAY(response, cseq); bSendFlag = RTP_PLAY;}else if (strcmp(method, \"TEARDOWN\") == 0){ rtsp_handle_TEARDOWN(response, cseq); bSendFlag = RTP_STOP;}else{ snprintf(response, sizeof(response), \"RTSP/1.0 501 Not Implemented\\r\\nCSeq: %d\\r\\n\\r\\n\", cseq);}

✨2.3、读取AAC音频帧并发送

处理完RTSP命令后,就需要读取并发送RTP包了。

// aacAACReaderInfo_t aacInfo;if(AAC_FileOpen(AAC_FILE_NAME, &aacInfo) < 0){ printf(\"failed to open %s\\n\", AAC_FILE_NAME); return NULL; }while(pRtpSend->bPlayFlag) {if(!AAC_IsEndOfFile(&aacInfo)){AACFrame_t aacFrame;memset(&aacFrame, 0, sizeof(aacFrame));AAC_GetADTSFrame(&aacFrame, &aacInfo);if(aacFrame.pFrameBuf != NULL){//printf(\"rtpSendAACFrame\\n\");rtpSendAACFrame(rtp_send_fd, cli_ip, rtpPort, rtpPacket,aacFrame.pFrameBuf+ADTS_HEADER_LEN, aacFrame.frame_len-ADTS_HEADER_LEN);free(aacFrame.pFrameBuf);/* * 如果采样频率是48000 * 一般AAC每个1024个采样为一帧 * 所以一秒就有 48000 / 1024 = 47帧 * 时间增量就是 48000 / 47 = 1021 * 一帧的时间为 1000ms / 47 = 21ms */rtpPacket->rtpHeader.timestamp += 1021;usleep(21*1000);}else{printf(\"warning SeekFile\\n\"); AAC_SeekFile(&aacInfo);}} }

【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器

🎄三、传输AAC的RTSP服务器的实现源码

总共有5个源代码文件,具体如下:

1、aacReader.h

/** * @file aacReader.h * @author : https://blog.csdn.net/wkd_007 * @brief * @version 0.1 * @date 2025-06-30 * * @copyright Copyright (c) 2025 * */#ifndef__AAC_READER_H__#define __AAC_READER_H__#include #define ADTS_HEADER_LEN(7)typedef struct{int frame_len; //! unsigned char *pFrameBuf; //! } AACFrame_t;typedef struct AACReaderInfo_s{FILE *pFileFd;}AACReaderInfo_t;int AAC_FileOpen(char *fileName, AACReaderInfo_t *pAACInfo);int AAC_FileClose(AACReaderInfo_t *pAACInfo);int AAC_GetADTSFrame(AACFrame_t *pAACFrame, const AACReaderInfo_t *pAACInfo);int AAC_IsEndOfFile(const AACReaderInfo_t *pAACInfo);void AAC_SeekFile(const AACReaderInfo_t *pAACInfo);#endif // __AAC_READER_H__

2、aacReader.c

/** * @file aacReader.c * @author : https://blog.csdn.net/wkd_007 * @brief * @version 0.1 * @date 2025-06-30 * * @copyright Copyright (c) 2025 * */#include #include #include \"aacReader.h\"#define MAX_FRAME_LEN (1024*1024)// 一帧数据最大字节数#define MAX_SYNCCODE_LEN (3) // 同步码字节个数 2025-05-21 17:45:06static int findSyncCode_0xFFF(unsigned char *Buf, int *size){if((Buf[0] == 0xff) && ((Buf[1] & 0xf0) == 0xf0) )//0xFF F,前12bit都为1 2025-05-21 17:46:57 { *size |= ((Buf[3] & 0x03) <<11); //high 2 bit *size |= Buf[4]<<3; //middle 8 bit *size |= ((Buf[5] & 0xe0)>>5); //low 3bit return 1; }return 0;}int AAC_FileOpen(char *fileName, AACReaderInfo_t *pAACInfo){pAACInfo->pFileFd = fopen(fileName, \"rb+\");if (pAACInfo->pFileFd==NULL){printf(\"[%s %d]Open file error\\n\",__FILE__,__LINE__);return -1;}return 0;}int AAC_FileClose(AACReaderInfo_t *pAACInfo){if (pAACInfo->pFileFd != NULL) {fclose(pAACInfo->pFileFd);pAACInfo->pFileFd = NULL;}return 0;}int AAC_IsEndOfFile(const AACReaderInfo_t *pAACInfo){return feof(pAACInfo->pFileFd);}void AAC_SeekFile(const AACReaderInfo_t *pAACInfo){fseek(pAACInfo->pFileFd,0,SEEK_SET);}/** * @brief * * @param pAACFrame :输出参数,使用后 pAACInfo->pFrameBuf 需要free * @param pAACInfo * @return int */int AAC_GetADTSFrame(AACFrame_t *pAACFrame, const AACReaderInfo_t *pAACInfo){ int rewind = 0;if (pAACInfo->pFileFd==NULL){printf(\"[%s %d]pFileFd error\\n\",__FILE__,__LINE__);return -1;} // 1.先读取ADTS帧头(7个字节)unsigned char* pFrame = (unsigned char*)malloc(MAX_FRAME_LEN);int readLen = fread(pFrame, 1, ADTS_HEADER_LEN, pAACInfo->pFileFd);if(readLen <= 0){printf(\"[%s %d]fread error readLen=%d\\n\",__FILE__,__LINE__,readLen);free(pFrame);return -1;} // 2.查找当前帧同步码,获取帧长度 int i=0; int size = 0;for(; i<readLen-MAX_SYNCCODE_LEN; i++){if(!findSyncCode_0xFFF(&pFrame[i], &size)){continue;}else{break;}}if(i!=0)// 不是帧开头,偏移到帧开头重新读{printf(\"[%s %d]synccode error, i=%d\\n\",__FILE__,__LINE__,i);free(pFrame);rewind = (-(readLen-i));fseek (pAACInfo->pFileFd, rewind, SEEK_CUR);return -1;} // 3.读取ADTS帧数据 2025-05-22 21:44:39 readLen = fread(pFrame+ADTS_HEADER_LEN, 1, size-ADTS_HEADER_LEN, pAACInfo->pFileFd); if(readLen <= 0){printf(\"[%s %d]fread error\\n\",__FILE__,__LINE__);free(pFrame);return -1;} // 4.填数据 pAACFrame->frame_len = size; pAACFrame->pFrameBuf = pFrame;return pAACFrame->frame_len;}

3、rtp.h

#ifndef _RTP_H_#define _RTP_H_#include  #define RTP_VESION  2 #define RTP_PAYLOAD_TYPE_H264 96#define RTP_PAYLOAD_TYPE_AAC 97 #define RTP_HEADER_SIZE 12#define RTP_MAX_PKT_SIZE 1400 /* * * 0  1  2  3 * 7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |V=2|P|X| CC |M| PT | sequence number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | timestamp | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |  synchronization source (SSRC) identifier | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * | contributing source (CSRC) identifiers | * : .... : * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */struct RtpHeader{ /* byte 0 */ uint8_t csrcLen:4; uint8_t extension:1; uint8_t padding:1; uint8_t version:2; /* byte 1 */ uint8_t payloadType:7; uint8_t marker:1; /* bytes 2,3 */ uint16_t seq; /* bytes 4-7 */ uint32_t timestamp; /* bytes 8-11 */ uint32_t ssrc;}; struct RtpPacket{ struct RtpHeader rtpHeader; uint8_t payload[0];}; void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension,  uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker,  uint16_t seq, uint32_t timestamp, uint32_t ssrc);int rtpSendPacket(int socket, char* ip, int16_t port, struct RtpPacket* rtpPacket, uint32_t dataSize); #endif //_RTP_H_

4、rtp.c

#include #include #include #include #include  #include \"rtp.h\" void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension,  uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker,  uint16_t seq, uint32_t timestamp, uint32_t ssrc){ rtpPacket->rtpHeader.csrcLen = csrcLen; rtpPacket->rtpHeader.extension = extension; rtpPacket->rtpHeader.padding = padding; rtpPacket->rtpHeader.version = version; rtpPacket->rtpHeader.payloadType = payloadType; rtpPacket->rtpHeader.marker = marker; rtpPacket->rtpHeader.seq = seq; rtpPacket->rtpHeader.timestamp = timestamp; rtpPacket->rtpHeader.ssrc = ssrc;} int rtpSendPacket(int socket, char* ip, int16_t port, struct RtpPacket* rtpPacket, uint32_t dataSize){ struct sockaddr_in addr; int ret; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); rtpPacket->rtpHeader.seq = htons(rtpPacket->rtpHeader.seq); rtpPacket->rtpHeader.timestamp = htonl(rtpPacket->rtpHeader.timestamp); rtpPacket->rtpHeader.ssrc = htonl(rtpPacket->rtpHeader.ssrc); ret = sendto(socket, (void*)rtpPacket, dataSize+RTP_HEADER_SIZE, 0,  (struct sockaddr*)&addr, sizeof(addr)); rtpPacket->rtpHeader.seq = ntohs(rtpPacket->rtpHeader.seq); rtpPacket->rtpHeader.timestamp = ntohl(rtpPacket->rtpHeader.timestamp); rtpPacket->rtpHeader.ssrc = ntohl(rtpPacket->rtpHeader.ssrc); return ret;}

5、rtsp_aac_main.c

/** * @file rtsp_aac_main.c * @author : https://blog.csdn.net/wkd_007 * @brief * @version 0.1 * @date 2025-07-01 * * @copyright Copyright (c) 2025 */#include #include #include #include #include #include #include #include #include #include #include #include \"rtp.h\"#include \"aacReader.h\"#define AAC_FILE_NAME \"test.aac\"#define RTSP_PORT 8554#define RTP_PORT 55666#define MAX_CLIENTS 5#define SESSION_ID 10086001#define SESSION_TIMEOUT 60typedef struct{ int rtpSendFd; int rtpPort; int bPlayFlag; // 播放标志 char *cliIp;} RTP_Send_t;typedef enum{ RTP_NULL, RTP_PLAY, RTP_PLAYING, RTP_STOP,} RTP_PLAY_STATE;static int createUdpSocket(){ int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return -1; int on = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); return fd;}static int rtpSendAACFrame(int socket, char *ip, int16_t port, struct RtpPacket *rtpPacket, uint8_t *frame, uint32_t frameSize){ int ret; rtpPacket->payload[0] = 0x00; rtpPacket->payload[1] = 0x10; rtpPacket->payload[2] = (frameSize & 0x1FE0) >> 5; // 高8位 rtpPacket->payload[3] = (frameSize & 0x1F) << 3; // 低5位 memcpy(rtpPacket->payload + 4, frame, frameSize); ret = rtpSendPacket(socket, ip, port, rtpPacket, frameSize + 4); if (ret < 0) { printf(\"failed to send rtp packet\\n\"); return -1; } rtpPacket->rtpHeader.seq++; return 0;}void *sendRtp(void *arg){ RTP_Send_t *pRtpSend = (RTP_Send_t *)arg; int rtp_send_fd = pRtpSend->rtpSendFd; int rtpPort = pRtpSend->rtpPort; char *cli_ip = pRtpSend->cliIp;struct RtpPacket* rtpPacket = (struct RtpPacket*)malloc(sizeof(struct RtpPacket)+1500);rtpHeaderInit(rtpPacket, 0, 0, 0, RTP_VESION, RTP_PAYLOAD_TYPE_AAC, 1, 0, 0, 0x32411);// aacAACReaderInfo_t aacInfo;if(AAC_FileOpen(AAC_FILE_NAME, &aacInfo) < 0){ printf(\"failed to open %s\\n\", AAC_FILE_NAME); return NULL; }while(pRtpSend->bPlayFlag) {if(!AAC_IsEndOfFile(&aacInfo)){AACFrame_t aacFrame;memset(&aacFrame, 0, sizeof(aacFrame));AAC_GetADTSFrame(&aacFrame, &aacInfo);if(aacFrame.pFrameBuf != NULL){//printf(\"rtpSendAACFrame\\n\");rtpSendAACFrame(rtp_send_fd, cli_ip, rtpPort, rtpPacket,aacFrame.pFrameBuf+ADTS_HEADER_LEN, aacFrame.frame_len-ADTS_HEADER_LEN);free(aacFrame.pFrameBuf);/* * 如果采样频率是48000 * 一般AAC每个1024个采样为一帧 * 所以一秒就有 48000 / 1024 = 47帧 * 时间增量就是 48000 / 47 = 1021 * 一帧的时间为 1000ms / 47 = 21ms */rtpPacket->rtpHeader.timestamp += 1021;usleep(21*1000);}else{printf(\"warning SeekFile\\n\"); AAC_SeekFile(&aacInfo);}} } free(rtpPacket); AAC_FileClose(&aacInfo); return NULL;}// 解析RTSP请求void rtsp_request_parse(char *buffer, char *method, char *url, int *cseq, int *pRtpPort){ char *line = strtok(buffer, \"\\r\\n\"); sscanf(line, \"%s %s RTSP/1.0\", method, url); while ((line = strtok(NULL, \"\\r\\n\")) != NULL) { if (strncmp(line, \"CSeq:\", 5) == 0) { sscanf(line, \"CSeq: %d\", cseq); } char *pCliPort = strstr(line, \"client_port=\"); if (pCliPort != NULL) { int rtcpPort = 0; sscanf(pCliPort, \"client_port=%d-%d\", pRtpPort, &rtcpPort); // printf(\"rtpPort: %d-%d\\n\",*pRtpPort, rtcpPort); } }}// 生成SDP描述const char *generate_sdp(){ return \"v=0\\r\\n\"  \"o=- 0 0 IN IP4 0.0.0.0\\r\\n\"  \"s=Example Stream\\r\\n\"  \"t=0 0\\r\\n\"  \"m=audio 0 RTP/AVP 97\\r\\n\"  \"a=rtpmap:97 mpeg4-generic/48000/2\\r\\n\"  \"a=fmtp:97 SizeLength=13;\\r\\n\"  \"a=control:streamid=0\\r\\n\";}void rtsp_handle_OPTION(char *response, int cseq){ sprintf(response, \"RTSP/1.0 200 OK\\r\\n\" \"CSeq: %d\\r\\n\" \"Public: OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN\\r\\n\\r\\n\", cseq);}static void rtsp_handle_DESCRIBE(char *response, int cseq){ sprintf(response, \"RTSP/1.0 200 OK\\r\\n\" \"CSeq: %d\\r\\n\" \"Content-Type: application/sdp\\r\\n\" \"Content-Length: %zu\\r\\n\\r\\n%s\", cseq, strlen(generate_sdp()), generate_sdp());}static void rtsp_handle_SETUP(char *response, int cseq, int rtpPort){ sprintf(response, \"RTSP/1.0 200 OK\\r\\n\" \"CSeq: %d\\r\\n\" \"Session: %u; timeout=%d\\r\\n\" \"Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d\\r\\n\\r\\n\", cseq, SESSION_ID, SESSION_TIMEOUT, rtpPort, rtpPort + 1, RTP_PORT, RTP_PORT + 1);}static void rtsp_handle_PLAY(char *response, int cseq){ sprintf(response, \"RTSP/1.0 200 OK\\r\\n\" \"CSeq: %d\\r\\n\" \"Session: %u; timeout=%d\\r\\n\" \"Range: npt=0.000-\\r\\n\\r\\n\", cseq, SESSION_ID, SESSION_TIMEOUT);}static void rtsp_handle_TEARDOWN(char *response, int cseq){ sprintf(response, \"RTSP/1.0 200 OK\\r\\n\" \"CSeq: %d\\r\\n\" \"Session: %d; timeout=%d\\r\\n\\r\\n\", cseq, SESSION_ID, SESSION_TIMEOUT);}// 处理客户端连接int handle_client(int cli_fd, int rtp_send_fd, char *cli_ip){ int client_sock = cli_fd; char buffer[1024] = {0}; int cseq = 0; int rtpPort = 0; unsigned char bSendFlag = RTP_NULL; RTP_Send_t rtpSend; pthread_t thread_id; while (1) { memset(buffer, 0, sizeof(buffer)); int len = read(client_sock, buffer, sizeof(buffer) - 1); if (len <= 0) break; printf(\"C->S [%s]\\n\\n\", buffer); char method[16] = {0}; char url[128] = {0}; rtsp_request_parse(buffer, method, url, &cseq, &rtpPort); char response[1024] = {0}; // 构造响应 if (strcmp(method, \"OPTIONS\") == 0) { rtsp_handle_OPTION(response, cseq); } else if (strcmp(method, \"DESCRIBE\") == 0) { rtsp_handle_DESCRIBE(response, cseq); } else if (strcmp(method, \"SETUP\") == 0) { rtsp_handle_SETUP(response, cseq, rtpPort); } else if (strcmp(method, \"PLAY\") == 0) { rtsp_handle_PLAY(response, cseq); bSendFlag = RTP_PLAY; } else if (strcmp(method, \"TEARDOWN\") == 0) { rtsp_handle_TEARDOWN(response, cseq); bSendFlag = RTP_STOP; } else { snprintf(response, sizeof(response),  \"RTSP/1.0 501 Not Implemented\\r\\nCSeq: %d\\r\\n\\r\\n\", cseq); } write(client_sock, response, strlen(response)); printf(\"S->C [%s]\\n\\n\", response); if (bSendFlag == RTP_PLAY) // PLAY { rtpSend.rtpSendFd = rtp_send_fd; rtpSend.rtpPort = rtpPort; rtpSend.cliIp = cli_ip; rtpSend.bPlayFlag = 1; // 这里不使用线程的话,会一直无法处理 client_sock 发过来的 OPTION 消息,导致播放出问题 if (pthread_create(&thread_id, NULL, (void *)sendRtp, (void *)&rtpSend) < 0) { perror(\"pthread_create\"); } bSendFlag = RTP_PLAYING; } if (bSendFlag == RTP_STOP) // TEARDOWN { rtpSend.bPlayFlag = 0; pthread_join(thread_id); // 等待线程结束 bSendFlag = RTP_NULL; break; } } printf(\"close ip=[%s] fd=[%d]\\n\", cli_ip, client_sock); close(client_sock); return 0;}int main(int argc, char *argv[]){ int server_fd, client_fd; struct sockaddr_in address; int opt = 1; socklen_t addrlen = sizeof(address); // 创建套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror(\"socket failed\"); return -1; } // 设置套接字选项 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror(\"setsockopt\"); return -1; } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(RTSP_PORT); // 绑定端口 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror(\"bind failed\"); return -1; } // 开始监听 if (listen(server_fd, MAX_CLIENTS) < 0) { perror(\"listen\"); return -1; } // 用于发送 rtp 包的udp套接字 int rtp_send_fd = createUdpSocket(); if (rtp_send_fd < 0) { printf(\"failed to create socket\\n\"); return -1; } address.sin_port = htons(RTP_PORT); if (bind(rtp_send_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror(\"rtp_send_fd bind failed\"); return -1; } printf(\"RTSP Server listening on port %d\\n\", RTSP_PORT); // 主循环接受连接,目前处理一个客户端 while (1) { char cli_ip[40] = {0}; if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen)) < 0) { perror(\"accept\"); return -1; } strncpy(cli_ip, inet_ntoa(address.sin_addr), sizeof(cli_ip)); printf(\"handle cliend [%s]\\n\", cli_ip); handle_client(client_fd, rtp_send_fd, cli_ip); } return 0;}

将上面代码保存在同一个目录后,并且在同目录里放一个.aac文件,然后运行 gcc *.c -lpthread 编译,再执行./a.out运行程序,下面是我运行的过程:
【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器


【RTSP从零实践】5、实现最简单的传输AAC的RTSP服务器

🎄四、总结

本文介绍了实现介绍怎么通过RTSP协议通信,将aac音频数据封装成RTP包并发送的,也提供了实现源码和运行结果,可以帮助读者快速了解怎样实现一个最简单的RTSP服务器。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考:
https://blog.csdn.net/huabiaochen/article/details/104557971