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 #include <utils/String16.h>
23 #include <media/AudioTrack.h>
24 #include <aaudio/AAudio.h>
25
26 #include "core/AudioStream.h"
27 #include "legacy/AudioStreamLegacy.h"
28
29 using namespace android;
30 using namespace aaudio;
31
AudioStreamLegacy()32 AudioStreamLegacy::AudioStreamLegacy()
33 : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
34 }
35
~AudioStreamLegacy()36 AudioStreamLegacy::~AudioStreamLegacy() {
37 }
38
39 // Called from AudioTrack.cpp or AudioRecord.cpp
AudioStreamLegacy_callback(int event,void * userData,void * info)40 static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
41 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
42 streamLegacy->processCallback(event, info);
43 }
44
getLegacyCallback()45 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
46 return AudioStreamLegacy_callback;
47 }
48
49 // Implement FixedBlockProcessor
onProcessFixedBlock(uint8_t * buffer,int32_t numBytes)50 int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
51 int32_t frameCount = numBytes / getBytesPerFrame();
52 // Call using the AAudio callback interface.
53 AAudioStream_dataCallback appCallback = getDataCallbackProc();
54 return (*appCallback)(
55 (AAudioStream *) this,
56 getDataCallbackUserData(),
57 buffer,
58 frameCount);
59 }
60
processCallbackCommon(aaudio_callback_operation_t opcode,void * info)61 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
62 aaudio_data_callback_result_t callbackResult;
63
64 if (!mCallbackEnabled.load()) {
65 return;
66 }
67
68 switch (opcode) {
69 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
70 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
71 // Note that this code assumes an AudioTrack::Buffer is the same as
72 // AudioRecord::Buffer
73 // TODO define our own AudioBuffer and pass it from the subclasses.
74 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
75 if (audioBuffer->frameCount == 0) return;
76
77 // If the caller specified an exact size then use a block size adapter.
78 if (mBlockAdapter != nullptr) {
79 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
80 callbackResult = mBlockAdapter->processVariableBlock(
81 (uint8_t *) audioBuffer->raw, byteCount);
82 } else {
83 // Call using the AAudio callback interface.
84 callbackResult = (*getDataCallbackProc())(
85 (AAudioStream *) this,
86 getDataCallbackUserData(),
87 audioBuffer->raw,
88 audioBuffer->frameCount
89 );
90 }
91 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
92 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
93 incrementClientFrameCounter(audioBuffer->frameCount);
94 } else {
95 audioBuffer->size = 0;
96 }
97 break;
98 }
99 }
100 /// FALL THROUGH
101
102 // Stream got rerouted so we disconnect.
103 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: {
104 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
105 ALOGD("processCallbackCommon() stream disconnected");
106 if (getErrorCallbackProc() != nullptr) {
107 (*getErrorCallbackProc())(
108 (AAudioStream *) this,
109 getErrorCallbackUserData(),
110 AAUDIO_ERROR_DISCONNECTED
111 );
112 }
113 mCallbackEnabled.store(false);
114 }
115 break;
116
117 default:
118 break;
119 }
120 }
121
getBestTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds,ExtendedTimestamp * extendedTimestamp)122 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
123 int64_t *framePosition,
124 int64_t *timeNanoseconds,
125 ExtendedTimestamp *extendedTimestamp) {
126 int timebase;
127 switch (clockId) {
128 case CLOCK_BOOTTIME:
129 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
130 break;
131 case CLOCK_MONOTONIC:
132 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
133 break;
134 default:
135 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
136 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
137 break;
138 }
139 status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase);
140 return AAudioConvert_androidToAAudioResult(status);
141 }
142
onAudioDeviceUpdate(audio_port_handle_t deviceId)143 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
144 {
145 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
146 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
147 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
148 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
149 // if we have a data callback and the stream is active, send the error callback from
150 // data callback thread when it sees the DISCONNECTED state
151 if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) {
152 (*getErrorCallbackProc())(
153 (AAudioStream *) this,
154 getErrorCallbackUserData(),
155 AAUDIO_ERROR_DISCONNECTED
156 );
157 }
158 }
159 setDeviceId(deviceId);
160 }
161