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 
24 using namespace oboe;
25 
OboeErrorToMegaAudioError(oboe::Result oboeError)26 StreamBase::Result OboeStream::OboeErrorToMegaAudioError(oboe::Result oboeError) {
27 
28     StreamBase::Result maErr = ERROR_UNKNOWN;
29 
30     switch (oboeError) {
31         case oboe::Result::OK:
32             maErr = OK;
33             break;
34         case oboe::Result::ErrorInternal:
35             maErr = ERROR_UNKNOWN;
36             break;
37         case oboe::Result::ErrorClosed:
38             maErr = ERROR_INVALID_STATE;
39             break;
40         default:
41             maErr = ERROR_UNKNOWN;
42             break;
43     }
44 
45     return maErr;
46 }
47 
teardownStream()48 StreamBase::Result OboeStream::teardownStream() {
49     std::lock_guard<std::mutex> lock(mStreamLock);
50     return teardownStream_l();
51 }
52 
teardownStream_l()53 StreamBase::Result OboeStream::teardownStream_l() {
54     // tear down the player
55     if (mAudioStream == nullptr) {
56         return ERROR_INVALID_STATE;
57     } else {
58         oboe::Result result = oboe::Result::OK;
59         result = mAudioStream->stop();
60         if (result == oboe::Result::OK) {
61             result = mAudioStream->close();
62         }
63         mAudioStream = nullptr;
64         return OboeErrorToMegaAudioError(result);
65     }
66 }
67 
startStream()68 StreamBase::Result OboeStream::startStream() {
69     // Don't cover up (potential) bugs in AAudio
70     oboe::OboeGlobals::setWorkaroundsEnabled(false);
71 
72     std::lock_guard<std::mutex> lock(mStreamLock);
73 
74     oboe::Result result = oboe::Result::ErrorInternal;
75     if (mAudioStream != nullptr) {
76         result = mAudioStream->requestStart();
77         if (result != oboe::Result::OK){
78             __android_log_print(
79                     ANDROID_LOG_ERROR,
80                     TAG,
81                     "requestStart failed. Error: %s", convertToText(result));
82 
83             // clean up
84             teardownStream_l();
85         }
86     }
87     mStreamStarted = result == oboe::Result::OK;
88 
89     return OboeErrorToMegaAudioError(result);
90 }
91 
stopStream()92 StreamBase::Result OboeStream::stopStream() {
93     std::lock_guard<std::mutex> lock(mStreamLock);
94 
95     Result errCode = ERROR_UNKNOWN;
96     if (mAudioStream == nullptr) {
97         errCode = ERROR_INVALID_STATE;
98     } else {
99         oboe::Result result = mAudioStream->stop();
100         mStreamStarted = false;
101 
102         errCode = OboeErrorToMegaAudioError(result);
103     }
104 
105     mStreamStarted = false;
106     return errCode;
107 }
108 
getTimeStamp(oboe::FrameTimestamp * timeStamp)109 StreamBase::Result OboeStream::getTimeStamp(oboe::FrameTimestamp* timeStamp) {
110     Result errCode = ERROR_UNKNOWN;
111     if (mAudioStream == nullptr) {
112         __android_log_print(ANDROID_LOG_ERROR, TAG, "ERROR_INVALID_STATE");
113         errCode = ERROR_INVALID_STATE;
114     } else {
115         ResultWithValue<oboe::FrameTimestamp> result = mAudioStream->getTimestamp(CLOCK_MONOTONIC);
116 
117         *timeStamp = result.value();
118 
119         errCode = OK;
120     }
121 
122     return errCode;
123 }
124 
getState() const125 oboe::StreamState OboeStream::getState() const {
126     return mAudioStream != nullptr ? mAudioStream->getState() : oboe::StreamState::Unknown;
127 }
128 
getLastErrorCallbackResult()129 int OboeStream::getLastErrorCallbackResult() {
130     return (int) (mAudioStream != nullptr
131                     ? (int) mAudioStream->getLastErrorCallbackResult() : StreamBase::ERROR_INVALID_STATE);
132 }
133 
getRoutedDeviceId()134 int32_t OboeStream::getRoutedDeviceId() {
135     return (int32_t) (mAudioStream != nullptr
136                                ? (int32_t) mAudioStream->getDeviceId()
137                                : ROUTING_DEVICE_NONE);
138 }
139 
getSharingMode()140 int32_t OboeStream::getSharingMode() {
141     return (int32_t) (mAudioStream != nullptr
142                                ? (int32_t) mAudioStream->getSharingMode()
143                                : SHARING_MODE_INVALID);
144 }
145 
getChannelCount()146 int32_t OboeStream::getChannelCount() {
147     return (int32_t) (mAudioStream != nullptr
148                                ? (int32_t) mAudioStream->getChannelCount()
149                                : -1);
150 }
151 
isMMap()152 bool OboeStream::isMMap() {
153     return OboeExtensions::isMMapUsed(mAudioStream.get());
154 }
155 
156