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     __android_log_print(ANDROID_LOG_INFO, TAG, "teardownStream()");
50 
51     std::lock_guard<std::mutex> lock(mStreamLock);
52     return teardownStream_l();
53 }
54 
teardownStream_l()55 StreamBase::Result OboeStream::teardownStream_l() {
56     // tear down the player
57     if (mAudioStream == nullptr) {
58         return ERROR_INVALID_STATE;
59     } else {
60         oboe::Result result = oboe::Result::OK;
61         result = mAudioStream->stop();
62         if (result == oboe::Result::OK) {
63             result = mAudioStream->close();
64         }
65         mAudioStream = nullptr;
66         return OboeErrorToMegaAudioError(result);
67     }
68 }
69 
startStream()70 StreamBase::Result OboeStream::startStream() {
71     __android_log_print(ANDROID_LOG_INFO, TAG, "startStream()");
72 
73     // Don't cover up (potential) bugs in AAudio
74     oboe::OboeGlobals::setWorkaroundsEnabled(false);
75 
76     std::lock_guard<std::mutex> lock(mStreamLock);
77 
78     oboe::Result result = oboe::Result::ErrorInternal;
79     if (mAudioStream != nullptr) {
80         result = mAudioStream->requestStart();
81         if (result != oboe::Result::OK){
82             __android_log_print(
83                     ANDROID_LOG_ERROR,
84                     TAG,
85                     "requestStart failed. Error: %s", convertToText(result));
86 
87             // clean up
88             teardownStream_l();
89         }
90     }
91     mStreamStarted = result == oboe::Result::OK;
92 
93     return OboeErrorToMegaAudioError(result);
94 }
95 
stopStream()96 StreamBase::Result OboeStream::stopStream() {
97     std::lock_guard<std::mutex> lock(mStreamLock);
98 
99     Result errCode = ERROR_UNKNOWN;
100     if (mAudioStream == nullptr) {
101         errCode = ERROR_INVALID_STATE;
102     } else {
103         oboe::Result result = mAudioStream->stop();
104         mStreamStarted = false;
105 
106         errCode = OboeErrorToMegaAudioError(result);
107     }
108 
109     mStreamStarted = false;
110     return errCode;
111 }
112 
getTimeStamp(oboe::FrameTimestamp * timeStamp)113 StreamBase::Result OboeStream::getTimeStamp(oboe::FrameTimestamp* timeStamp) {
114     __android_log_print(ANDROID_LOG_INFO, TAG, "getTimeStamp()");
115     Result errCode = ERROR_UNKNOWN;
116     if (mAudioStream == nullptr) {
117         __android_log_print(ANDROID_LOG_INFO, TAG, "ERROR_INVALID_STATE");
118         errCode = ERROR_INVALID_STATE;
119     } else {
120         ResultWithValue<oboe::FrameTimestamp> result = mAudioStream->getTimestamp(CLOCK_MONOTONIC);
121 
122         *timeStamp = result.value();
123 
124         errCode = OK;
125     }
126 
127     return errCode;
128 }
129