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