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
29using namespace android;
30using namespace aaudio;
31
32AudioStreamLegacy::AudioStreamLegacy()
33        : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
34}
35
36AudioStreamLegacy::~AudioStreamLegacy() {
37}
38
39// Called from AudioTrack.cpp or AudioRecord.cpp
40static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
41    AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
42    streamLegacy->processCallback(event, info);
43}
44
45aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
46    return AudioStreamLegacy_callback;
47}
48
49// Implement FixedBlockProcessor
50int32_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
61void 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
122aaudio_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
143void 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