xref: /aosp_15_r20/external/oboe/src/common/Utilities.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2016 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 
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sstream>
21 
22 #ifdef __ANDROID__
23 #include <sys/system_properties.h>
24 #endif
25 
26 #include <oboe/AudioStream.h>
27 #include "oboe/Definitions.h"
28 #include "oboe/Utilities.h"
29 
30 namespace oboe {
31 
32 constexpr float kScaleI16ToFloat = (1.0f / 32768.0f);
33 
convertFloatToPcm16(const float * source,int16_t * destination,int32_t numSamples)34 void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples) {
35     for (int i = 0; i < numSamples; i++) {
36         float fval = source[i];
37         fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
38         fval *= 32768.0f;
39         auto sample = static_cast<int32_t>(fval);
40         // clip to 16-bit range
41         if (sample < 0) sample = 0;
42         else if (sample > 0x0FFFF) sample = 0x0FFFF;
43         sample -= 32768; // center at zero
44         destination[i] = static_cast<int16_t>(sample);
45     }
46 }
47 
convertPcm16ToFloat(const int16_t * source,float * destination,int32_t numSamples)48 void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples) {
49     for (int i = 0; i < numSamples; i++) {
50         destination[i] = source[i] * kScaleI16ToFloat;
51     }
52 }
53 
convertFormatToSizeInBytes(AudioFormat format)54 int32_t convertFormatToSizeInBytes(AudioFormat format) {
55     int32_t size = 0;
56     switch (format) {
57         case AudioFormat::I16:
58             size = sizeof(int16_t);
59             break;
60         case AudioFormat::Float:
61             size = sizeof(float);
62             break;
63         case AudioFormat::I24:
64             size = 3; // packed 24-bit data
65             break;
66         case AudioFormat::I32:
67             size = sizeof(int32_t);
68             break;
69         case AudioFormat::IEC61937:
70             size = sizeof(int16_t);
71             break;
72         default:
73             break;
74     }
75     return size;
76 }
77 
78 template<>
convertToText(Result returnCode)79 const char *convertToText<Result>(Result returnCode) {
80     switch (returnCode) {
81         case Result::OK:                    return "OK";
82         case Result::ErrorDisconnected:     return "ErrorDisconnected";
83         case Result::ErrorIllegalArgument:  return "ErrorIllegalArgument";
84         case Result::ErrorInternal:         return "ErrorInternal";
85         case Result::ErrorInvalidState:     return "ErrorInvalidState";
86         case Result::ErrorInvalidHandle:    return "ErrorInvalidHandle";
87         case Result::ErrorUnimplemented:    return "ErrorUnimplemented";
88         case Result::ErrorUnavailable:      return "ErrorUnavailable";
89         case Result::ErrorNoFreeHandles:    return "ErrorNoFreeHandles";
90         case Result::ErrorNoMemory:         return "ErrorNoMemory";
91         case Result::ErrorNull:             return "ErrorNull";
92         case Result::ErrorTimeout:          return "ErrorTimeout";
93         case Result::ErrorWouldBlock:       return "ErrorWouldBlock";
94         case Result::ErrorInvalidFormat:    return "ErrorInvalidFormat";
95         case Result::ErrorOutOfRange:       return "ErrorOutOfRange";
96         case Result::ErrorNoService:        return "ErrorNoService";
97         case Result::ErrorInvalidRate:      return "ErrorInvalidRate";
98         case Result::ErrorClosed:           return "ErrorClosed";
99         default:                            return "Unrecognized result";
100     }
101 }
102 
103 template<>
convertToText(AudioFormat format)104 const char *convertToText<AudioFormat>(AudioFormat format) {
105     switch (format) {
106         case AudioFormat::Invalid:      return "Invalid";
107         case AudioFormat::Unspecified:  return "Unspecified";
108         case AudioFormat::I16:          return "I16";
109         case AudioFormat::Float:        return "Float";
110         case AudioFormat::I24:          return "I24";
111         case AudioFormat::I32:          return "I32";
112         case AudioFormat::IEC61937:     return "IEC61937";
113         default:                        return "Unrecognized format";
114     }
115 }
116 
117 template<>
convertToText(PerformanceMode mode)118 const char *convertToText<PerformanceMode>(PerformanceMode mode) {
119     switch (mode) {
120         case PerformanceMode::LowLatency:   return "LowLatency";
121         case PerformanceMode::None:         return "None";
122         case PerformanceMode::PowerSaving:  return "PowerSaving";
123         default:                            return "Unrecognized performance mode";
124     }
125 }
126 
127 template<>
convertToText(SharingMode mode)128 const char *convertToText<SharingMode>(SharingMode mode) {
129     switch (mode) {
130         case SharingMode::Exclusive:    return "Exclusive";
131         case SharingMode::Shared:       return "Shared";
132         default:                        return "Unrecognized sharing mode";
133     }
134 }
135 
136 template<>
convertToText(DataCallbackResult result)137 const char *convertToText<DataCallbackResult>(DataCallbackResult result) {
138     switch (result) {
139         case DataCallbackResult::Continue:  return "Continue";
140         case DataCallbackResult::Stop:      return "Stop";
141         default:                            return "Unrecognized data callback result";
142     }
143 }
144 
145 template<>
convertToText(Direction direction)146 const char *convertToText<Direction>(Direction direction) {
147     switch (direction) {
148         case Direction::Input:  return "Input";
149         case Direction::Output: return "Output";
150         default:                return "Unrecognized direction";
151     }
152 }
153 
154 template<>
convertToText(StreamState state)155 const char *convertToText<StreamState>(StreamState state) {
156     switch (state) {
157         case StreamState::Closed:           return "Closed";
158         case StreamState::Closing:          return "Closing";
159         case StreamState::Disconnected:     return "Disconnected";
160         case StreamState::Flushed:          return "Flushed";
161         case StreamState::Flushing:         return "Flushing";
162         case StreamState::Open:             return "Open";
163         case StreamState::Paused:           return "Paused";
164         case StreamState::Pausing:          return "Pausing";
165         case StreamState::Started:          return "Started";
166         case StreamState::Starting:         return "Starting";
167         case StreamState::Stopped:          return "Stopped";
168         case StreamState::Stopping:         return "Stopping";
169         case StreamState::Uninitialized:    return "Uninitialized";
170         case StreamState::Unknown:          return "Unknown";
171         default:                            return "Unrecognized stream state";
172     }
173 }
174 
175 template<>
convertToText(AudioApi audioApi)176 const char *convertToText<AudioApi>(AudioApi audioApi) {
177 
178     switch (audioApi) {
179         case AudioApi::Unspecified: return "Unspecified";
180         case AudioApi::OpenSLES:    return "OpenSLES";
181         case AudioApi::AAudio:      return "AAudio";
182         default:                    return "Unrecognized audio API";
183     }
184 }
185 
186 template<>
convertToText(AudioStream * stream)187 const char *convertToText<AudioStream*>(AudioStream* stream) {
188     static std::string streamText;
189     std::stringstream s;
190 
191     s<<"StreamID: "<< static_cast<void*>(stream)<<std::endl
192      <<"DeviceId: "<<stream->getDeviceId()<<std::endl
193      <<"Direction: "<<oboe::convertToText(stream->getDirection())<<std::endl
194      <<"API type: "<<oboe::convertToText(stream->getAudioApi())<<std::endl
195      <<"BufferCapacity: "<<stream->getBufferCapacityInFrames()<<std::endl
196      <<"BufferSize: "<<stream->getBufferSizeInFrames()<<std::endl
197      <<"FramesPerBurst: "<< stream->getFramesPerBurst()<<std::endl
198      <<"FramesPerDataCallback: "<<stream->getFramesPerDataCallback()<<std::endl
199      <<"SampleRate: "<<stream->getSampleRate()<<std::endl
200      <<"ChannelCount: "<<stream->getChannelCount()<<std::endl
201      <<"Format: "<<oboe::convertToText(stream->getFormat())<<std::endl
202      <<"SharingMode: "<<oboe::convertToText(stream->getSharingMode())<<std::endl
203      <<"PerformanceMode: "<<oboe::convertToText(stream->getPerformanceMode())
204      <<std::endl
205      <<"CurrentState: "<<oboe::convertToText(stream->getState())<<std::endl
206      <<"XRunCount: "<<stream->getXRunCount()<<std::endl
207      <<"FramesRead: "<<stream->getFramesRead()<<std::endl
208      <<"FramesWritten: "<<stream->getFramesWritten()<<std::endl;
209 
210     streamText = s.str();
211     return streamText.c_str();
212 }
213 
214 template<>
convertToText(Usage usage)215 const char *convertToText<Usage>(Usage usage) {
216 
217     switch (usage) {
218         case Usage::Media:                         return "Media";
219         case Usage::VoiceCommunication:            return "VoiceCommunication";
220         case Usage::VoiceCommunicationSignalling:  return "VoiceCommunicationSignalling";
221         case Usage::Alarm:                         return "Alarm";
222         case Usage::Notification:                  return "Notification";
223         case Usage::NotificationRingtone:          return "NotificationRingtone";
224         case Usage::NotificationEvent:             return "NotificationEvent";
225         case Usage::AssistanceAccessibility:       return "AssistanceAccessibility";
226         case Usage::AssistanceNavigationGuidance:  return "AssistanceNavigationGuidance";
227         case Usage::AssistanceSonification:        return "AssistanceSonification";
228         case Usage::Game:                          return "Game";
229         case Usage::Assistant:                     return "Assistant";
230         default:                                   return "Unrecognized usage";
231     }
232 }
233 
234 template<>
convertToText(ContentType contentType)235 const char *convertToText<ContentType>(ContentType contentType) {
236 
237     switch (contentType) {
238         case ContentType::Speech:        return "Speech";
239         case ContentType::Music:         return "Music";
240         case ContentType::Movie:         return "Movie";
241         case ContentType::Sonification:  return "Sonification";
242         default:                         return "Unrecognized content type";
243     }
244 }
245 
246 template<>
convertToText(InputPreset inputPreset)247 const char *convertToText<InputPreset>(InputPreset inputPreset) {
248 
249     switch (inputPreset) {
250         case InputPreset::Generic:             return "Generic";
251         case InputPreset::Camcorder:           return "Camcorder";
252         case InputPreset::VoiceRecognition:    return "VoiceRecognition";
253         case InputPreset::VoiceCommunication:  return "VoiceCommunication";
254         case InputPreset::Unprocessed:         return "Unprocessed";
255         case InputPreset::VoicePerformance:    return "VoicePerformance";
256         default:                               return "Unrecognized input preset";
257     }
258 }
259 
260 template<>
convertToText(SessionId sessionId)261 const char *convertToText<SessionId>(SessionId sessionId) {
262 
263     switch (sessionId) {
264         case SessionId::None:      return "None";
265         case SessionId::Allocate:  return "Allocate";
266         default:                   return "Unrecognized session id";
267     }
268 }
269 
270 template<>
convertToText(ChannelCount channelCount)271 const char *convertToText<ChannelCount>(ChannelCount channelCount) {
272 
273     switch (channelCount) {
274         case ChannelCount::Unspecified:  return "Unspecified";
275         case ChannelCount::Mono:         return "Mono";
276         case ChannelCount::Stereo:       return "Stereo";
277         default:                         return "Unrecognized channel count";
278     }
279 }
280 
281 template<>
convertToText(SampleRateConversionQuality sampleRateConversionQuality)282 const char *convertToText<SampleRateConversionQuality>(SampleRateConversionQuality sampleRateConversionQuality) {
283 
284     switch (sampleRateConversionQuality) {
285         case SampleRateConversionQuality::None:     return "None";
286         case SampleRateConversionQuality::Fastest:  return "Fastest";
287         case SampleRateConversionQuality::Low:      return "Low";
288         case SampleRateConversionQuality::Medium:   return "Medium";
289         case SampleRateConversionQuality::High:     return "High";
290         case SampleRateConversionQuality::Best:     return "Best";
291         default:                                    return "Unrecognized sample rate conversion quality";
292     }
293 }
294 
getPropertyString(const char * name)295 std::string getPropertyString(const char * name) {
296     std::string result;
297 #ifdef __ANDROID__
298     char valueText[PROP_VALUE_MAX] = {0};
299     if (__system_property_get(name, valueText) != 0) {
300         result = valueText;
301     }
302 #else
303     (void) name;
304 #endif
305     return result;
306 }
307 
getPropertyInteger(const char * name,int defaultValue)308 int getPropertyInteger(const char * name, int defaultValue) {
309     int result = defaultValue;
310 #ifdef __ANDROID__
311     char valueText[PROP_VALUE_MAX] = {0};
312     if (__system_property_get(name, valueText) != 0) {
313         result = atoi(valueText);
314     }
315 #else
316     (void) name;
317 #endif
318     return result;
319 }
320 
getSdkVersion()321 int getSdkVersion() {
322     static int sCachedSdkVersion = -1;
323 #ifdef __ANDROID__
324     if (sCachedSdkVersion == -1) {
325         sCachedSdkVersion = getPropertyInteger("ro.build.version.sdk", -1);
326     }
327 #endif
328     return sCachedSdkVersion;
329 }
330 
isAtLeastPreReleaseCodename(const std::string & codename)331 bool isAtLeastPreReleaseCodename(const std::string& codename) {
332     std::string buildCodename = getPropertyString("ro.build.version.codename");
333     // Special case "REL", which means the build is not a pre-release build.
334     if ("REL" == buildCodename) {
335         return false;
336     }
337 
338     // Otherwise lexically compare them. Return true if the build codename is equal to or
339     // greater than the requested codename.
340     return buildCodename.compare(codename) >= 0;
341 }
342 
getChannelCountFromChannelMask(ChannelMask channelMask)343 int getChannelCountFromChannelMask(ChannelMask channelMask) {
344     return __builtin_popcount(static_cast<uint32_t>(channelMask));
345 }
346 
347 }// namespace oboe
348