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