1 /*
2 * Copyright 2020 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 #include <android/log.h>
17
18 #include <oboe/Oboe.h>
19
20 #include "OboeStream.h"
21
22 static const char * const TAG = "OboeStream(native)";
23 static const bool LOG = true;
24
25 using namespace oboe;
26
OboeErrorToMegaAudioError(oboe::Result oboeError)27 StreamBase::Result OboeStream::OboeErrorToMegaAudioError(oboe::Result oboeError) {
28
29 StreamBase::Result maErr = ERROR_UNKNOWN;
30
31 switch (oboeError) {
32 case oboe::Result::OK:
33 maErr = OK;
34 break;
35 case oboe::Result::ErrorInternal:
36 maErr = ERROR_UNKNOWN;
37 break;
38 case oboe::Result::ErrorClosed:
39 maErr = ERROR_INVALID_STATE;
40 break;
41 default:
42 maErr = ERROR_UNKNOWN;
43 break;
44 }
45
46 return maErr;
47 }
48
startStream()49 StreamBase::Result OboeStream::startStream() {
50 if (LOG) {
51 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s()", this, __FUNCTION__);
52 }
53 // Don't cover up (potential) bugs in AAudio
54 oboe::OboeGlobals::setWorkaroundsEnabled(false);
55
56 std::lock_guard<std::mutex> lock(mStreamLock);
57
58 oboe::Result result = oboe::Result::ErrorInternal;
59 if (mAudioStream != nullptr) {
60 result = mAudioStream->requestStart();
61 if (result != oboe::Result::OK){
62 __android_log_print(
63 ANDROID_LOG_ERROR,
64 TAG,
65 "requestStart failed. Error: %s", convertToText(result));
66 }
67 }
68 mStreamStarted = result == oboe::Result::OK;
69
70 if (LOG) {
71 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s() returns:%d",
72 this, __FUNCTION__, OboeErrorToMegaAudioError(result));
73 }
74 return OboeErrorToMegaAudioError(result);
75 }
76
closeStream()77 StreamBase::Result OboeStream::closeStream() {
78 // We might have gotten an error because the stream is already stopped,
79 // but we still want to try to close it to avoid a resource leak
80 if (LOG) {
81 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s() mAudioStream:%p",
82 this, __FUNCTION__, mAudioStream.get());
83 }
84
85 oboe::Result result = oboe::Result::OK;
86 if (mAudioStream != nullptr) {
87 result = mAudioStream->close();
88 }
89
90 return OboeErrorToMegaAudioError(result);
91 }
92
stopStream()93 StreamBase::Result OboeStream::stopStream() {
94 if (LOG) {
95 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s() mAudioStream:%p",
96 this, __FUNCTION__, mAudioStream.get());
97 }
98
99 std::lock_guard<std::mutex> lock(mStreamLock);
100
101 Result errCode = ERROR_UNKNOWN;
102 if (mAudioStream == nullptr) {
103 errCode = ERROR_INVALID_STATE;
104 } else {
105 oboe::Result result = mAudioStream->stop();
106 mStreamStarted = false;
107
108 errCode = OboeErrorToMegaAudioError(result);
109 }
110 return errCode;
111 }
112
teardownStream()113 StreamBase::Result OboeStream::teardownStream() {
114 if (LOG) {
115 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s()", this, __FUNCTION__);
116 }
117 std::lock_guard<std::mutex> lock(mStreamLock);
118 return teardownStream_l();
119 }
120
teardownStream_l()121 StreamBase::Result OboeStream::teardownStream_l() {
122 // tear down the stream for this player/recorder
123 if (LOG) {
124 __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%p]::%s()", this, __FUNCTION__);
125 }
126
127 if (mAudioStream == nullptr) {
128 return ERROR_INVALID_STATE;
129 } else {
130 oboe::Result resultStop = mAudioStream->stop();
131
132 // We might have gotten an error because the stream is already stopped,
133 // but we still want to try to close it to avoid a resource leak
134 oboe::Result resultClose = mAudioStream->close();
135
136 mAudioStream = nullptr;
137
138 return OboeErrorToMegaAudioError(
139 resultStop != oboe::Result::OK ? resultStop : resultClose);
140 }
141 }
142
getTimeStamp(oboe::FrameTimestamp * timeStamp)143 StreamBase::Result OboeStream::getTimeStamp(oboe::FrameTimestamp* timeStamp) {
144 Result errCode = ERROR_UNKNOWN;
145 if (mAudioStream == nullptr) {
146 __android_log_print(ANDROID_LOG_ERROR, TAG, "ERROR_INVALID_STATE");
147 errCode = ERROR_INVALID_STATE;
148 } else {
149 ResultWithValue<oboe::FrameTimestamp> result = mAudioStream->getTimestamp(CLOCK_MONOTONIC);
150
151 *timeStamp = result.value();
152
153 errCode = OK;
154 }
155
156 return errCode;
157 }
158
getState() const159 oboe::StreamState OboeStream::getState() const {
160 return mAudioStream != nullptr ? mAudioStream->getState() : oboe::StreamState::Unknown;
161 }
162
getLastErrorCallbackResult()163 int OboeStream::getLastErrorCallbackResult() {
164 return (int) (mAudioStream != nullptr
165 ? (int) mAudioStream->getLastErrorCallbackResult() : StreamBase::ERROR_INVALID_STATE);
166 }
167
getRoutedDeviceId()168 int32_t OboeStream::getRoutedDeviceId() {
169 return (int32_t) (mAudioStream != nullptr
170 ? (int32_t) mAudioStream->getDeviceId()
171 : ROUTING_DEVICE_NONE);
172 }
173
getSharingMode()174 int32_t OboeStream::getSharingMode() {
175 return (int32_t) (mAudioStream != nullptr
176 ? (int32_t) mAudioStream->getSharingMode()
177 : SHARING_MODE_INVALID);
178 }
179
getChannelCount()180 int32_t OboeStream::getChannelCount() {
181 return (int32_t) (mAudioStream != nullptr
182 ? (int32_t) mAudioStream->getChannelCount()
183 : -1);
184 }
185
isMMap()186 bool OboeStream::isMMap() {
187 return OboeExtensions::isMMapUsed(mAudioStream.get());
188 }
189
190