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