• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "AmrnbDecoderTest"
19 #define OUTPUT_FILE "/data/local/tmp/amrnbDecode.out"
20 
21 #include <utils/Log.h>
22 
23 #include <audio_utils/sndfile.h>
24 #include <stdio.h>
25 #include <fstream>
26 
27 #include "gsmamr_dec.h"
28 
29 #include "AmrnbDecTestEnvironment.h"
30 
31 // Constants for AMR-NB
32 constexpr int32_t kInputBufferSize = 64;
33 constexpr int32_t kSamplesPerFrame = L_FRAME;
34 constexpr int32_t kBitsPerSample = 16;
35 constexpr int32_t kSampleRate = 8000;
36 constexpr int32_t kChannels = 1;
37 constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
38 const int32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31, -1, -1, -1, -1, -1, -1, -1, -1};
39 
40 constexpr int32_t kNumFrameReset = 150;
41 
42 static AmrnbDecTestEnvironment *gEnv = nullptr;
43 
44 class AmrnbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
45   public:
AmrnbDecoderTest()46     AmrnbDecoderTest() : mFpInput(nullptr) {}
47 
~AmrnbDecoderTest()48     ~AmrnbDecoderTest() {
49         if (mFpInput) {
50             fclose(mFpInput);
51             mFpInput = nullptr;
52         }
53     }
54 
55     FILE *mFpInput;
56     SNDFILE *openOutputFile(SF_INFO *sfInfo);
57     int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
58     bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
59 };
60 
openOutputFile(SF_INFO * sfInfo)61 SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
62     memset(sfInfo, 0, sizeof(SF_INFO));
63     sfInfo->channels = kChannels;
64     sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
65     sfInfo->samplerate = kSampleRate;
66     SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
67     return outFileHandle;
68 }
69 
DecodeFrames(void * amrHandle,SNDFILE * outFileHandle,int32_t frameCount)70 int32_t AmrnbDecoderTest::DecodeFrames(void *amrHandle, SNDFILE *outFileHandle,
71                                        int32_t frameCount) {
72     uint8_t inputBuf[kInputBufferSize];
73     int16_t outputBuf[kOutputBufferSize];
74 
75     while (frameCount > 0) {
76         uint8_t mode;
77         int32_t bytesRead = fread(&mode, 1, 1, mFpInput);
78         if (bytesRead != 1) break;
79 
80         // Find frame type
81         Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f);
82         int32_t frameSize = kFrameSizes[frameType];
83         if (frameSize < 0) {
84             ALOGE("Illegal frame type");
85             return -1;
86         }
87         bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
88         if (bytesRead != frameSize) break;
89 
90         int32_t bytesDecoded = AMRDecode(amrHandle, frameType, inputBuf, outputBuf, MIME_IETF);
91         if (bytesDecoded == -1) {
92             ALOGE("Failed to decode the input file");
93             return -1;
94         }
95 
96         sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame);
97         frameCount--;
98     }
99     return 0;
100 }
101 
compareBinaryFiles(const std::string & refFilePath,const std::string & outFilePath)102 bool AmrnbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
103                                           const std::string &outFilePath) {
104     std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
105     std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
106     assert(refFile.is_open() && "Error opening reference file " + refFilePath);
107     assert(outFile.is_open() && "Error opening output file " + outFilePath);
108 
109     std::streamsize refFileSize = refFile.tellg();
110     std::streamsize outFileSize = outFile.tellg();
111     if (refFileSize != outFileSize) {
112         ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
113               " but output file size = %td bytes.", refFileSize, outFileSize);
114         return false;
115     }
116 
117     refFile.seekg(0, std::ios::beg);
118     outFile.seekg(0, std::ios::beg);
119     constexpr std::streamsize kBufferSize = 16 * 1024;
120     char refBuffer[kBufferSize];
121     char outBuffer[kBufferSize];
122 
123     while (refFile && outFile) {
124         refFile.read(refBuffer, kBufferSize);
125         outFile.read(outBuffer, kBufferSize);
126 
127         std::streamsize refBytesRead = refFile.gcount();
128         std::streamsize outBytesRead = outFile.gcount();
129 
130         if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
131             ALOGE("Error, File content mismatch.");
132             return false;
133         }
134     }
135     return true;
136 }
137 
TEST_F(AmrnbDecoderTest,CreateAmrnbDecoderTest)138 TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
139     void *amrHandle;
140     int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
141     ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
142     GSMDecodeFrameExit(&amrHandle);
143     ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
144 }
145 
TEST_P(AmrnbDecoderTest,DecodeTest)146 TEST_P(AmrnbDecoderTest, DecodeTest) {
147     string inputFile = gEnv->getRes() + std::get<0>(GetParam());
148     mFpInput = fopen(inputFile.c_str(), "rb");
149     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
150 
151     // Open the output file.
152     SF_INFO sfInfo;
153     SNDFILE *outFileHandle = openOutputFile(&sfInfo);
154     ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
155 
156     void *amrHandle;
157     int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
158     ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
159 
160     // Decode
161     int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle);
162     ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
163 
164     sf_close(outFileHandle);
165     GSMDecodeFrameExit(&amrHandle);
166     ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
167 
168     string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
169     ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
170        << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
171        << " does not match the reference file " << refFilePath << ".";
172 }
173 
TEST_P(AmrnbDecoderTest,ResetDecodeTest)174 TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
175     string inputFile = gEnv->getRes() + std::get<0>(GetParam());
176     mFpInput = fopen(inputFile.c_str(), "rb");
177     ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
178 
179     // Open the output file.
180     SF_INFO sfInfo;
181     SNDFILE *outFileHandle = openOutputFile(&sfInfo);
182     ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
183 
184     void *amrHandle;
185     int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
186     ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
187 
188     // Decode kNumFrameReset first
189     int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle, kNumFrameReset);
190     ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
191 
192     status = Speech_Decode_Frame_reset(amrHandle);
193     ASSERT_EQ(status, 0) << "Error resting AMR-NB decoder";
194 
195     // Start decoding again
196     decoderErr = DecodeFrames(amrHandle, outFileHandle);
197     ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
198 
199     sf_close(outFileHandle);
200     GSMDecodeFrameExit(&amrHandle);
201     ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
202 }
203 
204 INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
205                          ::testing::Values(std::make_tuple(
206                                                    "bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb",
207                                                    "bbb_8000hz_1ch_8kbps_amrnb_30sec_ref.pcm"),
208                                            std::make_tuple(
209                                                    "sine_amrnb_1ch_12kbps_8000hz.amrnb",
210                                                    "sine_amrnb_1ch_12kbps_8000hz_ref.pcm"),
211                                            std::make_tuple(
212                                                    "trim_8000hz_1ch_12kpbs_amrnb_200ms.amrnb",
213                                                    "trim_8000hz_1ch_12kpbs_amrnb_200ms_ref.pcm"),
214                                            std::make_tuple(
215                                                    "bbb_8kHz_1ch_4.75kbps_amrnb_3sec.amrnb",
216                                                    "bbb_8kHz_1ch_4.75kbps_amrnb_3sec_ref.pcm"),
217                                            std::make_tuple(
218                                                    "bbb_8kHz_1ch_10kbps_amrnb_1sec.amrnb",
219                                                    "bbb_8kHz_1ch_10kbps_amrnb_1sec_ref.pcm"),
220                                            std::make_tuple(
221                                                    "bbb_8kHz_1ch_12.2kbps_amrnb_3sec.amrnb",
222                                                    "bbb_8kHz_1ch_12.2kbps_amrnb_3sec_ref.pcm")));
223 
main(int argc,char ** argv)224 int main(int argc, char **argv) {
225     gEnv = new AmrnbDecTestEnvironment();
226     ::testing::AddGlobalTestEnvironment(gEnv);
227     ::testing::InitGoogleTest(&argc, argv);
228     int status = gEnv->initFromOptions(argc, argv);
229     if (status == 0) {
230         status = RUN_ALL_TESTS();
231         ALOGV("Test result = %d\n", status);
232     }
233     return status;
234 }
235