• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 "AudioStreamLegacy"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <stdint.h>
22 
23 #include <aaudio/AAudio.h>
24 #include <audio_utils/primitives.h>
25 #include <media/AudioTrack.h>
26 #include <media/AudioTimestamp.h>
27 #include <utils/String16.h>
28 
29 #include "core/AudioGlobal.h"
30 #include "core/AudioStream.h"
31 #include "legacy/AudioStreamLegacy.h"
32 
33 using namespace android;
34 using namespace aaudio;
35 
AudioStreamLegacy()36 AudioStreamLegacy::AudioStreamLegacy()
37         : AudioStream() {
38 }
39 
~AudioStreamLegacy()40 AudioStreamLegacy::~AudioStreamLegacy() {
41 }
42 
43 // Called from AudioTrack.cpp or AudioRecord.cpp
AudioStreamLegacy_callback(int event,void * userData,void * info)44 static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
45     AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
46     streamLegacy->processCallback(event, info);
47 }
48 
getLegacyCallback()49 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
50     return AudioStreamLegacy_callback;
51 }
52 
callDataCallbackFrames(uint8_t * buffer,int32_t numFrames)53 aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
54                                                                         int32_t numFrames) {
55     void *finalAudioData = buffer;
56     if (getDirection() == AAUDIO_DIRECTION_INPUT) {
57         // Increment before because we already got the data from the device.
58         incrementFramesRead(numFrames);
59         finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
60     }
61 
62     // Call using the AAudio callback interface.
63     aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
64 
65     if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
66             && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
67         // Increment after because we are going to write the data to the device.
68         incrementFramesWritten(numFrames);
69     }
70     return callbackResult;
71 }
72 
73 // Implement FixedBlockProcessor
onProcessFixedBlock(uint8_t * buffer,int32_t numBytes)74 int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
75     int32_t numFrames = numBytes / mBlockAdapterBytesPerFrame;
76     return (int32_t) callDataCallbackFrames(buffer, numFrames);
77 }
78 
processCallbackCommon(aaudio_callback_operation_t opcode,void * info)79 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
80     aaudio_data_callback_result_t callbackResult;
81     // This illegal size can be used to tell AudioRecord or AudioTrack to stop calling us.
82     // This takes advantage of them killing the stream when they see a size out of range.
83     // That is an undocumented behavior.
84     // TODO add to API in AudioRecord and AudioTrack
85     const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
86 
87     switch (opcode) {
88         case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
89             (void) checkForDisconnectRequest(true);
90 
91             // Note that this code assumes an AudioTrack::Buffer is the same as
92             // AudioRecord::Buffer
93             // TODO define our own AudioBuffer and pass it from the subclasses.
94             AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
95             if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
96                 ALOGW("processCallbackCommon() data, stream disconnected");
97                 audioBuffer->size = SIZE_STOP_CALLBACKS;
98             } else if (!mCallbackEnabled.load()) {
99                 ALOGW("processCallbackCommon() no data because callback disabled");
100                 audioBuffer->size = SIZE_STOP_CALLBACKS;
101             } else {
102                 if (audioBuffer->frameCount == 0) {
103                     ALOGW("processCallbackCommon() data, frameCount is zero");
104                     return;
105                 }
106 
107                 // If the caller specified an exact size then use a block size adapter.
108                 if (mBlockAdapter != nullptr) {
109                     int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
110                     callbackResult = mBlockAdapter->processVariableBlock(
111                             (uint8_t *) audioBuffer->raw, byteCount);
112                 } else {
113                     // Call using the AAudio callback interface.
114                     callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
115                                                             audioBuffer->frameCount);
116                 }
117                 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
118                     audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
119                 } else {
120                     if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
121                         ALOGD("%s() callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
122                     } else {
123                         ALOGW("%s() callback returned invalid result = %d",
124                               __func__, callbackResult);
125                     }
126                     audioBuffer->size = 0;
127                     systemStopFromCallback();
128                     // Disable the callback just in case the system keeps trying to call us.
129                     mCallbackEnabled.store(false);
130                 }
131 
132                 if (updateStateMachine() != AAUDIO_OK) {
133                     forceDisconnect();
134                     mCallbackEnabled.store(false);
135                 }
136             }
137         }
138             break;
139 
140         // Stream got rerouted so we disconnect.
141         case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
142             ALOGD("processCallbackCommon() stream disconnected");
143             forceDisconnect();
144             mCallbackEnabled.store(false);
145             break;
146 
147         default:
148             break;
149     }
150 }
151 
checkForDisconnectRequest(bool errorCallbackEnabled)152 aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
153     if (mRequestDisconnect.isRequested()) {
154         ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
155         forceDisconnect(errorCallbackEnabled);
156         mRequestDisconnect.acknowledge();
157         mCallbackEnabled.store(false);
158         return AAUDIO_ERROR_DISCONNECTED;
159     } else {
160         return AAUDIO_OK;
161     }
162 }
163 
forceDisconnect(bool errorCallbackEnabled)164 void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
165     // There is no need to disconnect if already in these states.
166     if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED
167             && getState() != AAUDIO_STREAM_STATE_CLOSING
168             && getState() != AAUDIO_STREAM_STATE_CLOSED
169             ) {
170         setState(AAUDIO_STREAM_STATE_DISCONNECTED);
171         if (errorCallbackEnabled) {
172             maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
173         }
174     }
175 }
176 
getBestTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds,ExtendedTimestamp * extendedTimestamp)177 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
178                                                    int64_t *framePosition,
179                                                    int64_t *timeNanoseconds,
180                                                    ExtendedTimestamp *extendedTimestamp) {
181     int timebase;
182     switch (clockId) {
183         case CLOCK_BOOTTIME:
184             timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
185             break;
186         case CLOCK_MONOTONIC:
187             timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
188             break;
189         default:
190             ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
191             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
192             break;
193     }
194     ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
195     int64_t localPosition;
196     status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
197                                                           timebase, &location);
198     if (status == OK) {
199         // use MonotonicCounter to prevent retrograde motion.
200         mTimestampPosition.update32((int32_t) localPosition);
201         *framePosition = mTimestampPosition.get();
202     }
203 
204 //    ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
205 //          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
206 //          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
207 //          (int)location);
208     return AAudioConvert_androidToAAudioResult(status);
209 }
210 
onAudioDeviceUpdate(audio_io_handle_t,audio_port_handle_t deviceId)211 void AudioStreamLegacy::onAudioDeviceUpdate(audio_io_handle_t /* audioIo */,
212             audio_port_handle_t deviceId) {
213     // Device routing is a common source of errors and DISCONNECTS.
214     // Please leave this log in place. If there is a bug then this might
215     // get called after the stream has been deleted so log before we
216     // touch the stream object.
217     ALOGD("%s(deviceId = %d)", __func__, (int)deviceId);
218     if (getDeviceId() != AAUDIO_UNSPECIFIED
219             && getDeviceId() != deviceId
220             && getState() != AAUDIO_STREAM_STATE_DISCONNECTED
221             ) {
222         // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
223         // If we have a data callback and the stream is active, then ask the data callback
224         // to DISCONNECT and call the error callback.
225         if (isDataCallbackActive()) {
226             ALOGD("%s() request DISCONNECT in data callback, device %d => %d",
227                   __func__, (int) getDeviceId(), (int) deviceId);
228             // If the stream is stopped before the data callback has a chance to handle the
229             // request then the requestStop() and requestPause() methods will handle it after
230             // the callback has stopped.
231             mRequestDisconnect.request();
232         } else {
233             ALOGD("%s() DISCONNECT the stream now, device %d => %d",
234                   __func__, (int) getDeviceId(), (int) deviceId);
235             forceDisconnect();
236         }
237     }
238     setDeviceId(deviceId);
239 }
240