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