• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include <cstdio>
16 #include <iostream>
17 
18 #include "audio_service_client.h"
19 #include "audio_log.h"
20 #include "audio_system_manager.h"
21 #include "pcm2wav.h"
22 
23 
24 using namespace OHOS::AudioStandard;
25 using namespace std;
26 
27 namespace {
28     constexpr uint8_t DEFAULT_FORMAT = SAMPLE_S16LE;
29     constexpr uint8_t CHANNEL_INDEX = 2;
30     constexpr uint8_t SLEEP_TIME = 2;
31     constexpr uint8_t MAX_FRAME_COUNT = 10;
32 
33     constexpr int32_t SAMPLE_FORMAT_U8 = 8;
34     constexpr int32_t SAMPLE_FORMAT_S16LE = 16;
35     constexpr int32_t SAMPLE_FORMAT_S24LE = 24;
36     constexpr int32_t SAMPLE_FORMAT_S32LE = 32;
37 } // namespace
38 
InitClient(std::unique_ptr<AudioServiceClient> & client,uint32_t samplingRate,uint32_t channelCount)39 static bool InitClient(std::unique_ptr<AudioServiceClient> &client, uint32_t samplingRate, uint32_t channelCount)
40 {
41     AudioStreamParams audioParams;
42     audioParams.format = DEFAULT_FORMAT;
43     audioParams.samplingRate = samplingRate;
44     audioParams.channels = channelCount;
45 
46     if (client->Initialize(AUDIO_SERVICE_CLIENT_RECORD) < 0)
47         return false;
48 
49     if (client->CreateStream(audioParams, STREAM_MUSIC) < 0) {
50         client->ReleaseStream();
51         return false;
52     }
53 
54     if (client->StartStream() < 0)
55         return false;
56 
57     return true;
58 }
59 
StartRecording(char * recPath,int samplingRate,size_t frames,uint32_t channelCount)60 int32_t StartRecording(char *recPath, int samplingRate, size_t frames, uint32_t channelCount)
61 {
62     AUDIO_INFO_LOG("Recording::Path [%{public}s], rate [%{public}d], frames [%{public}zu], channel [%{public}d]",
63         recPath, samplingRate, frames, channelCount);
64 
65     if (frames > MAX_FRAME_COUNT || frames <= 0) {
66         std::cout << "ERROR!!<buffer count> supported value is from 1-10" << std::endl;
67         return AUDIO_ERR;
68     }
69 
70     std::unique_ptr client = std::make_unique<AudioServiceClient>();
71     if (!InitClient(client, samplingRate, channelCount)) {
72         AUDIO_ERR_LOG("Initialize client failed");
73         return AUDIO_ERR;
74     }
75 
76     size_t bufferLen;
77     if (client->GetMinimumBufferSize(bufferLen) < 0) {
78         return AUDIO_ERR;
79     }
80 
81     uint8_t* buffer = nullptr;
82     buffer = (uint8_t *) malloc(bufferLen);
83     if (buffer == nullptr) {
84         AUDIO_ERR_LOG("Failed to allocate buffer");
85         return AUDIO_ERR;
86     }
87 
88     char realPath[PATH_MAX + 1] = {0x00};
89     std::string sourceFilePath(recPath);
90     std::string rootPath;
91     std::string fileName;
92 
93     auto pos = sourceFilePath.rfind("/");
94     if (pos!= std::string::npos) {
95         rootPath = sourceFilePath.substr(0, pos);
96         fileName = sourceFilePath.substr(pos);
97     }
98 
99     if ((strlen(sourceFilePath.c_str()) >= PATH_MAX) || (realpath(rootPath.c_str(), realPath) == nullptr)) {
100         free(buffer);
101         AUDIO_ERR_LOG("StartRecording:: Invalid path errno = %{public}d", errno);
102         return AUDIO_ERR;
103     }
104 
105     std::string verifiedPath(realPath);
106     FILE *pFile = fopen(verifiedPath.append(fileName).c_str(), "wb");
107     if (pFile == nullptr) {
108         free(buffer);
109         AUDIO_ERR_LOG("StartRecording:: Failed to open file errno = %{public}d", errno);
110         return AUDIO_ERR;
111     }
112 
113     size_t size = 1;
114     size_t numBuffersToCapture = frames * 1024;
115     StreamBuffer stream;
116     stream.buffer = buffer;
117     stream.bufferLen = bufferLen;
118     int32_t bytesRead = 0;
119 
120     while (numBuffersToCapture) {
121         bytesRead = client->ReadStream(stream, false);
122         if (bytesRead < 0) {
123             break;
124         }
125 
126         if (bytesRead > 0) {
127             fwrite(stream.buffer, size, bytesRead, pFile);
128             numBuffersToCapture--;
129         }
130     }
131 
132     (void)fflush(pFile);
133     client->FlushStream();
134     client->StopStream();
135     client->ReleaseStream();
136     free(buffer);
137     (void)fclose(pFile);
138     sleep(SLEEP_TIME);
139     AUDIO_INFO_LOG("================RECORDING OVER==================");
140     return 0;
141 }
142 
InitPlayback(std::unique_ptr<AudioServiceClient> & client,AudioStreamParams & audioParams)143 static int32_t InitPlayback(std::unique_ptr<AudioServiceClient> &client, AudioStreamParams &audioParams)
144 {
145     if (client == nullptr) {
146         AUDIO_ERR_LOG("Create AudioServiceClient instance failed");
147         return AUDIO_ERR;
148     }
149 
150     AUDIO_INFO_LOG("Initializing of AudioServiceClient");
151     if (client->Initialize(AUDIO_SERVICE_CLIENT_PLAYBACK) < 0) {
152         AUDIO_ERR_LOG("Initializing of AudioServiceClien failed");
153         return AUDIO_ERR;
154     }
155 
156     AUDIO_INFO_LOG("Creating Stream");
157     if (client->CreateStream(audioParams, STREAM_MUSIC) < 0) {
158         AUDIO_ERR_LOG("Creating Stream failed");
159         return AUDIO_ERR;
160     }
161 
162     AUDIO_INFO_LOG("Starting Stream");
163     if (client->StartStream() < 0) {
164         AUDIO_ERR_LOG("Starting Stream failed");
165         return AUDIO_ERR;
166     }
167 
168     return 0;
169 }
170 
StartPlayback(std::unique_ptr<AudioServiceClient> & client,FILE * wavFile)171 int32_t StartPlayback(std::unique_ptr<AudioServiceClient> &client, FILE *wavFile)
172 {
173     uint8_t* buffer = nullptr;
174     size_t n = 2;
175     size_t bytesToWrite = 0;
176     size_t bytesWritten = 0;
177     size_t minBytes = 4;
178     int32_t writeError;
179     uint64_t timeStamp = 0;
180     size_t bufferLen = 0;
181     StreamBuffer stream;
182 
183     if (client->GetMinimumBufferSize(bufferLen) < 0) {
184         AUDIO_ERR_LOG(" GetMinimumBufferSize failed");
185         return AUDIO_ERR;
186     }
187 
188     buffer = (uint8_t *) malloc(n * bufferLen);
189     if (buffer == nullptr) {
190         AUDIO_ERR_LOG("Failed to allocate buffer");
191         return AUDIO_ERR;
192     }
193 
194     while (!feof(wavFile)) {
195         bytesToWrite = fread(buffer, 1, bufferLen, wavFile);
196         bytesWritten = 0;
197 
198         while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
199             stream.buffer = buffer + bytesWritten;
200             stream.bufferLen = bytesToWrite - bytesWritten;
201             bytesWritten += client->WriteStream(stream, writeError);
202             if (client->GetCurrentTimeStamp(timeStamp) >= 0) {
203                 AUDIO_DEBUG_LOG("current timestamp: %{public}" PRIu64, timeStamp);
204             }
205         }
206     }
207 
208     AUDIO_DEBUG_LOG("File writing over");
209 
210     free(buffer);
211 
212     return 0;
213 }
214 
GetSampleFormat(int32_t wavSampleFormat)215 AudioSampleFormat GetSampleFormat(int32_t wavSampleFormat)
216 {
217     switch (wavSampleFormat) {
218         case SAMPLE_FORMAT_U8:
219             return AudioSampleFormat::SAMPLE_U8;
220         case SAMPLE_FORMAT_S16LE:
221             return AudioSampleFormat::SAMPLE_S16LE;
222         case SAMPLE_FORMAT_S24LE:
223             return AudioSampleFormat::SAMPLE_S24LE;
224         case SAMPLE_FORMAT_S32LE:
225             return AudioSampleFormat::SAMPLE_S32LE;
226         default:
227             return AudioSampleFormat::INVALID_WIDTH;
228     }
229 }
230 
StartRendererPlayback(char * inputPath)231 int32_t StartRendererPlayback(char *inputPath)
232 {
233     AUDIO_INFO_LOG("================PLAYBACK STARTED==================");
234     wav_hdr wavHeader;
235     size_t headerSize = sizeof(wav_hdr);
236     char path[PATH_MAX + 1] = { 0x00 };
237     if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
238         AUDIO_ERR_LOG("Invalid path");
239         return AUDIO_ERR;
240     }
241     AUDIO_INFO_LOG("path = %{public}s", path);
242     FILE* wavFile = fopen(path, "rb");
243     if (wavFile == nullptr) {
244         AUDIO_ERR_LOG("Unable to open wave file");
245         return AUDIO_ERR;
246     }
247 
248     float volume = 1.0f;
249     (void)fread(&wavHeader, 1, headerSize, wavFile);
250     AudioStreamParams audioParams;
251     audioParams.format = GetSampleFormat(wavHeader.bitsPerSample);
252     audioParams.samplingRate = wavHeader.SamplesPerSec;
253     audioParams.channels = wavHeader.NumOfChan;
254 
255     std::unique_ptr client = std::make_unique<AudioServiceClient>();
256     if (InitPlayback(client, audioParams) < 0) {
257         AUDIO_INFO_LOG("Initialize playback failed");
258         (void)fclose(wavFile);
259         return AUDIO_ERR;
260     }
261 
262     AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance();
263     audioSystemMgr->SetVolume(AudioVolumeType::STREAM_MUSIC, volume);
264 
265     if (StartPlayback(client, wavFile) < 0) {
266         AUDIO_INFO_LOG("Start playback failed");
267         (void)fclose(wavFile);
268         return AUDIO_ERR;
269     }
270 
271     client->FlushStream();
272     client->StopStream();
273     client->ReleaseStream();
274     (void)fclose(wavFile);
275     sleep(SLEEP_TIME);
276     AUDIO_INFO_LOG("================PLAYBACK OVER==================");
277     return 0;
278 }
279 
ActivateFileIoDevice(bool isActive)280 int32_t ActivateFileIoDevice(bool isActive)
281 {
282     AUDIO_INFO_LOG("==ActivateFileIoDevice== flag[%{public}d]", isActive);
283     AudioSystemManager::GetInstance()->SetDeviceActive(ActiveDeviceType::FILE_SINK_DEVICE, isActive);
284     return 0;
285 }
286 
ReconfigureChannel(uint32_t count,DeviceType type)287 int32_t ReconfigureChannel(uint32_t count, DeviceType type)
288 {
289     AUDIO_INFO_LOG("==ReconfigureChannel== count [%{public}d] type [%{public}d]", count, type);
290     AudioSystemManager::GetInstance()->ReconfigureAudioChannel(count, type);
291     return 0;
292 }
293 
PrintUsage()294 void PrintUsage()
295 {
296     cout << "[Audio Multichannel Test App]" << endl << endl;
297     cout << "Supported Functionalities:" << endl;
298     cout << "  a) Activates/Deactivates file sink and source module" << endl;
299     cout << "  b) Plays an input audio file"<< endl;
300     cout << "  c) Records audio stream and writes to a file"<< endl;
301     cout << "  d) Dynamically modify the sink and source module channel configuration"<< endl << endl;
302     cout << "================================Usage=======================================" << endl << endl;
303     cout << "-a\n\tActivates/Deactivates file sink and source module" << endl;
304     cout << "\tUsage : ./audio_multichannel_test -a <boolean>" << endl;
305     cout << "\tExample 1 : ./audio_multichannel_test -a true" << endl;
306     cout << "\tExample 2 : ./audio_multichannel_test -a false" << endl << endl;
307     cout << "-p\n\tPlays an input audio file" << endl;
308     cout << "\tUsage : ./audio_multichannel_test -p <audio file path>" << endl;
309     cout << "\tExample : ./audio_multichannel_test -p /data/test.wav" << endl << endl;
310     cout << "-r\n\tRecords audio stream and writes to a file" << endl;
311     cout << "\tUsage : ./audio_multichannel_test -r <file path> <sampling rate> <buffer count> <channel>" << endl;
312     cout << "\tNOTE :Total num of buffer to record = <buffer count> * 1024. <buffer count> Max value is 10" << endl;
313     cout << "\tExample 1 : ./audio_multichannel_test -r /data/record.pcm 48000 1 6" << endl;
314     cout << "\tExample 2 : ./audio_multichannel_test -r /data/record.pcm 44100 2 4" << endl << endl;
315     cout << "-c\n\tDynamically modify the sink and source module channel configuration" << endl;
316     cout << "\tUsage : ./audio_multichannel_test -c <channel count> <DeviceType>" << endl;
317     cout << "\tExample 1 : ./audio_multichannel_test -c 4 50" << endl;
318     cout << "\tExample 2: ./audio_multichannel_test -c 2 51" << endl;
319     cout << "\tNOTE :DeviceType 50=file_sink | 51=file_source" << endl;
320 }
321 
main(int argc,char * argv[])322 int main(int argc, char* argv[])
323 {
324     int c;
325     bool flag;
326     opterr = 0;
327     while ((c = getopt(argc, argv, "a:c:p:r:h")) != AUDIO_INVALID_PARAM) {
328         switch (c) {
329             case 'a':
330                 flag = (strcmp(optarg, "true") == 0 ? true : false);
331                 ActivateFileIoDevice(flag);
332                 break;
333             case 'p':
334                 StartRendererPlayback(optarg);
335                 break;
336             case 'r':
337                 StartRecording(optarg, atoi(argv[optind]), atoi(argv[optind+1]), atoi(argv[optind+CHANNEL_INDEX]));
338                 break;
339             case 'c':
340                 ReconfigureChannel(atoi(optarg), static_cast<DeviceType>(atoi(argv[optind])));
341                 break;
342             case 'h':
343                 PrintUsage();
344                 break;
345             default:
346                 cout << "Unsupported option. Exiting!!!" << endl;
347                 exit(0);
348                 break;
349         }
350     }
351 
352     return 0;
353 }
354