1/*
2 * Copyright (c) 2023 Huawei Device 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 <benchmark/benchmark.h>
17#include <climits>
18#include <gtest/gtest.h>
19#include "hdf_base.h"
20#include "osal_mem.h"
21#include "v4_0/audio_types.h"
22#include "v4_0/iaudio_manager.h"
23#include "v4_0/iaudio_render.h"
24
25using namespace std;
26using namespace testing::ext;
27
28namespace {
29const int BUFFER_LENTH = 1024 * 16;
30const int DEEP_BUFFER_RENDER_PERIOD_SIZE = 4 * 1024;
31const int MOVE_LEFT_NUM = 8;
32const int32_t AUDIO_RENDER_CHANNELCOUNT = 2;
33const int32_t AUDIO_SAMPLE_RATE_48K = 48000;
34const int32_t MAX_AUDIO_ADAPTER_DESC = 5;
35const int32_t MMAP_SUGGEST_BUFFER_SIZE = 1920;
36const int32_t ITERATION_FREQUENCY = 100;
37const int32_t REPETITION_FREQUENCY = 3;
38
39class AudioRenderMmapBenchmarkTest : public benchmark::Fixture {
40public:
41    struct IAudioManager *manager_ = nullptr;
42    struct AudioAdapterDescriptor descs_[MAX_AUDIO_ADAPTER_DESC];
43    struct AudioAdapterDescriptor *desc_;
44    struct IAudioAdapter *adapter_ = nullptr;
45    struct IAudioRender *render_ = nullptr;
46    struct AudioDeviceDescriptor devDescRender_ = {};
47    struct AudioSampleAttributes attrsRender_ = {};
48    uint32_t renderId_ = 0;
49    char *devDescriptorName_ = nullptr;
50    uint32_t size_ = MAX_AUDIO_ADAPTER_DESC;
51    virtual void SetUp(const ::benchmark::State &state);
52    virtual void TearDown(const ::benchmark::State &state);
53    void InitRenderAttrs(struct AudioSampleAttributes &attrs);
54    void InitRenderDevDesc(struct AudioDeviceDescriptor &devDesc);
55    void FreeAdapterElements(struct AudioAdapterDescriptor *dataBlock, bool freeSelf);
56    void ReleaseAllAdapterDescs(struct AudioAdapterDescriptor *descs, uint32_t descsLen);
57};
58
59void AudioRenderMmapBenchmarkTest::InitRenderAttrs(struct AudioSampleAttributes &attrs)
60{
61    attrs.channelCount = AUDIO_RENDER_CHANNELCOUNT;
62    attrs.sampleRate = AUDIO_SAMPLE_RATE_48K;
63    attrs.interleaved = 0;
64    attrs.type = AUDIO_MMAP_NOIRQ;
65    attrs.period = DEEP_BUFFER_RENDER_PERIOD_SIZE;
66    attrs.frameSize = AUDIO_FORMAT_TYPE_PCM_16_BIT * AUDIO_RENDER_CHANNELCOUNT / MOVE_LEFT_NUM;
67    attrs.isBigEndian = false;
68    attrs.isSignedData = true;
69    attrs.startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (attrs.format * attrs.channelCount / MOVE_LEFT_NUM);
70    attrs.stopThreshold = INT_MAX;
71    attrs.silenceThreshold = BUFFER_LENTH;
72}
73
74void AudioRenderMmapBenchmarkTest::InitRenderDevDesc(struct AudioDeviceDescriptor &devDesc)
75{
76    devDesc.pins = PIN_OUT_SPEAKER;
77    devDescriptorName_ = strdup("cardname");
78    devDesc.desc = devDescriptorName_;
79
80    ASSERT_NE(desc_, nullptr);
81    ASSERT_NE(desc_->ports, nullptr);
82    for (uint32_t index = 0; index < desc_->portsLen; index++) {
83        if (desc_->ports[index].dir == PORT_OUT) {
84            devDesc.portId = desc_->ports[index].portId;
85            return;
86        }
87    }
88    free(devDesc.desc);
89    devDesc.desc = nullptr;
90}
91
92void AudioRenderMmapBenchmarkTest::FreeAdapterElements(struct AudioAdapterDescriptor *dataBlock, bool freeSelf)
93{
94    if (dataBlock == nullptr) {
95        return;
96    }
97
98    OsalMemFree(dataBlock->adapterName);
99
100    OsalMemFree(dataBlock->ports);
101
102    if (freeSelf) {
103        OsalMemFree(dataBlock);
104    }
105}
106
107void AudioRenderMmapBenchmarkTest::ReleaseAllAdapterDescs(struct AudioAdapterDescriptor *descs, uint32_t descsLen)
108{
109    if (descs == nullptr || descsLen == 0) {
110        return;
111    }
112
113    for (uint32_t i = 0; i < descsLen; i++) {
114        FreeAdapterElements(&descs[i], false);
115    }
116}
117
118void AudioRenderMmapBenchmarkTest::SetUp(const ::benchmark::State &state)
119{
120    manager_ = IAudioManagerGet(false);
121    ASSERT_NE(manager_, nullptr);
122
123    ASSERT_EQ(HDF_SUCCESS, manager_->GetAllAdapters(manager_, descs_, &size_));
124    ASSERT_NE(descs_, nullptr);
125    EXPECT_GE(MAX_AUDIO_ADAPTER_DESC, size_);
126    desc_ = &descs_[0];
127    ASSERT_EQ(HDF_SUCCESS, manager_->LoadAdapter(manager_, desc_, &adapter_));
128    ASSERT_NE(adapter_, nullptr);
129    InitRenderDevDesc(devDescRender_);
130    InitRenderAttrs(attrsRender_);
131
132    attrsRender_.format = AUDIO_FORMAT_TYPE_PCM_16_BIT;
133    int32_t ret = adapter_->CreateRender(adapter_, &devDescRender_, &attrsRender_, &render_, &renderId_);
134    if (ret != HDF_SUCCESS) {
135        attrsRender_.format = AUDIO_FORMAT_TYPE_PCM_32_BIT;
136        ASSERT_EQ(HDF_SUCCESS, adapter_->CreateRender(adapter_, &devDescRender_, &attrsRender_, &render_, &renderId_));
137    }
138    ASSERT_NE(render_, nullptr);
139}
140
141void AudioRenderMmapBenchmarkTest::TearDown(const ::benchmark::State &state)
142{
143    ASSERT_NE(devDescriptorName_, nullptr);
144    free(devDescriptorName_);
145
146    if (adapter_ != nullptr) {
147        adapter_->DestroyRender(adapter_, renderId_);
148        render_ = nullptr;
149    }
150    if (manager_ != nullptr) {
151        manager_->UnloadAdapter(manager_, desc_->adapterName);
152        adapter_ = nullptr;
153        ReleaseAllAdapterDescs(descs_, size_);
154
155        IAudioManagerRelease(manager_, false);
156    }
157}
158
159BENCHMARK_F(AudioRenderMmapBenchmarkTest, ReqMmapBuffer)(benchmark::State &state)
160{
161    ASSERT_NE(render_, nullptr);
162    int32_t ret;
163    uint64_t frames = 0;
164    struct AudioTimeStamp time;
165    time.tvNSec = 0;
166    time.tvSec = 0;
167    int32_t reqSize = MMAP_SUGGEST_BUFFER_SIZE;
168    struct AudioMmapBufferDescriptor desc;
169
170    for (auto _ : state) {
171        ret = render_->ReqMmapBuffer(render_, reqSize, &desc);
172        ASSERT_TRUE(ret == HDF_SUCCESS || ret == HDF_ERR_INVALID_PARAM);
173
174        ret = render_->Start(render_);
175        ASSERT_TRUE(ret == HDF_SUCCESS || ret == HDF_FAILURE);
176
177        ret = render_->GetMmapPosition(render_, &frames, &time);
178        ASSERT_TRUE(ret == HDF_SUCCESS);
179
180        ret = render_->Stop(render_);
181        ASSERT_TRUE(ret == HDF_SUCCESS || ret == HDF_FAILURE);
182    }
183}
184
185BENCHMARK_REGISTER_F(AudioRenderMmapBenchmarkTest, ReqMmapBuffer)->
186    Iterations(ITERATION_FREQUENCY)->Repetitions(REPETITION_FREQUENCY)->ReportAggregatesOnly();
187}
188