1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "AmrnbEncoderTest"
19
20 #include <utils/Log.h>
21
22 #include <audio_utils/sndfile.h>
23 #include <stdio.h>
24
25 #include "gsmamr_enc.h"
26
27 #include "AmrnbEncTestEnvironment.h"
28
29 #define OUTPUT_FILE "/data/local/tmp/amrnbEncode.out"
30
31 constexpr int32_t kInputBufferSize = L_FRAME * 2; // 160 samples * 16-bit per sample.
32 constexpr int32_t kOutputBufferSize = 1024;
33 constexpr int32_t kNumFrameReset = 200;
34 constexpr int32_t kMaxCount = 10;
35 struct AmrNbEncState {
36 void *encCtx;
37 void *pidSyncCtx;
38 };
39
40 static AmrnbEncTestEnvironment *gEnv = nullptr;
41
42 class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
43 public:
AmrnbEncoderTest()44 AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
45
~AmrnbEncoderTest()46 ~AmrnbEncoderTest() {
47 if (mAmrEncHandle) {
48 free(mAmrEncHandle);
49 mAmrEncHandle = nullptr;
50 }
51 }
52
53 AmrNbEncState *mAmrEncHandle;
54 int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
55 int32_t frameCount = INT32_MAX);
56 };
57
EncodeFrames(int32_t mode,FILE * fpInput,FILE * mFpOutput,int32_t frameCount)58 int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
59 int32_t frameCount) {
60 int32_t frameNum = 0;
61 uint16_t inputBuf[kInputBufferSize];
62 uint8_t outputBuf[kOutputBufferSize];
63 while (frameNum < frameCount) {
64 int32_t bytesRead = fread(inputBuf, 1, kInputBufferSize, fpInput);
65 if (bytesRead != kInputBufferSize && !feof(fpInput)) {
66 ALOGE("Unable to read data from input file");
67 return -1;
68 } else if (feof(fpInput) && bytesRead == 0) {
69 break;
70 }
71 Frame_Type_3GPP frame_type = (Frame_Type_3GPP)mode;
72 int32_t bytesGenerated =
73 AMREncode(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx, (Mode)mode,
74 (Word16 *)inputBuf, outputBuf, &frame_type, AMR_TX_WMF);
75 frameNum++;
76 if (bytesGenerated < 0) {
77 ALOGE("Error in encoging the file: Invalid output format");
78 return -1;
79 }
80
81 // Convert from WMF to RFC 3267 format.
82 if (bytesGenerated > 0) {
83 outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c;
84 }
85 fwrite(outputBuf, 1, bytesGenerated, mFpOutput);
86 }
87 return 0;
88 }
89
TEST_F(AmrnbEncoderTest,CreateAmrnbEncoderTest)90 TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
91 mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
92 ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
93 for (int count = 0; count < kMaxCount; count++) {
94 int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
95 ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
96 ALOGV("Successfully created encoder");
97 }
98 if (mAmrEncHandle) {
99 AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
100 ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
101 ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
102 free(mAmrEncHandle);
103 mAmrEncHandle = nullptr;
104 ALOGV("Successfully deleted encoder");
105 }
106 }
107
TEST_P(AmrnbEncoderTest,EncodeTest)108 TEST_P(AmrnbEncoderTest, EncodeTest) {
109 mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
110 ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
111 int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
112 ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
113
114 string inputFile = gEnv->getRes() + GetParam().first;
115 FILE *fpInput = fopen(inputFile.c_str(), "rb");
116 ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
117
118 FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
119 ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
120
121 // Write file header.
122 fwrite("#!AMR\n", 1, 6, fpOutput);
123
124 int32_t mode = GetParam().second;
125 int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
126 ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
127
128 fclose(fpOutput);
129 fclose(fpInput);
130
131 AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
132 ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
133 ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
134 free(mAmrEncHandle);
135 mAmrEncHandle = nullptr;
136 ALOGV("Successfully deleted encoder");
137 }
138
TEST_P(AmrnbEncoderTest,ResetEncoderTest)139 TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
140 mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
141 ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
142 int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
143 ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
144
145 string inputFile = gEnv->getRes() + GetParam().first;
146 FILE *fpInput = fopen(inputFile.c_str(), "rb");
147 ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
148
149 FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
150 ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
151
152 // Write file header.
153 fwrite("#!AMR\n", 1, 6, fpOutput);
154
155 int32_t mode = GetParam().second;
156 // Encode kNumFrameReset first
157 int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
158 ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
159
160 status = AMREncodeReset(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx);
161 ASSERT_EQ(status, 0) << "Error resting AMR-NB encoder";
162
163 // Start encoding again
164 encodeErr = EncodeFrames(mode, fpInput, fpOutput);
165 ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
166
167 fclose(fpOutput);
168 fclose(fpInput);
169
170 AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
171 ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
172 ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
173 free(mAmrEncHandle);
174 mAmrEncHandle = nullptr;
175 ALOGV("Successfully deleted encoder");
176 }
177
178 // TODO: Add more test vectors
179 INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
180 ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
181 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
182 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
183 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
184 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
185 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
186 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
187 make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
188 make_pair("sinesweepraw.raw", MR475),
189 make_pair("sinesweepraw.raw", MR515),
190 make_pair("sinesweepraw.raw", MR59),
191 make_pair("sinesweepraw.raw", MR67),
192 make_pair("sinesweepraw.raw", MR74),
193 make_pair("sinesweepraw.raw", MR795),
194 make_pair("sinesweepraw.raw", MR102),
195 make_pair("sinesweepraw.raw", MR122)));
196
main(int argc,char ** argv)197 int main(int argc, char **argv) {
198 gEnv = new AmrnbEncTestEnvironment();
199 ::testing::AddGlobalTestEnvironment(gEnv);
200 ::testing::InitGoogleTest(&argc, argv);
201 int status = gEnv->initFromOptions(argc, argv);
202 if (status == 0) {
203 status = RUN_ALL_TESTS();
204 ALOGV("Test result = %d\n", status);
205 }
206 return status;
207 }
208