1 /*
2  * Copyright (c) 2024 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 "audio_pcm_processor.h"
17 #include "const_def.h"
18 #include "sharing_log.h"
19 
20 namespace OHOS {
21 namespace Sharing {
22 constexpr uint32_t LPCM_PES_PAYLOAD_PRIVATE_SIZE = 4;
23 constexpr uint32_t LPCM_PES_PAYLOAD_DATA_SIZE = 1920;
24 constexpr uint32_t LPCM_PES_PAYLOAD_TIME_DURATION = 10;
25 constexpr uint32_t FIFO_SAMPLES = 3840;
26 constexpr uint8_t AUDIO_SAMPLING_FREQUENCY_48K = 2 << 3;
27 constexpr uint8_t NUMBER_OF_AUDIO_CHANNEL_STEREO = 1;
28 
29 static std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
30 static uint64_t duration = 0;
31 static uint8_t data[LPCM_PES_PAYLOAD_DATA_SIZE];
32 
AudioPcmProcessor()33 AudioPcmProcessor::AudioPcmProcessor()
34 {
35     SHARING_LOGD("trace.");
36 }
37 
~AudioPcmProcessor()38 AudioPcmProcessor::~AudioPcmProcessor()
39 {
40     av_audio_fifo_free(fifo_);
41     SHARING_LOGD("trace.");
42 }
43 
Init(uint32_t channels, uint32_t sampleBit, uint32_t sampleRate)44 int32_t AudioPcmProcessor::Init(uint32_t channels, uint32_t sampleBit, uint32_t sampleRate)
45 {
46     channels_ = channels;
47     sampleBit_ = sampleBit;
48     sampleRate_ = sampleRate;
49     if (channels_ == 0 || sampleBit_ == 0 || sampleRate_ == 0) {
50         SHARING_LOGE("Invalid pcm parameters!");
51         return 1;
52     }
53 
54     sampleSize_ = sampleBit * channels / AUDIO_SAMPLE_BIT_U8;
55     if (!(fifo_ = av_audio_fifo_alloc(AV_SAMPLE_FMT_S16, channels, FIFO_SAMPLES))) {
56         SHARING_LOGE("Could not allocate FIFO");
57         return 1;
58     }
59     return 0;
60 }
61 
OnFrame(const Frame::Ptr &frame)62 void AudioPcmProcessor::OnFrame(const Frame::Ptr &frame)
63 {
64     if (frame == nullptr) {
65         SHARING_LOGE("frame is nullptr!");
66         return;
67     }
68 
69     if (channels_ == 0 || sampleBit_ == 0 || sampleRate_ == 0) {
70         SHARING_LOGE("Invalid pcm parameters!");
71         return;
72     }
73 
74     if (duration == 0) {
75         std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
76         duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
77     }
78 
79     PcmLittleToBigEndian(frame->Data(), frame->Size());
80     uint8_t *captureData[] = {frame->Data()};
81     uint8_t *payloadData[] = {data};
82     int32_t payloadSampleNum = LPCM_PES_PAYLOAD_DATA_SIZE / sampleSize_;
83     av_audio_fifo_write(fifo_, reinterpret_cast<void **>(captureData), frame->Size() / sampleSize_);
84     while (av_audio_fifo_size(fifo_) >= payloadSampleNum) {
85         av_audio_fifo_read(fifo_, reinterpret_cast<void **>(payloadData), payloadSampleNum);
86         auto pcmFrame = FrameImpl::Create();
87         pcmFrame->pts_ = duration;
88         pcmFrame->codecId_ = CODEC_PCM;
89         pcmFrame->SetCapacity(LPCM_PES_PAYLOAD_PRIVATE_SIZE + LPCM_PES_PAYLOAD_DATA_SIZE);
90         pcmFrame->Append(0xa0);          // 0xa0 - sub_stream_id
91         pcmFrame->Append(0x06);          // 0x06 - number_of_frame_header
92         pcmFrame->Append(0x00);          // audio_emphasis_flag
93         pcmFrame->Append(AUDIO_SAMPLING_FREQUENCY_48K | NUMBER_OF_AUDIO_CHANNEL_STEREO);
94         pcmFrame->Append(payloadData[0], LPCM_PES_PAYLOAD_DATA_SIZE);
95         DeliverFrame(pcmFrame);
96         duration += LPCM_PES_PAYLOAD_TIME_DURATION;
97     }
98 }
99 
PcmLittleToBigEndian(uint8_t *data, int32_t size)100 void AudioPcmProcessor::PcmLittleToBigEndian(uint8_t *data, int32_t size)
101 {
102     uint32_t sampleSize = sampleSize_ / channels_;
103     if (sampleSize <= 1) {
104         return;
105     }
106 
107     uint8_t tmpData;
108     int32_t count = size / sampleSize;
109     for (int32_t i = 0; i < count; i++) {
110         tmpData = data[i * sampleSize];
111         data[i * sampleSize] = data[i * sampleSize + 1];
112         data[i * sampleSize + 1] = tmpData;
113     }
114 }
115 } // namespace Sharing
116 } // namespace OHOS
117