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}