• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "AAudioStream"
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         : mPlayerBase(new MyPlayerBase(this))
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 
~AudioStream()39 AudioStream::~AudioStream() {
40     ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
41     // If the stream is deleted when OPEN or in use then audio resources will leak.
42     // This would indicate an internal error. So we want to find this ASAP.
43     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
44                           || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
45                           || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
46                         "aaudio stream still in use, state = %s",
47                         AAudio_convertStreamStateToText(getState()));
48 
49     mPlayerBase->clearParentReference(); // remove reference to this AudioStream
50 }
51 
AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode)52 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
53     const char *result;
54     switch (sharingMode) {
55         case AAUDIO_SHARING_MODE_EXCLUSIVE:
56             result = "EX";
57             break;
58         case AAUDIO_SHARING_MODE_SHARED:
59             result = "SH";
60             break;
61         default:
62             result = "?!";
63             break;
64     }
65     return result;
66 }
67 
open(const AudioStreamBuilder & builder)68 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
69 {
70     // Call here as well because the AAudioService will call this without calling build().
71     aaudio_result_t result = builder.validate();
72     if (result != AAUDIO_OK) {
73         return result;
74     }
75 
76     // Copy parameters from the Builder because the Builder may be deleted after this call.
77     mSamplesPerFrame = builder.getSamplesPerFrame();
78     mSampleRate = builder.getSampleRate();
79     mDeviceId = builder.getDeviceId();
80     mFormat = builder.getFormat();
81     mSharingMode = builder.getSharingMode();
82     mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
83 
84     mPerformanceMode = builder.getPerformanceMode();
85 
86     // callbacks
87     mFramesPerDataCallback = builder.getFramesPerDataCallback();
88     mDataCallbackProc = builder.getDataCallbackProc();
89     mErrorCallbackProc = builder.getErrorCallbackProc();
90     mDataCallbackUserData = builder.getDataCallbackUserData();
91     mErrorCallbackUserData = builder.getErrorCallbackUserData();
92 
93     // This is very helpful for debugging in the future. Please leave it in.
94     ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
95           mSampleRate, mSamplesPerFrame, mFormat,
96           AudioStream_convertSharingModeToShortText(mSharingMode),
97           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
98     ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
99           mDeviceId, mPerformanceMode,
100           (mDataCallbackProc == nullptr ? "OFF" : "ON"),
101           mFramesPerDataCallback);
102 
103     return AAUDIO_OK;
104 }
105 
106 
waitForStateChange(aaudio_stream_state_t currentState,aaudio_stream_state_t * nextState,int64_t timeoutNanoseconds)107 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
108                                                 aaudio_stream_state_t *nextState,
109                                                 int64_t timeoutNanoseconds)
110 {
111     aaudio_result_t result = updateStateMachine();
112     if (result != AAUDIO_OK) {
113         return result;
114     }
115 
116     int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
117     aaudio_stream_state_t state = getState();
118     while (state == currentState && timeoutNanoseconds > 0) {
119         if (durationNanos > timeoutNanoseconds) {
120             durationNanos = timeoutNanoseconds;
121         }
122         AudioClock::sleepForNanos(durationNanos);
123         timeoutNanoseconds -= durationNanos;
124 
125         aaudio_result_t result = updateStateMachine();
126         if (result != AAUDIO_OK) {
127             return result;
128         }
129 
130         state = getState();
131     }
132     if (nextState != nullptr) {
133         *nextState = state;
134     }
135     return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
136 }
137 
138 // This registers the callback thread with the server before
139 // passing control to the app. This gives the server an opportunity to boost
140 // the thread's performance characteristics.
wrapUserThread()141 void* AudioStream::wrapUserThread() {
142     void* procResult = nullptr;
143     mThreadRegistrationResult = registerThread();
144     if (mThreadRegistrationResult == AAUDIO_OK) {
145         // Run callback loop. This may take a very long time.
146         procResult = mThreadProc(mThreadArg);
147         mThreadRegistrationResult = unregisterThread();
148     }
149     return procResult;
150 }
151 
152 // This is the entry point for the new thread created by createThread().
153 // It converts the 'C' function call to a C++ method call.
AudioStream_internalThreadProc(void * threadArg)154 static void* AudioStream_internalThreadProc(void* threadArg) {
155     AudioStream *audioStream = (AudioStream *) threadArg;
156     return audioStream->wrapUserThread();
157 }
158 
159 // This is not exposed in the API.
160 // But it is still used internally to implement callbacks for MMAP mode.
createThread(int64_t periodNanoseconds,aaudio_audio_thread_proc_t threadProc,void * threadArg)161 aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
162                                      aaudio_audio_thread_proc_t threadProc,
163                                      void* threadArg)
164 {
165     if (mHasThread) {
166         ALOGE("AudioStream::createThread() - mHasThread already true");
167         return AAUDIO_ERROR_INVALID_STATE;
168     }
169     if (threadProc == nullptr) {
170         return AAUDIO_ERROR_NULL;
171     }
172     // Pass input parameters to the background thread.
173     mThreadProc = threadProc;
174     mThreadArg = threadArg;
175     setPeriodNanoseconds(periodNanoseconds);
176     int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
177     if (err != 0) {
178         return AAudioConvert_androidToAAudioResult(-errno);
179     } else {
180         mHasThread = true;
181         return AAUDIO_OK;
182     }
183 }
184 
joinThread(void ** returnArg,int64_t timeoutNanoseconds)185 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
186 {
187     if (!mHasThread) {
188         ALOGE("AudioStream::joinThread() - but has no thread");
189         return AAUDIO_ERROR_INVALID_STATE;
190     }
191 #if 0
192     // TODO implement equivalent of pthread_timedjoin_np()
193     struct timespec abstime;
194     int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
195 #else
196     int err = pthread_join(mThread, returnArg);
197 #endif
198     mHasThread = false;
199     return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
200 }
201 
202 
203 #if AAUDIO_USE_VOLUME_SHAPER
applyVolumeShaper(const android::media::VolumeShaper::Configuration & configuration __unused,const android::media::VolumeShaper::Operation & operation __unused)204 android::media::VolumeShaper::Status AudioStream::applyVolumeShaper(
205         const android::media::VolumeShaper::Configuration& configuration __unused,
206         const android::media::VolumeShaper::Operation& operation __unused) {
207     ALOGW("applyVolumeShaper() is not supported");
208     return android::media::VolumeShaper::Status::ok();
209 }
210 #endif
211 
MyPlayerBase(AudioStream * parent)212 AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
213 }
214 
~MyPlayerBase()215 AudioStream::MyPlayerBase::~MyPlayerBase() {
216     ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
217 }
218 
registerWithAudioManager()219 void AudioStream::MyPlayerBase::registerWithAudioManager() {
220     if (!mRegistered) {
221         init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
222         mRegistered = true;
223     }
224 }
225 
unregisterWithAudioManager()226 void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
227     if (mRegistered) {
228         baseDestroy();
229         mRegistered = false;
230     }
231 }
232 
233 
destroy()234 void AudioStream::MyPlayerBase::destroy() {
235     unregisterWithAudioManager();
236 }
237