• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <chrono>
18 #include <fstream>
19 #include <functional>
20 #include <getopt.h>
21 #include <netinet/in.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <thread>
28 #include <unistd.h>
29 #include "codec_factory.h"
30 #include "common/sharing_log.h"
31 #include "frame.h"
32 #include "media_frame_pipeline.h"
33 #include "media_player.h"
34 #include "rtp_def.h"
35 #include "rtp_factory.h"
36 
37 using namespace OHOS::Sharing;
38 
39 int gType = -1; // 0 for G.711
40 char *gInFile = nullptr;
41 int gPort = 0;
42 #define BUFF_SIZE 10240
43 
ShowUsage(char * exe)44 void ShowUsage(char *exe)
45 {
46     SHARING_LOGD("usage:\n%{public}s -i <in file> [-p <local port>]", exe);
47     SHARING_LOGD("\t-t 0: play g711 alaw file, 1: play g711 RTP stream");
48     SHARING_LOGD("\t-i in file");
49     SHARING_LOGD("\t-p local rtp port");
50 }
51 
ParseParam(int argc,char * argv[])52 int ParseParam(int argc, char *argv[])
53 {
54     int ret;
55 
56     while ((ret = getopt(argc, argv, ":t:i:p:")) != -1) {
57         switch (ret) {
58             case ('t'):
59                 gType = atoi(optarg);
60                 break;
61             case ('i'):
62                 gInFile = optarg;
63                 break;
64             case ('p'):
65                 gPort = atoi(optarg);
66                 break;
67             case ':':
68                 SHARING_LOGD("option [-%c] requires an argument.", static_cast<char>(optopt));
69                 break;
70             case '?':
71                 SHARING_LOGD("unknown option: %c.", static_cast<char>(optopt));
72                 break;
73             default:
74                 break;
75         }
76     }
77 
78     if (!((gType == 0 && gInFile != nullptr) || (gType == 1 && gPort > 0))) {
79         SHARING_LOGD("param error");
80         ShowUsage(argv[0]);
81         return -1;
82     }
83 
84     return 0;
85 }
86 
87 class RawDataReceiver : public FrameDestination {
88 public:
RawDataReceiver(const std::shared_ptr<MediaPlayer> & player)89     RawDataReceiver(const std::shared_ptr<MediaPlayer> &player) : player_(player) {}
90 
91     ~RawDataReceiver() = default;
92 
OnFrame(const Frame::Ptr & frame)93     void OnFrame(const Frame::Ptr &frame) override
94     {
95         player_->OnData((uint8_t *)frame->Data(), (size_t)frame->Size(), true);
96         SHARING_LOGD("recv decoded data(%p) len(%{public}d)", frame->Data(), frame->Size());
97         for (int i = 0; i < 12 && i < frame->Size(); i++) {
98             printf("%02x ", *(frame->Data() + i));
99         }
100         printf("\n");
101     }
102 
103 private:
104     std::shared_ptr<MediaPlayer> player_;
105 };
106 
InitMediaPlayer(int channels,int sampleRate)107 std::shared_ptr<MediaPlayer> InitMediaPlayer(int channels, int sampleRate)
108 {
109     std::shared_ptr<MediaPlayer> player = std::make_shared<MediaPlayer>();
110     player->SetAudioParameter(channels, sampleRate);
111     player->Prepare();
112     player->Play();
113     return player;
114 }
115 
DecodeG711ByTime(char * data,int length)116 void DecodeG711ByTime(char *data, int length)
117 {
118     std::shared_ptr<AudioDecoder> decoder = CodecFactory::CreateAudioDecoder(CODEC_G711A);
119     if (!decoder) {
120         return;
121     }
122 
123     decoder->Init();
124     // set audio paramters
125     int sampleRate = 44100;
126     int channel = 1;
127 
128     std::shared_ptr<MediaPlayer> player = InitMediaPlayer(channel, sampleRate);
129 
130     auto rawReceiver = std::make_shared<RawDataReceiver>(player);
131 
132     decoder->AddAudioDestination(rawReceiver);
133     auto g711Frame = FrameImpl::Create();
134     g711Frame->codecId_ = CODEC_G711A;
135     char *p = data;
136 
137     std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
138     std::chrono::microseconds interval = std::chrono::milliseconds(20); // 20 ms, 50 packets/second
139     int packSize = (sampleRate / 50) * channel;
140     SHARING_LOGD("sampleRate: %{public}d, channel: %{public}d, packSize per 20ms: %{public}d", sampleRate, channel,
141                  packSize);
142     for (int i = 0; i < length / packSize; i++) {
143         SHARING_LOGD("for i(%{public}d)", i);
144         g711Frame->Clear();
145         g711Frame->Assign(p, packSize);
146         decoder->OnFrame(g711Frame);
147         p += packSize;
148         std::this_thread::sleep_until(start + interval * i);
149     }
150 
151     SHARING_LOGD("decodeG711ByTime line(%{public}d).", __LINE__);
152 }
153 
DecodeG711Immediately(char * data,int length)154 void DecodeG711Immediately(char *data, int length) {}
155 
RecvUDP(const std::function<void (const char * buf,int len)> & cb)156 int RecvUDP(const std::function<void(const char *buf, int len)> &cb)
157 {
158     int servSocket, nbytes;
159     struct sockaddr_in servAddr, cliAddr;
160     int addrLen = sizeof(cliAddr);
161     char buffer[BUFF_SIZE];
162 
163     if ((servSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
164         perror("socket err");
165         return -1;
166     }
167 
168     bzero(&servAddr, sizeof(servAddr));
169 
170     servAddr.sin_family = AF_INET;
171     servAddr.sin_port = htons(gPort);
172     servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
173 
174     if (bind(servSocket, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
175         perror("bind err");
176         return -1;
177     }
178 
179     while (1) {
180         if ((nbytes = recvfrom(servSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliAddr,
181                                (socklen_t *)&addrLen)) < 0) {
182             perror("recvfrom err");
183             return -1;
184         }
185 
186         SHARING_LOGD("\nRecv data(size:%{public}d) From %{public}s:%{public}d", nbytes, inet_ntoa(cliAddr.sin_addr),
187                      ntohs(cliAddr.sin_port));
188 
189         cb(buffer, nbytes);
190         memset(buffer, 0, BUFF_SIZE);
191     }
192 }
193 
main(int argc,char * argv[])194 int main(int argc, char *argv[])
195 {
196     SHARING_LOGD("trace");
197     if (ParseParam(argc, argv) != 0) {
198         return -1;
199     }
200 
201     // play local g711 file
202     if (gType == 0) {
203         std::fstream infile(gInFile, std::ios::in | std::ios_base::binary);
204         if (!infile.is_open()) {
205             SHARING_LOGD("failed to open file");
206             return -1;
207         }
208 
209         infile.seekg(0, std::ios::end);
210         int size = infile.tellg();
211         infile.seekg(0, std::ios::beg);
212 
213         char *content = new char[size];
214         infile.read(content, size);
215         SHARING_LOGD("size %{public}d.", size);
216         infile.close();
217 
218         DecodeG711ByTime(content, size);
219         delete[] content;
220     } else if (gType == 1) {
221         // recv rtp g711 stream,  decode rtp, play
222 
223         std::shared_ptr<AudioDecoder> decoder = CodecFactory::CreateAudioDecoder(CODEC_G711A);
224         if (!decoder) {
225             return -1;
226         }
227 
228         decoder->Init();
229         std::shared_ptr<MediaPlayer> player = InitMediaPlayer(2, 8000);
230         auto rawReceiver = std::make_shared<RawDataReceiver>(player);
231         decoder->AddAudioDestination(rawReceiver);
232 
233         auto g711Unpack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{97, 8000, RtpPayloadStream::PCMA});
234         g711Unpack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
235             SHARING_LOGD("setOnRtpUnpack");
236             if (frame->GetTrackType() == TRACK_AUDIO) {
237                 SHARING_LOGD("unpack G711 rtp: len: %{public}d dts: %{public}d.", frame->Size(), frame->Dts());
238                 for (int i = 0; i < 0x12 && i < static_cast<int>(frame->Size()); i++) {
239                     printf("%02x ", *(frame->Data() + i));
240                 }
241                 printf("\n");
242 
243                 decoder->OnFrame(frame);
244             }
245         });
246 
247         RecvUDP([g711Unpack](const char *buf, int len) {
248             // print data (12B RTP header + 12B Payload)
249             for (int i = 0; i < 24 && i < len; i++) {
250                 printf("%02x ", buf[i] & 0xff);
251                 if (i == 11) {
252                     printf("\n");
253                 }
254             }
255             printf("\n");
256             g711Unpack->ParseRtp(buf, len);
257         });
258     }
259 }