summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtneya Nair <atneya@google.com>2022-01-18 16:55:22 -0500
committerAtneya Nair <atneya@google.com>2022-02-09 11:06:52 -0500
commit045e21dfc1d2b7d29f49cd5d81d2fb6c7735615b (patch)
tree5b450ed5a37ea85187be342cea42c558e4695d75
parent48cf30d4a6b635c55a71fdd40ab3b2dca4d73477 (diff)
downloadwilhelm-045e21dfc1d2b7d29f49cd5d81d2fb6c7735615b.tar.gz
Refactor for AudioTrack/Record callback interface
Replace libaudioclient callback functions with appropriate interfaces. Control callback object lifetime with ref-counting. Misc cleanup including using sp<> where appropriate. Test: OboeTester Output/Input streams Bug: 199156212 Bug: 216175830 Change-Id: I366c543e85a62f878908836e9ad1914182dc9e6f
-rw-r--r--src/android/AudioPlayer_to_android.cpp77
-rw-r--r--src/android/AudioRecordCallback.h80
-rw-r--r--src/android/AudioRecorder_to_android.cpp132
-rw-r--r--src/android/AudioTrackCallback.h98
-rw-r--r--src/classes.h2
-rw-r--r--src/itf/IEngine.cpp1
6 files changed, 246 insertions, 144 deletions
diff --git a/src/android/AudioPlayer_to_android.cpp b/src/android/AudioPlayer_to_android.cpp
index a324b4a..ef466b6 100644
--- a/src/android/AudioPlayer_to_android.cpp
+++ b/src/android/AudioPlayer_to_android.cpp
@@ -19,6 +19,7 @@
#include "android/android_AudioToCbRenderer.h"
#include "android/android_StreamPlayer.h"
#include "android/android_LocAVPlayer.h"
+#include "android/AudioTrackCallback.h"
#include "android/include/AacBqToPcmCbRenderer.h"
#include "android/channels.h"
@@ -1233,23 +1234,15 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer)
//-----------------------------------------------------------------------------
// Callback associated with an AudioTrack of an SL ES AudioPlayer that gets its data
// from a buffer queue. This will not be called once the AudioTrack has been destroyed.
-static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *info) {
- CAudioPlayer *ap = (CAudioPlayer *)user;
-
- if (!android::CallbackProtector::enterCbIfOk(ap->mCallbackProtector)) {
- // it is not safe to enter the callback (the track is about to go away)
- return;
- }
+size_t audioTrack_handleMoreData_lockPlay(CAudioPlayer* ap,
+ const android::AudioTrack::Buffer& buffer) {
void * callbackPContext = NULL;
- switch (event) {
-
- case android::AudioTrack::EVENT_MORE_DATA: {
+ size_t bytesWritten = 0;
//SL_LOGV("received event EVENT_MORE_DATA from AudioTrack TID=%d", gettid());
slPrefetchCallback prefetchCallback = NULL;
void *prefetchContext = NULL;
SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
- android::AudioTrack::Buffer* pBuff = (android::AudioTrack::Buffer*)info;
// retrieve data from the buffer queue
interface_lock_exclusive(&ap->mBufferQueue);
@@ -1274,17 +1267,15 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i
BufferHeader *newFront = &oldFront[1];
size_t availSource = oldFront->mSize - ap->mBufferQueue.mSizeConsumed;
- size_t availSink = pBuff->size;
+ size_t availSink = buffer.size();
size_t bytesToCopy = availSource < availSink ? availSource : availSink;
void *pSrc = (char *)oldFront->mBuffer + ap->mBufferQueue.mSizeConsumed;
- memcpy(pBuff->raw, pSrc, bytesToCopy);
-
+ memcpy(buffer.data(), pSrc, bytesToCopy);
+ bytesWritten = bytesToCopy;
if (bytesToCopy < availSource) {
ap->mBufferQueue.mSizeConsumed += bytesToCopy;
- // pBuff->size is already equal to bytesToCopy in this case
} else {
// consumed an entire buffer, dequeue
- pBuff->size = bytesToCopy;
ap->mBufferQueue.mSizeConsumed = 0;
if (newFront ==
&ap->mBufferQueue.mArray
@@ -1299,8 +1290,6 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i
ap->mBufferQueue.mCallbackPending = true;
}
} else { // empty queue
- // signal no data available
- pBuff->size = 0;
// signal we're at the end of the content, but don't pause (see note in function)
audioPlayer_dispatch_headAtEnd_lockPlay(ap, false /*set state to paused?*/, false);
@@ -1336,41 +1325,8 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i
SL_PREFETCHEVENT_FILLLEVELCHANGE);
}
}
- }
- break;
- case android::AudioTrack::EVENT_MARKER:
- //SL_LOGI("received event EVENT_MARKER from AudioTrack");
- audioTrack_handleMarker_lockPlay(ap);
- break;
-
- case android::AudioTrack::EVENT_NEW_POS:
- //SL_LOGI("received event EVENT_NEW_POS from AudioTrack");
- audioTrack_handleNewPos_lockPlay(ap);
- break;
-
- case android::AudioTrack::EVENT_UNDERRUN:
- //SL_LOGI("received event EVENT_UNDERRUN from AudioTrack");
- audioTrack_handleUnderrun_lockPlay(ap);
- break;
-
- case android::AudioTrack::EVENT_NEW_IAUDIOTRACK:
- // ignore for now
- break;
-
- case android::AudioTrack::EVENT_BUFFER_END:
- case android::AudioTrack::EVENT_LOOP_END:
- case android::AudioTrack::EVENT_STREAM_END:
- // These are unexpected so fall through
- FALLTHROUGH_INTENDED;
- default:
- // FIXME where does the notification of SL_PLAYEVENT_HEADMOVING fit?
- SL_LOGE("Encountered unknown AudioTrack event %d for CAudioPlayer %p", event,
- (CAudioPlayer *)user);
- break;
- }
-
- ap->mCallbackProtector->exitCb();
+ return bytesWritten;
}
@@ -1684,16 +1640,15 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async
} else {
notificationFrames = 0;
}
-
- android::AudioTrack* pat = new android::AudioTrack(
+ const auto callbackHandle = android::sp<android::AudioTrackCallback>::make(pAudioPlayer);
+ const auto pat = android::sp<android::AudioTrack>::make(
pAudioPlayer->mStreamType, // streamType
sampleRate, // sampleRate
sles_to_android_sampleFormat(df_pcm), // format
channelMask, // channel mask
0, // frameCount
policy, // flags
- audioTrack_callBack_pullFromBuffQueue, // callback
- (void *) pAudioPlayer, // user
+ callbackHandle, // callback
notificationFrames, // see comment above
pAudioPlayer->mSessionId);
@@ -1702,17 +1657,17 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async
android::status_t status = pat->initCheck();
if (status != android::NO_ERROR) {
- // AudioTracks are meant to be refcounted, so their dtor is protected.
- static_cast<void>(android::sp<android::AudioTrack>(pat));
-
SL_LOGE("AudioTrack::initCheck status %u", status);
// FIXME should return a more specific result depending on status
result = SL_RESULT_CONTENT_UNSUPPORTED;
return result;
}
- pAudioPlayer->mTrackPlayer->init(pat, android::PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE,
- usageForStreamType(pAudioPlayer->mStreamType), pAudioPlayer->mSessionId);
+ pAudioPlayer->mTrackPlayer->init(
+ pat, callbackHandle,
+ android::PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE,
+ usageForStreamType(pAudioPlayer->mStreamType),
+ pAudioPlayer->mSessionId);
// update performance mode according to actual flags granted to AudioTrack
checkAndSetPerformanceModePost(pAudioPlayer);
diff --git a/src/android/AudioRecordCallback.h b/src/android/AudioRecordCallback.h
new file mode 100644
index 0000000..53b7e35
--- /dev/null
+++ b/src/android/AudioRecordCallback.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef SL_PREFETCHEVENT_NONE // This is defined in slesl_allinclusive, which isn't guarded
+#include "sles_allinclusive.h"
+#endif
+
+#include "media/AudioRecord.h"
+
+void audioRecorder_handleOverrun_lockRecord(CAudioRecorder* ar);
+void audioRecorder_handleNewPos_lockRecord(CAudioRecorder* ar);
+void audioRecorder_handleMarker_lockRecord(CAudioRecorder* ar);
+size_t audioRecorder_handleMoreData_lockRecord(CAudioRecorder* ar,
+ const android::AudioRecord::Buffer&);
+//--------------------------------------------------------------------------------------------------
+namespace android {
+
+class AudioRecordCallback : public android::AudioRecord::IAudioRecordCallback {
+ public:
+ AudioRecordCallback(CAudioRecorder * audioRecorder) : mAr(audioRecorder) {}
+ AudioRecordCallback(const AudioRecordCallback&) = delete;
+ AudioRecordCallback& operator=(const AudioRecordCallback&) = delete;
+
+ private:
+ size_t onMoreData(const android::AudioRecord::Buffer& buffer) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAr->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return buffer.size(); // replicate existing behavior
+ }
+ size_t bytesRead = audioRecorder_handleMoreData_lockRecord(mAr, buffer);
+ mAr->mCallbackProtector->exitCb();
+ return bytesRead;
+ }
+
+
+ void onOverrun() override {
+ if (!android::CallbackProtector::enterCbIfOk(mAr->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+ audioRecorder_handleOverrun_lockRecord(mAr);
+ mAr->mCallbackProtector->exitCb();
+ }
+ void onMarker(uint32_t) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAr->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+
+ audioRecorder_handleMarker_lockRecord(mAr);
+ mAr->mCallbackProtector->exitCb();
+ }
+ void onNewPos(uint32_t) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAr->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+
+ audioRecorder_handleNewPos_lockRecord(mAr);
+ mAr->mCallbackProtector->exitCb();
+ }
+ CAudioRecorder * const mAr;
+};
+
+} // namespace android
diff --git a/src/android/AudioRecorder_to_android.cpp b/src/android/AudioRecorder_to_android.cpp
index 411beff..d4b2964 100644
--- a/src/android/AudioRecorder_to_android.cpp
+++ b/src/android/AudioRecorder_to_android.cpp
@@ -24,6 +24,7 @@
#include <SLES/OpenSLES_Android.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android/AudioRecordCallback.h>
#define KEY_RECORDING_SOURCE_PARAMSIZE sizeof(SLuint32)
#define KEY_RECORDING_PRESET_PARAMSIZE sizeof(SLuint32)
@@ -307,96 +308,58 @@ SLresult android_audioRecorder_checkSourceSink(CAudioRecorder* ar) {
return SL_RESULT_SUCCESS;
}
//-----------------------------------------------------------------------------
-static void audioRecorder_callback(int event, void* user, void *info) {
+size_t audioRecorder_handleMoreData_lockRecord(CAudioRecorder* ar,
+ const android::AudioRecord::Buffer& buffer) {
//SL_LOGV("audioRecorder_callback(%d, %p, %p) entering", event, user, info);
- CAudioRecorder *ar = (CAudioRecorder *)user;
-
- if (!android::CallbackProtector::enterCbIfOk(ar->mCallbackProtector)) {
- // it is not safe to enter the callback (the track is about to go away)
- return;
- }
-
void * callbackPContext = NULL;
-
- switch (event) {
- case android::AudioRecord::EVENT_MORE_DATA: {
- slBufferQueueCallback callback = NULL;
- android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;
-
- // push data to the buffer queue
- interface_lock_exclusive(&ar->mBufferQueue);
-
- if (ar->mBufferQueue.mState.count != 0) {
- assert(ar->mBufferQueue.mFront != ar->mBufferQueue.mRear);
-
- BufferHeader *oldFront = ar->mBufferQueue.mFront;
- BufferHeader *newFront = &oldFront[1];
-
- size_t availSink = oldFront->mSize - ar->mBufferQueue.mSizeConsumed;
- size_t availSource = pBuff->size;
- size_t bytesToCopy = availSink < availSource ? availSink : availSource;
- void *pDest = (char *)oldFront->mBuffer + ar->mBufferQueue.mSizeConsumed;
- memcpy(pDest, pBuff->raw, bytesToCopy);
-
- if (bytesToCopy < availSink) {
- // can't consume the whole or rest of the buffer in one shot
- ar->mBufferQueue.mSizeConsumed += availSource;
- // pBuff->size is already equal to bytesToCopy in this case
- } else {
- // finish pushing the buffer or push the buffer in one shot
- pBuff->size = bytesToCopy;
- ar->mBufferQueue.mSizeConsumed = 0;
- if (newFront == &ar->mBufferQueue.mArray[ar->mBufferQueue.mNumBuffers + 1]) {
- newFront = ar->mBufferQueue.mArray;
- }
- ar->mBufferQueue.mFront = newFront;
-
- ar->mBufferQueue.mState.count--;
- ar->mBufferQueue.mState.playIndex++;
-
- // data has been copied to the buffer, and the buffer queue state has been updated
- // we will notify the client if applicable
- callback = ar->mBufferQueue.mCallback;
- // save callback data
- callbackPContext = ar->mBufferQueue.mContext;
+ size_t bytesRead = 0;
+ slBufferQueueCallback callback = NULL;
+
+ // push data to the buffer queue
+ interface_lock_exclusive(&ar->mBufferQueue);
+
+ if (ar->mBufferQueue.mState.count != 0) {
+ assert(ar->mBufferQueue.mFront != ar->mBufferQueue.mRear);
+
+ BufferHeader *oldFront = ar->mBufferQueue.mFront;
+ BufferHeader *newFront = &oldFront[1];
+
+ size_t availSink = oldFront->mSize - ar->mBufferQueue.mSizeConsumed;
+ size_t availSource = buffer.size();
+ size_t bytesToCopy = availSink < availSource ? availSink : availSource;
+ void *pDest = (char *)oldFront->mBuffer + ar->mBufferQueue.mSizeConsumed;
+ memcpy(pDest, buffer.data(), bytesToCopy);
+ bytesRead = bytesToCopy;
+ if (bytesToCopy < availSink) {
+ // can't consume the whole or rest of the buffer in one shot
+ ar->mBufferQueue.mSizeConsumed += availSource;
+ } else {
+ // finish pushing the buffer or push the buffer in one shot
+ ar->mBufferQueue.mSizeConsumed = 0;
+ if (newFront == &ar->mBufferQueue.mArray[ar->mBufferQueue.mNumBuffers + 1]) {
+ newFront = ar->mBufferQueue.mArray;
}
- } else { // empty queue
- // no destination to push the data
- pBuff->size = 0;
- }
+ ar->mBufferQueue.mFront = newFront;
- interface_unlock_exclusive(&ar->mBufferQueue);
+ ar->mBufferQueue.mState.count--;
+ ar->mBufferQueue.mState.playIndex++;
- // notify client
- if (NULL != callback) {
- (*callback)(&ar->mBufferQueue.mItf, callbackPContext);
+ // data has been copied to the buffer, and the buffer queue state has been updated
+ // we will notify the client if applicable
+ callback = ar->mBufferQueue.mCallback;
+ // save callback data
+ callbackPContext = ar->mBufferQueue.mContext;
}
- }
- break;
-
- case android::AudioRecord::EVENT_OVERRUN:
- audioRecorder_handleOverrun_lockRecord(ar);
- break;
-
- case android::AudioRecord::EVENT_MARKER:
- audioRecorder_handleMarker_lockRecord(ar);
- break;
-
- case android::AudioRecord::EVENT_NEW_POS:
- audioRecorder_handleNewPos_lockRecord(ar);
- break;
+ }
- case android::AudioRecord::EVENT_NEW_IAUDIORECORD:
- // ignore for now
- break;
+ interface_unlock_exclusive(&ar->mBufferQueue);
- default:
- SL_LOGE("Encountered unknown AudioRecord event %d for CAudioRecord %p", event, ar);
- break;
+ // notify client
+ if (NULL != callback) {
+ (*callback)(&ar->mBufferQueue.mItf, callbackPContext);
}
-
- ar->mCallbackProtector->exitCb();
+ return bytesRead;
}
@@ -420,6 +383,7 @@ SLresult android_audioRecorder_create(CAudioRecorder* ar) {
// microphone to simple buffer queue
ar->mAndroidObjType = AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE;
ar->mAudioRecord.clear();
+ ar->mCallbackHandle.clear();
ar->mCallbackProtector = new android::CallbackProtector();
ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_DEFAULT;
@@ -694,7 +658,7 @@ SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
attributionSource.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
attributionSource.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
attributionSource.token = android::sp<android::BBinder>::make();
-
+ ar->mCallbackHandle = android::sp<android::AudioRecordCallback>::make(ar);
// initialize platform-specific CAudioRecorder fields
ar->mAudioRecord = new android::AudioRecord(
ar->mRecordSource, // source
@@ -703,8 +667,7 @@ SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
channelMask, // channel mask
attributionSource,
0, // frameCount
- audioRecorder_callback,// callback_t
- (void*)ar, // user, callback data, here the AudioRecorder
+ ar->mCallbackHandle,
0, // notificationFrames
AUDIO_SESSION_ALLOCATE,
android::AudioRecord::TRANSFER_CALLBACK,
@@ -721,6 +684,7 @@ SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
// FIXME should return a more specific result depending on status
result = SL_RESULT_CONTENT_UNSUPPORTED;
ar->mAudioRecord.clear();
+ ar->mCallbackHandle.clear();
return result;
}
@@ -744,6 +708,7 @@ SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
SL_LOGE("Java exception releasing recorder routing object.");
result = SL_RESULT_INTERNAL_ERROR;
ar->mAudioRecord.clear();
+ ar->mCallbackHandle.clear();
return result;
}
}
@@ -810,6 +775,7 @@ void android_audioRecorder_destroy(CAudioRecorder* ar) {
ar->mAudioRecord.clear();
}
// explicit destructor
+ ar->mCallbackHandle.~sp();
ar->mAudioRecord.~sp();
ar->mCallbackProtector.~sp();
}
diff --git a/src/android/AudioTrackCallback.h b/src/android/AudioTrackCallback.h
new file mode 100644
index 0000000..7020606
--- /dev/null
+++ b/src/android/AudioTrackCallback.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef SL_PREFETCHEVENT_NONE // This is defined in slesl_allinclusive, which isn't guarded
+#include "sles_allinclusive.h"
+#endif
+
+#include "media/AudioTrack.h"
+
+void audioPlayer_dispatch_headAtEnd_lockPlay(CAudioPlayer*, bool, bool);
+
+void audioTrack_handleUnderrun_lockPlay(CAudioPlayer* ap);
+void audioTrack_handleMarker_lockPlay(CAudioPlayer* ap);
+void audioTrack_handleNewPos_lockPlay(CAudioPlayer* ap);
+size_t audioTrack_handleMoreData_lockPlay(CAudioPlayer* ap,
+ const android::AudioTrack::Buffer& buffer);
+//--------------------------------------------------------------------------------------------------
+namespace android {
+class AudioTrackCallback : public AudioTrack::IAudioTrackCallback {
+ public:
+ AudioTrackCallback(CAudioPlayer * player) : mAp(player) {}
+
+ size_t onMoreData(const AudioTrack::Buffer& buffer) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAp->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return buffer.size(); // duplicate existing behavior
+ }
+ size_t bytesCopied = audioTrack_handleMoreData_lockPlay(mAp, buffer);
+ mAp->mCallbackProtector->exitCb();
+ return bytesCopied;
+ }
+
+ void onUnderrun() override {
+ if (!android::CallbackProtector::enterCbIfOk(mAp->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+ audioTrack_handleUnderrun_lockPlay(mAp);
+ mAp->mCallbackProtector->exitCb();
+ }
+
+ void onLoopEnd([[maybe_unused]] int32_t loopsRemaining) override {
+ SL_LOGE("Encountered loop end for CAudioPlayer %p", mAp);
+ }
+ void onMarker([[maybe_unused]] uint32_t markerPosition) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAp->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+ audioTrack_handleMarker_lockPlay(mAp);
+ mAp->mCallbackProtector->exitCb();
+ }
+
+ void onNewPos([[maybe_unused]] uint32_t newPos) override {
+ if (!android::CallbackProtector::enterCbIfOk(mAp->mCallbackProtector)) {
+ // it is not safe to enter the callback (the track is about to go away)
+ return;
+ }
+ audioTrack_handleNewPos_lockPlay(mAp);
+ mAp->mCallbackProtector->exitCb();
+ }
+ void onBufferEnd() override {
+ SL_LOGE("Encountered buffer end for CAudioPlayer %p", mAp);
+ }
+ // Ignore
+ void onNewIAudioTrack() override {}
+ void onStreamEnd() override {
+ SL_LOGE("Encountered buffer end for CAudioPlayer %p", mAp);
+ }
+ void onNewTimestamp([[maybe_unused]] AudioTimestamp timestamp) {
+ SL_LOGE("Encountered write more data for CAudioPlayer %p", mAp);
+ }
+ size_t onCanWriteMoreData([[maybe_unused]] const AudioTrack::Buffer& buffer) {
+ SL_LOGE("Encountered write more data for CAudioPlayer %p", mAp);
+ return 0;
+ }
+
+ private:
+ AudioTrackCallback(const AudioTrackCallback&) = delete;
+ AudioTrackCallback& operator=(const AudioTrackCallback&) = delete;
+ CAudioPlayer* const mAp;
+};
+} // namespace android
diff --git a/src/classes.h b/src/classes.h
index fc64f25..c42fde4 100644
--- a/src/classes.h
+++ b/src/classes.h
@@ -21,6 +21,7 @@
#include "android/android_GenericPlayer.h"
#include <media/TrackPlayerBase.h>
#include <audiomanager/IAudioManager.h>
+namespace android { class AudioRecordCallback; };
#endif
// Class structures
@@ -161,6 +162,7 @@
enum AndroidObjectType mAndroidObjType;
android::sp<android::AudioRecord> mAudioRecord;
android::sp<android::CallbackProtector> mCallbackProtector;
+ android::sp<android::AudioRecordCallback> mCallbackHandle;
audio_source_t mRecordSource;
SLuint32 mPerformanceMode;
#endif
diff --git a/src/itf/IEngine.cpp b/src/itf/IEngine.cpp
index da5623c..be2d2b0 100644
--- a/src/itf/IEngine.cpp
+++ b/src/itf/IEngine.cpp
@@ -459,6 +459,7 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco
// FIXME unnecessary once those fields are encapsulated in one class, rather
// than a structure
(void) new (&thiz->mAudioRecord) android::sp<android::AudioRecord>();
+ (void) new (&thiz->mCallbackHandle) android::sp<android::AudioRecordCallback>();
(void) new (&thiz->mCallbackProtector)
android::sp<android::CallbackProtector>();
thiz->mRecordSource = AUDIO_SOURCE_DEFAULT;