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         default:
70             break;
71     }
72     return size;
73 }
74 
75 template<>
convertToText(Result returnCode)76 const char *convertToText<Result>(Result returnCode) {
77     switch (returnCode) {
78         case Result::OK:                    return "OK";
79         case Result::ErrorDisconnected:     return "ErrorDisconnected";
80         case Result::ErrorIllegalArgument:  return "ErrorIllegalArgument";
81         case Result::ErrorInternal:         return "ErrorInternal";
82         case Result::ErrorInvalidState:     return "ErrorInvalidState";
83         case Result::ErrorInvalidHandle:    return "ErrorInvalidHandle";
84         case Result::ErrorUnimplemented:    return "ErrorUnimplemented";
85         case Result::ErrorUnavailable:      return "ErrorUnavailable";
86         case Result::ErrorNoFreeHandles:    return "ErrorNoFreeHandles";
87         case Result::ErrorNoMemory:         return "ErrorNoMemory";
88         case Result::ErrorNull:             return "ErrorNull";
89         case Result::ErrorTimeout:          return "ErrorTimeout";
90         case Result::ErrorWouldBlock:       return "ErrorWouldBlock";
91         case Result::ErrorInvalidFormat:    return "ErrorInvalidFormat";
92         case Result::ErrorOutOfRange:       return "ErrorOutOfRange";
93         case Result::ErrorNoService:        return "ErrorNoService";
94         case Result::ErrorInvalidRate:      return "ErrorInvalidRate";
95         case Result::ErrorClosed:           return "ErrorClosed";
96         default:                            return "Unrecognized result";
97     }
98 }
99 
100 template<>
convertToText(AudioFormat format)101 const char *convertToText<AudioFormat>(AudioFormat format) {
102     switch (format) {
103         case AudioFormat::Invalid:      return "Invalid";
104         case AudioFormat::Unspecified:  return "Unspecified";
105         case AudioFormat::I16:          return "I16";
106         case AudioFormat::Float:        return "Float";
107         case AudioFormat::I24:          return "I24";
108         case AudioFormat::I32:          return "I32";
109         default:                        return "Unrecognized format";
110     }
111 }
112 
113 template<>
convertToText(PerformanceMode mode)114 const char *convertToText<PerformanceMode>(PerformanceMode mode) {
115     switch (mode) {
116         case PerformanceMode::LowLatency:   return "LowLatency";
117         case PerformanceMode::None:         return "None";
118         case PerformanceMode::PowerSaving:  return "PowerSaving";
119         default:                            return "Unrecognized performance mode";
120     }
121 }
122 
123 template<>
convertToText(SharingMode mode)124 const char *convertToText<SharingMode>(SharingMode mode) {
125     switch (mode) {
126         case SharingMode::Exclusive:    return "Exclusive";
127         case SharingMode::Shared:       return "Shared";
128         default:                        return "Unrecognized sharing mode";
129     }
130 }
131 
132 template<>
convertToText(DataCallbackResult result)133 const char *convertToText<DataCallbackResult>(DataCallbackResult result) {
134     switch (result) {
135         case DataCallbackResult::Continue:  return "Continue";
136         case DataCallbackResult::Stop:      return "Stop";
137         default:                            return "Unrecognized data callback result";
138     }
139 }
140 
141 template<>
convertToText(Direction direction)142 const char *convertToText<Direction>(Direction direction) {
143     switch (direction) {
144         case Direction::Input:  return "Input";
145         case Direction::Output: return "Output";
146         default:                return "Unrecognized direction";
147     }
148 }
149 
150 template<>
convertToText(StreamState state)151 const char *convertToText<StreamState>(StreamState state) {
152     switch (state) {
153         case StreamState::Closed:           return "Closed";
154         case StreamState::Closing:          return "Closing";
155         case StreamState::Disconnected:     return "Disconnected";
156         case StreamState::Flushed:          return "Flushed";
157         case StreamState::Flushing:         return "Flushing";
158         case StreamState::Open:             return "Open";
159         case StreamState::Paused:           return "Paused";
160         case StreamState::Pausing:          return "Pausing";
161         case StreamState::Started:          return "Started";
162         case StreamState::Starting:         return "Starting";
163         case StreamState::Stopped:          return "Stopped";
164         case StreamState::Stopping:         return "Stopping";
165         case StreamState::Uninitialized:    return "Uninitialized";
166         case StreamState::Unknown:          return "Unknown";
167         default:                            return "Unrecognized stream state";
168     }
169 }
170 
171 template<>
convertToText(AudioApi audioApi)172 const char *convertToText<AudioApi>(AudioApi audioApi) {
173 
174     switch (audioApi) {
175         case AudioApi::Unspecified: return "Unspecified";
176         case AudioApi::OpenSLES:    return "OpenSLES";
177         case AudioApi::AAudio:      return "AAudio";
178         default:                    return "Unrecognized audio API";
179     }
180 }
181 
182 template<>
convertToText(AudioStream * stream)183 const char *convertToText<AudioStream*>(AudioStream* stream) {
184     static std::string streamText;
185     std::stringstream s;
186 
187     s<<"StreamID: "<< static_cast<void*>(stream)<<std::endl
188      <<"DeviceId: "<<stream->getDeviceId()<<std::endl
189      <<"Direction: "<<oboe::convertToText(stream->getDirection())<<std::endl
190      <<"API type: "<<oboe::convertToText(stream->getAudioApi())<<std::endl
191      <<"BufferCapacity: "<<stream->getBufferCapacityInFrames()<<std::endl
192      <<"BufferSize: "<<stream->getBufferSizeInFrames()<<std::endl
193      <<"FramesPerBurst: "<< stream->getFramesPerBurst()<<std::endl
194      <<"FramesPerDataCallback: "<<stream->getFramesPerDataCallback()<<std::endl
195      <<"SampleRate: "<<stream->getSampleRate()<<std::endl
196      <<"ChannelCount: "<<stream->getChannelCount()<<std::endl
197      <<"Format: "<<oboe::convertToText(stream->getFormat())<<std::endl
198      <<"SharingMode: "<<oboe::convertToText(stream->getSharingMode())<<std::endl
199      <<"PerformanceMode: "<<oboe::convertToText(stream->getPerformanceMode())
200      <<std::endl
201      <<"CurrentState: "<<oboe::convertToText(stream->getState())<<std::endl
202      <<"XRunCount: "<<stream->getXRunCount()<<std::endl
203      <<"FramesRead: "<<stream->getFramesRead()<<std::endl
204      <<"FramesWritten: "<<stream->getFramesWritten()<<std::endl;
205 
206     streamText = s.str();
207     return streamText.c_str();
208 }
209 
210 template<>
convertToText(Usage usage)211 const char *convertToText<Usage>(Usage usage) {
212 
213     switch (usage) {
214         case Usage::Media:                         return "Media";
215         case Usage::VoiceCommunication:            return "VoiceCommunication";
216         case Usage::VoiceCommunicationSignalling:  return "VoiceCommunicationSignalling";
217         case Usage::Alarm:                         return "Alarm";
218         case Usage::Notification:                  return "Notification";
219         case Usage::NotificationRingtone:          return "NotificationRingtone";
220         case Usage::NotificationEvent:             return "NotificationEvent";
221         case Usage::AssistanceAccessibility:       return "AssistanceAccessibility";
222         case Usage::AssistanceNavigationGuidance:  return "AssistanceNavigationGuidance";
223         case Usage::AssistanceSonification:        return "AssistanceSonification";
224         case Usage::Game:                          return "Game";
225         case Usage::Assistant:                     return "Assistant";
226         default:                                   return "Unrecognized usage";
227     }
228 }
229 
230 template<>
convertToText(ContentType contentType)231 const char *convertToText<ContentType>(ContentType contentType) {
232 
233     switch (contentType) {
234         case ContentType::Speech:        return "Speech";
235         case ContentType::Music:         return "Music";
236         case ContentType::Movie:         return "Movie";
237         case ContentType::Sonification:  return "Sonification";
238         default:                         return "Unrecognized content type";
239     }
240 }
241 
242 template<>
convertToText(InputPreset inputPreset)243 const char *convertToText<InputPreset>(InputPreset inputPreset) {
244 
245     switch (inputPreset) {
246         case InputPreset::Generic:             return "Generic";
247         case InputPreset::Camcorder:           return "Camcorder";
248         case InputPreset::VoiceRecognition:    return "VoiceRecognition";
249         case InputPreset::VoiceCommunication:  return "VoiceCommunication";
250         case InputPreset::Unprocessed:         return "Unprocessed";
251         case InputPreset::VoicePerformance:    return "VoicePerformance";
252         default:                               return "Unrecognized input preset";
253     }
254 }
255 
256 template<>
convertToText(SessionId sessionId)257 const char *convertToText<SessionId>(SessionId sessionId) {
258 
259     switch (sessionId) {
260         case SessionId::None:      return "None";
261         case SessionId::Allocate:  return "Allocate";
262         default:                   return "Unrecognized session id";
263     }
264 }
265 
266 template<>
convertToText(ChannelCount channelCount)267 const char *convertToText<ChannelCount>(ChannelCount channelCount) {
268 
269     switch (channelCount) {
270         case ChannelCount::Unspecified:  return "Unspecified";
271         case ChannelCount::Mono:         return "Mono";
272         case ChannelCount::Stereo:       return "Stereo";
273         default:                         return "Unrecognized channel count";
274     }
275 }
276 
getPropertyString(const char * name)277 std::string getPropertyString(const char * name) {
278     std::string result;
279 #ifdef __ANDROID__
280     char valueText[PROP_VALUE_MAX] = {0};
281     if (__system_property_get(name, valueText) != 0) {
282         result = valueText;
283     }
284 #else
285     (void) name;
286 #endif
287     return result;
288 }
289 
getPropertyInteger(const char * name,int defaultValue)290 int getPropertyInteger(const char * name, int defaultValue) {
291     int result = defaultValue;
292 #ifdef __ANDROID__
293     char valueText[PROP_VALUE_MAX] = {0};
294     if (__system_property_get(name, valueText) != 0) {
295         result = atoi(valueText);
296     }
297 #else
298     (void) name;
299 #endif
300     return result;
301 }
302 
getSdkVersion()303 int getSdkVersion() {
304     static int sCachedSdkVersion = -1;
305 #ifdef __ANDROID__
306     if (sCachedSdkVersion == -1) {
307         sCachedSdkVersion = getPropertyInteger("ro.build.version.sdk", -1);
308     }
309 #endif
310     return sCachedSdkVersion;
311 }
312 
313 }// namespace oboe
314