1 /*
2  * Copyright 2015 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_TAG "AAudio"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <atomic>
22 #include <stdint.h>
23 #include <aaudio/AAudio.h>
24 
25 #include "AudioStreamBuilder.h"
26 #include "AudioStream.h"
27 #include "AudioClock.h"
28 
29 using namespace aaudio;
30 
AudioStream()31 AudioStream::AudioStream()
32         : mCallbackEnabled(false)
33 {
34     // mThread is a pthread_t of unknown size so we need memset.
35     memset(&mThread, 0, sizeof(mThread));
36     setPeriodNanoseconds(0);
37 }
38 
open(const AudioStreamBuilder & builder)39 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
40 {
41     // Copy parameters from the Builder because the Builder may be deleted after this call.
42     mSamplesPerFrame = builder.getSamplesPerFrame();
43     mSampleRate = builder.getSampleRate();
44     mDeviceId = builder.getDeviceId();
45     mFormat = builder.getFormat();
46     mSharingMode = builder.getSharingMode();
47     mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
48 
49     mPerformanceMode = builder.getPerformanceMode();
50 
51     // callbacks
52     mFramesPerDataCallback = builder.getFramesPerDataCallback();
53     mDataCallbackProc = builder.getDataCallbackProc();
54     mErrorCallbackProc = builder.getErrorCallbackProc();
55     mDataCallbackUserData = builder.getDataCallbackUserData();
56     mErrorCallbackUserData = builder.getErrorCallbackUserData();
57 
58     // This is very helpful for debugging in the future. Please leave it in.
59     ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %d, dir = %s",
60           mSampleRate, mSamplesPerFrame, mFormat, mSharingMode,
61           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
62     ALOGI("AudioStream::open() device = %d, perfMode = %d, callbackFrames = %d",
63           mDeviceId, mPerformanceMode, mFramesPerDataCallback);
64 
65     // Check for values that are ridiculously out of range to prevent math overflow exploits.
66     // The service will do a better check.
67     if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
68         ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
69         return AAUDIO_ERROR_OUT_OF_RANGE;
70     }
71 
72     switch(mFormat) {
73         case AAUDIO_FORMAT_UNSPECIFIED:
74         case AAUDIO_FORMAT_PCM_I16:
75         case AAUDIO_FORMAT_PCM_FLOAT:
76             break; // valid
77         default:
78             ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat);
79             return AAUDIO_ERROR_INVALID_FORMAT;
80             // break;
81     }
82 
83     if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) {
84         ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
85         return AAUDIO_ERROR_INVALID_RATE;
86     }
87 
88     switch(mPerformanceMode) {
89         case AAUDIO_PERFORMANCE_MODE_NONE:
90         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
91         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
92             break;
93         default:
94             ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode);
95             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
96     }
97 
98     return AAUDIO_OK;
99 }
100 
~AudioStream()101 AudioStream::~AudioStream() {
102     close();
103 }
104 
waitForStateChange(aaudio_stream_state_t currentState,aaudio_stream_state_t * nextState,int64_t timeoutNanoseconds)105 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
106                                                 aaudio_stream_state_t *nextState,
107                                                 int64_t timeoutNanoseconds)
108 {
109     aaudio_result_t result = updateStateWhileWaiting();
110     if (result != AAUDIO_OK) {
111         return result;
112     }
113 
114     int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
115     aaudio_stream_state_t state = getState();
116     while (state == currentState && timeoutNanoseconds > 0) {
117         if (durationNanos > timeoutNanoseconds) {
118             durationNanos = timeoutNanoseconds;
119         }
120         AudioClock::sleepForNanos(durationNanos);
121         timeoutNanoseconds -= durationNanos;
122 
123         aaudio_result_t result = updateStateWhileWaiting();
124         if (result != AAUDIO_OK) {
125             return result;
126         }
127 
128         state = getState();
129     }
130     if (nextState != nullptr) {
131         *nextState = state;
132     }
133     return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
134 }
135 
136 // This registers the callback thread with the server before
137 // passing control to the app. This gives the server an opportunity to boost
138 // the thread's performance characteristics.
wrapUserThread()139 void* AudioStream::wrapUserThread() {
140     void* procResult = nullptr;
141     mThreadRegistrationResult = registerThread();
142     if (mThreadRegistrationResult == AAUDIO_OK) {
143         // Run callback loop. This may take a very long time.
144         procResult = mThreadProc(mThreadArg);
145         mThreadRegistrationResult = unregisterThread();
146     }
147     return procResult;
148 }
149 
150 // This is the entry point for the new thread created by createThread().
151 // It converts the 'C' function call to a C++ method call.
AudioStream_internalThreadProc(void * threadArg)152 static void* AudioStream_internalThreadProc(void* threadArg) {
153     AudioStream *audioStream = (AudioStream *) threadArg;
154     return audioStream->wrapUserThread();
155 }
156 
157 // This is not exposed in the API.
158 // But it is still used internally to implement callbacks for MMAP mode.
createThread(int64_t periodNanoseconds,aaudio_audio_thread_proc_t threadProc,void * threadArg)159 aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
160                                      aaudio_audio_thread_proc_t threadProc,
161                                      void* threadArg)
162 {
163     if (mHasThread) {
164         return AAUDIO_ERROR_INVALID_STATE;
165     }
166     if (threadProc == nullptr) {
167         return AAUDIO_ERROR_NULL;
168     }
169     // Pass input parameters to the background thread.
170     mThreadProc = threadProc;
171     mThreadArg = threadArg;
172     setPeriodNanoseconds(periodNanoseconds);
173     int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
174     if (err != 0) {
175         return AAudioConvert_androidToAAudioResult(-errno);
176     } else {
177         mHasThread = true;
178         return AAUDIO_OK;
179     }
180 }
181 
joinThread(void ** returnArg,int64_t timeoutNanoseconds)182 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
183 {
184     if (!mHasThread) {
185         return AAUDIO_ERROR_INVALID_STATE;
186     }
187 #if 0
188     // TODO implement equivalent of pthread_timedjoin_np()
189     struct timespec abstime;
190     int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
191 #else
192     int err = pthread_join(mThread, returnArg);
193 #endif
194     mHasThread = false;
195     return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
196 }
197 
198