1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <arpa/inet.h>
17 #include <condition_variable>
18 #include <functional>
19 #include <getopt.h>
20 #include <memory>
21 #include <mutex>
22 #include <netinet/in.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29 #include "rtp_def.h"
30 #include "rtp_factory.h"
31 #include "rtsp_client.h"
32 #include "sharing_log.h"
33
34 using namespace OHOS::Sharing;
35
36 #define RTP_AUDIO_LOCAL_PORT 60000
37 #define RTP_VIDEO_LOCAL_PORT 60002
38 #define BUFF_SIZE 10240
39
40 FILE *h264File = nullptr;
41 FILE *aacFile = nullptr;
42
HandleSignal(int sig)43 void HandleSignal(int sig)
44 {
45 if (h264File) {
46 fclose(h264File);
47 }
48
49 if (aacFile) {
50 fclose(aacFile);
51 }
52
53 printf("Catch Ctrl+C, exit success.\n");
54 exit(0);
55 }
56
RecvUDP(int port,const std::function<void (const char * buf,int len)> & cb)57 int RecvUDP(int port, const std::function<void(const char *buf, int len)> &cb)
58 {
59 int servSocket, nbytes;
60 struct sockaddr_in servAddr, cliAddr;
61 int addrLen = sizeof(cliAddr);
62 char buffer[BUFF_SIZE];
63
64 if ((servSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
65 perror("socket err");
66 return -1;
67 }
68
69 bzero(&servAddr, sizeof(servAddr));
70
71 servAddr.sin_family = AF_INET;
72 servAddr.sin_port = htons(port);
73 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
74
75 if (bind(servSocket, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
76 perror("bind err");
77 return -1;
78 }
79
80 while (1) {
81 if ((nbytes = recvfrom(servSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliAddr,
82 (socklen_t *)&addrLen)) < 0) {
83 perror("recvfrom err");
84 return -1;
85 }
86
87 printf("\nRecv data(size:%d) From %s:%d\n", nbytes, inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
88
89 cb(buffer, nbytes);
90 memset(buffer, 0, BUFF_SIZE);
91 }
92 }
93
RecvSaveH264()94 void RecvSaveH264()
95 {
96 if (!h264File) {
97 time_t t = time(nullptr);
98 std::string file = "RTP_" + std::to_string(t) + ".h264";
99 h264File = fopen(file.c_str(), "wb");
100 if (!h264File) {
101 return;
102 }
103 printf("Save H264 (%s)\n", file.c_str());
104 }
105
106 auto h264unPack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{96, 90000, RtpPayloadStream::H264});
107 h264unPack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
108 if (frame->GetTrackType() == TRACK_VIDEO) {
109 printf("h264 data: len: %d dts: %d\n", frame->Size(), frame->Dts());
110 auto data = frame->Data();
111 auto bytes = frame->Size();
112 for (size_t i = 0; i < 16 && i < bytes; i++) {
113 printf("%02x ", data[i] & 0xff);
114 }
115 printf("\nfwrite (len: %d)\n", frame->Size());
116 fwrite(frame->Data(), frame->Size(), 1, h264File); // save .h264 file
117 }
118 });
119
120 RecvUDP(RTP_VIDEO_LOCAL_PORT, [h264unPack](const char *buf, int len) {
121 // print data (12B RTP header + 12B Payload)
122 for (size_t i = 0; i < 24 && i < len; i++) {
123 printf("%02x ", buf[i] & 0xff);
124 if (i == 11) {
125 printf("\n");
126 }
127 }
128 printf("\n");
129 h264unPack->ParseRtp(buf, len);
130 });
131 }
132
main(int argc,char * argv[])133 int main(int argc, char *argv[])
134 {
135 auto rtspClient = std::make_shared<RtspClient>();
136 std::vector<OHOS::Sharing::SdpTrack::Ptr> medias;
137 uint32_t trackIndex = 0;
138 std::mutex mutex;
139 std::condition_variable cvSignal;
140 std::string url(argv[1]);
141
142 // Catch Ctrl+C cvSignal
143 signal(SIGINT, HandleSignal);
144
145 rtspClient->SetUrl(url);
146 rtspClient->SetOnRecvRtspPacket([&](const std::string &method, const RtspMessage &rsp) {
147 printf("SetOnRecvRtspPacket method: %s\n", method.c_str());
148 if (method == "OPTIONS") {
149 printf("SetOnRecvRtspPacket OPTIONS");
150 auto err = rtspClient->HandleOptionRsp(rsp);
151 switch (err) {
152 case RtspRspResult::RSP_UNAUTHED:
153 rtspClient->SendOption();
154 break;
155 case RtspRspResult::RSP_OK:
156 rtspClient->SendDescribe();
157 break;
158 default: {
159 printf("SetOnRecvRtspPacket ret err");
160 cvSignal.notify_one();
161 } break;
162 }
163
164 } else if (method == "DESCRIBE") {
165 printf("SetOnRecvRtspPacket DESCRIBE");
166 auto err = rtspClient->HandleDescribeRsp(rsp);
167 switch (err) {
168 case RtspRspResult::RSP_UNAUTHED:
169 rtspClient->SendDescribe();
170 break;
171 case RtspRspResult::RSP_OK: {
172 auto mediaTemp = rtspClient->GetAllMedia();
173 for (auto media : mediaTemp) {
174 medias.emplace_back(media);
175 }
176 // set RTP listening port for a/v, may just use one port
177 rtspClient->SetTransPort(RTP_AUDIO_LOCAL_PORT, TRACK_AUDIO);
178 rtspClient->SetTransPort(RTP_VIDEO_LOCAL_PORT, TRACK_VIDEO);
179 rtspClient->SendSetup(trackIndex++);
180
181 break;
182 }
183 default: {
184 printf("SetOnRecvRtspPacket ret err");
185 cvSignal.notify_one();
186 break;
187 }
188 }
189 } else if (method == "SETUP") {
190 printf("SetOnRecvRtspPacket SETUP");
191 auto err = rtspClient->HandleSetupRsp(rsp);
192 switch (err) {
193 case RtspRspResult::RSP_OK:
194 if (trackIndex < medias.size()) {
195 rtspClient->SendSetup(trackIndex++);
196 } else {
197 rtspClient->SendPlay();
198 trackIndex = 0;
199 }
200 break;
201 default: {
202 printf("SetOnRecvRtspPacket ret err");
203 cvSignal.notify_one();
204 } break;
205 }
206 } else if (method == "PLAY") {
207 printf("SetOnRecvRtspPacket PLAY");
208 auto err = rtspClient->HandlePlayRsp(rsp);
209 if (err != RtspRspResult::RSP_OK) {
210 printf("SetOnRecvRtspPacket ret err");
211 cvSignal.notify_one();
212 }
213
214 RecvSaveH264();
215
216 cvSignal.notify_one();
217 }
218 });
219
220 rtspClient->SetExceptionCb([&](const RtspExceptType except) {
221 printf("OnRtspException err");
222 printf("%s %d\n", __FUNCTION__, __LINE__);
223 cvSignal.notify_one();
224 });
225
226 rtspClient->SetRtspReadyCb([&]() {
227 printf("%s %d send Option\n", __FUNCTION__, __LINE__);
228 rtspClient->SendOption();
229 });
230
231 if (!rtspClient->Open()) {
232 printf("OpenRtspClient err");
233 return 0;
234 }
235
236 std::unique_lock<std::mutex> lk(mutex);
237 cvSignal.wait(lk);
238 return 0;
239 };