aaudio: close MMAP stream if client dies
Notify client when audio service dies. Clear connection.
Notify AAudio service when client dies. Close client streams.
Use sp<> to track ServiceStreams.
Bug: 38267698
Test: test_no_close.cpp
Change-Id: I5f1699ed3b8b7bd960947c0028a89ca8419ce7a0
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 3a00f51..d4cb407 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -25,7 +25,7 @@
#include "AAudioSimplePlayer.h"
#define SAMPLE_RATE 48000
-#define NUM_SECONDS 20
+#define NUM_SECONDS 4
#define MMAP_POLICY AAUDIO_UNSPECIFIED
//#define MMAP_POLICY AAUDIO_POLICY_NEVER
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 28c4d7f..7131c6c 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -52,6 +52,7 @@
binding/AAudioBinderClient.cpp \
binding/AAudioStreamRequest.cpp \
binding/AAudioStreamConfiguration.cpp \
+ binding/IAAudioClient.cpp \
binding/IAAudioService.cpp \
binding/RingBufferParcelable.cpp \
binding/SharedMemoryParcelable.cpp \
@@ -109,6 +110,7 @@
binding/AAudioBinderClient.cpp \
binding/AAudioStreamRequest.cpp \
binding/AAudioStreamConfiguration.cpp \
+ binding/IAAudioClient.cpp \
binding/IAAudioService.cpp \
binding/RingBufferParcelable.cpp \
binding/SharedMemoryParcelable.cpp \
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index c45bd71..6464334 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -19,75 +19,101 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h>
+#include <media/AudioSystem.h>
#include <aaudio/AAudio.h>
#include "AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
-#include "binding/AAudioStreamConfiguration.h"
-#include "binding/IAAudioService.h"
-#include "binding/AAudioServiceMessage.h"
+#include "binding/AAudioBinderClient.h"
+//#include "binding/AAudioStreamRequest.h"
+//#include "binding/AAudioStreamConfiguration.h"
+//#include "binding/IAAudioService.h"
+//#include "binding/AAudioServiceMessage.h"
-#include "AAudioBinderClient.h"
-#include "AAudioServiceInterface.h"
+//#include "AAudioServiceInterface.h"
using android::String16;
using android::IServiceManager;
using android::defaultServiceManager;
using android::interface_cast;
+using android::IInterface;
using android::IAAudioService;
using android::Mutex;
using android::sp;
+using android::wp;
using namespace aaudio;
-static android::Mutex gServiceLock;
-static sp<IAAudioService> gAAudioService;
-
ANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient);
+AAudioBinderClient::AAudioBinderClient()
+ : AAudioServiceInterface()
+ , Singleton<AAudioBinderClient>() {
+
+ mAAudioClient = new AAudioClient(this);
+ ALOGD("AAudioBinderClient() created mAAudioClient = %p", mAAudioClient.get());
+}
+
+AAudioBinderClient::~AAudioBinderClient() {
+ Mutex::Autolock _l(mServiceLock);
+ if (mAAudioService != 0) {
+ IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
+ }
+}
+
// TODO Share code with other service clients.
// Helper function to get access to the "AAudioService" service.
// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
-static const sp<IAAudioService> getAAudioService() {
- sp<IBinder> binder;
- Mutex::Autolock _l(gServiceLock);
- if (gAAudioService == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- // Try several times to get the service.
- int retries = 4;
- do {
- binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+const sp<IAAudioService> AAudioBinderClient::getAAudioService() {
+ sp<IAAudioService> aaudioService;
+ bool needToRegister = false;
+ {
+ Mutex::Autolock _l(mServiceLock);
+ if (mAAudioService == 0) {
+ sp<IBinder> binder;
+ sp<IServiceManager> sm = defaultServiceManager();
+ // Try several times to get the service.
+ int retries = 4;
+ do {
+ binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+ if (binder != 0) {
+ break;
+ }
+ } while (retries-- > 0);
+
if (binder != 0) {
- break;
+ // Ask for notification if the service dies.
+ status_t status = binder->linkToDeath(mAAudioClient);
+ ALOGD("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
+ mAAudioClient.get(), status);
+ mAAudioService = interface_cast<IAAudioService>(binder);
+ needToRegister = true;
+ // Make sure callbacks can be received by mAAudioClient
+ android::ProcessState::self()->startThreadPool();
+ } else {
+ ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
}
- } while (retries-- > 0);
-
- if (binder != 0) {
- // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
- // TODO Create a DeathRecipient that disconnects all active streams.
- gAAudioService = interface_cast<IAAudioService>(binder);
- } else {
- ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME);
}
+ aaudioService = mAAudioService;
}
- return gAAudioService;
+ // Do this outside the mutex lock.
+ if (needToRegister && aaudioService != 0) { // new client?
+ aaudioService->registerClient(mAAudioClient);
+ }
+ return aaudioService;
}
-static void dropAAudioService() {
- Mutex::Autolock _l(gServiceLock);
- gAAudioService.clear(); // force a reconnect
+void AAudioBinderClient::dropAAudioService() {
+ Mutex::Autolock _l(mServiceLock);
+ mAAudioService.clear(); // force a reconnect
}
-AAudioBinderClient::AAudioBinderClient()
- : AAudioServiceInterface()
- , Singleton<AAudioBinderClient>() {}
-
-AAudioBinderClient::~AAudioBinderClient() {}
/**
* @param request info needed to create the stream
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 7cf7bf8..469f0a8 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
#define ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
+#include <utils/RefBase.h>
#include <utils/Singleton.h>
#include <aaudio/AAudio.h>
@@ -25,14 +26,16 @@
#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
#include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioService.h"
/**
- * Implements the AAudioServiceInterface by talking to the actual service through Binder.
+ * Implements the AAudioServiceInterface by talking to the service through Binder.
*/
namespace aaudio {
-class AAudioBinderClient : public AAudioServiceInterface
+class AAudioBinderClient : public virtual android::RefBase
+ , public AAudioServiceInterface
, public android::Singleton<AAudioBinderClient> {
public:
@@ -41,6 +44,12 @@
virtual ~AAudioBinderClient();
+ const android::sp<android::IAAudioService> getAAudioService();
+
+ void dropAAudioService();
+
+ void registerClient(const android::sp<android::IAAudioClient>& client __unused) override {}
+
/**
* @param request info needed to create the stream
* @param configuration contains resulting information about the created stream
@@ -87,6 +96,45 @@
aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) override;
+
+ void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+ // TODO This is just a stub so we can have a client Binder to pass to the service.
+ // TODO Implemented in a later CL.
+ ALOGW("onStreamChange called!");
+ }
+
+ class AAudioClient : public android::IBinder::DeathRecipient , public android::BnAAudioClient
+ {
+ public:
+ AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient)
+ : mBinderClient(aaudioBinderClient) {
+ }
+
+ // implement DeathRecipient
+ virtual void binderDied(const android::wp<android::IBinder>& who __unused) {
+ android::sp<AAudioBinderClient> client = mBinderClient.promote();
+ if (client != 0) {
+ client->dropAAudioService();
+ }
+ ALOGW("AAudio service binderDied()!");
+ }
+
+ // implement BnAAudioClient
+ void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+ android::sp<AAudioBinderClient> client = mBinderClient.promote();
+ if (client != 0) {
+ client->onStreamChange(handle, opcode, value);
+ }
+ }
+ private:
+ android::wp<AAudioBinderClient> mBinderClient;
+ };
+
+
+ android::Mutex mServiceLock;
+ android::sp<android::IAAudioService> mAAudioService;
+ android::sp<AAudioClient> mAAudioClient;
+
};
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index 638544e..8a2303c 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -29,8 +29,9 @@
namespace android {
-enum aaudio_commands_t {
- OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
+enum aaudio_service_commands_t {
+ REGISTER_CLIENT = IBinder::FIRST_CALL_TRANSACTION,
+ OPEN_STREAM,
CLOSE_STREAM,
GET_STREAM_DESCRIPTION,
START_STREAM,
@@ -41,6 +42,10 @@
UNREGISTER_AUDIO_THREAD
};
+enum aaudio_client_commands_t {
+ ON_STREAM_CHANGE = IBinder::FIRST_CALL_TRANSACTION
+};
+
} // namespace android
namespace aaudio {
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index d6a130f..7368062 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -17,10 +17,13 @@
#ifndef ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
#define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#include <utils/StrongPointer.h>
+
#include "binding/AAudioServiceDefinitions.h"
#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
#include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioClient.h"
/**
* This has the same methods as IAAudioService but without the Binder features.
@@ -36,6 +39,8 @@
AAudioServiceInterface() {};
virtual ~AAudioServiceInterface() = default;
+ virtual void registerClient(const android::sp<android::IAAudioClient>& client) = 0;
+
/**
* @param request info needed to create the stream
* @param configuration contains information about the created stream
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 77138da..462246b 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -68,7 +68,6 @@
mSharingModeMatchRequired = required;
}
-
const AAudioStreamConfiguration &getConstantConfiguration() const {
return mConfiguration;
}
diff --git a/media/libaaudio/src/binding/IAAudioClient.cpp b/media/libaaudio/src/binding/IAAudioClient.cpp
new file mode 100644
index 0000000..c69c4e8
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioBinderClient.h"
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/IAAudioClient.h"
+#include "utility/AAudioUtilities.h"
+
+namespace android {
+
+using aaudio::aaudio_handle_t;
+
+/**
+ * This is used by the AAudio Service to talk to an AAudio Client.
+ *
+ * The order of parameters in the Parcels must match with code in AAudioClient.cpp.
+ */
+class BpAAudioClient : public BpInterface<IAAudioClient>
+{
+public:
+ explicit BpAAudioClient(const sp<IBinder>& impl)
+ : BpInterface<IAAudioClient>(impl)
+ {
+ }
+
+ void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAAudioClient::getInterfaceDescriptor());
+ data.writeInt32(handle);
+ data.writeInt32(opcode);
+ data.writeInt32(value);
+ remote()->transact(ON_STREAM_CHANGE, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+};
+
+// Implement an interface to the service.
+IMPLEMENT_META_INTERFACE(AAudioClient, "IAAudioClient");
+
+// The order of parameters in the Parcels must match with code in BpAAudioClient
+
+status_t BnAAudioClient::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ aaudio_handle_t streamHandle;
+ int32_t opcode = 0;
+ int32_t value = 0;
+ ALOGV("BnAAudioClient::onTransact(%u) %u", code, flags);
+
+ switch(code) {
+ case ON_STREAM_CHANGE: {
+ CHECK_INTERFACE(IAAudioClient, data, reply);
+ data.readInt32(&streamHandle);
+ data.readInt32(&opcode);
+ data.readInt32(&value);
+ onStreamChange(streamHandle, opcode, value);
+ ALOGD("BnAAudioClient onStreamChange(%x, %d, %d)", streamHandle, opcode, value);
+ return NO_ERROR;
+ } break;
+
+ default:
+ // ALOGW("BnAAudioClient::onTransact not handled %u", code);
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
new file mode 100644
index 0000000..21cc33b
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_AAUDIO_IAAUDIO_CLIENT_H
+#define ANDROID_AAUDIO_IAAUDIO_CLIENT_H
+
+#include <stdint.h>
+#include <binder/IInterface.h>
+
+#include <aaudio/AAudio.h>
+
+#include "utility/HandleTracker.h"
+
+namespace android {
+
+
+// Interface (our AIDL) - client methods called by service
+class IAAudioClient : public IInterface {
+public:
+
+ DECLARE_META_INTERFACE(AAudioClient);
+
+ virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+
+};
+
+class BnAAudioClient : public BnInterface<IAAudioClient> {
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+} /* namespace android */
+
+#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index e4bf82a..97fbaaa 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <aaudio/AAudio.h>
#include <binder/IPCThreadState.h>
@@ -41,8 +45,16 @@
{
}
- virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) override {
+ void registerClient(const sp<IAAudioClient>& client) override
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(client));
+ remote()->transact(REGISTER_CLIENT, data, &reply);
+ }
+
+ aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ aaudio::AAudioStreamConfiguration &configurationOutput) override {
Parcel data, reply;
// send command
data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
@@ -56,7 +68,6 @@
// parse reply
aaudio_handle_t stream;
err = reply.readInt32(&stream);
- ALOGD("BpAAudioService::client openStream returned stream = 0x%08x", stream);
if (err != NO_ERROR) {
ALOGE("BpAAudioService::client transact(OPEN_STREAM) readInt %d", err);
return AAudioConvert_androidToAAudioResult(err);
@@ -233,7 +244,7 @@
status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
- aaudio_handle_t stream;
+ aaudio_handle_t streamHandle;
aaudio::AAudioStreamRequest request;
aaudio::AAudioStreamConfiguration configuration;
pid_t tid;
@@ -242,6 +253,14 @@
ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
switch(code) {
+ case REGISTER_CLIENT: {
+ CHECK_INTERFACE(IAAudioService, data, reply);
+ sp<IAAudioClient> client = interface_cast<IAAudioClient>(
+ data.readStrongBinder());
+ registerClient(client);
+ return NO_ERROR;
+ } break;
+
case OPEN_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
request.readFromParcel(&data);
@@ -250,28 +269,28 @@
// Override the uid and pid from the client in case they are incorrect.
request.setUserId(IPCThreadState::self()->getCallingUid());
request.setProcessId(IPCThreadState::self()->getCallingPid());
- stream = openStream(request, configuration);
- //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X ----", stream);
- reply->writeInt32(stream);
+ streamHandle = openStream(request, configuration);
+ //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", streamHandle);
+ reply->writeInt32(streamHandle);
configuration.writeToParcel(reply);
return NO_ERROR;
} break;
case CLOSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
- result = closeStream(stream);
+ data.readInt32(&streamHandle);
+ result = closeStream(streamHandle);
//ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
- // stream, result);
+ // streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case GET_STREAM_DESCRIPTION: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
+ data.readInt32(&streamHandle);
aaudio::AudioEndpointParcelable parcelable;
- result = getStreamDescription(stream, parcelable);
+ result = getStreamDescription(streamHandle, parcelable);
if (result != AAUDIO_OK) {
return AAudioConvert_aaudioToAndroidStatus(result);
}
@@ -288,63 +307,63 @@
case START_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
- result = startStream(stream);
+ data.readInt32(&streamHandle);
+ result = startStream(streamHandle);
ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case PAUSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
- result = pauseStream(stream);
+ data.readInt32(&streamHandle);
+ result = pauseStream(streamHandle);
ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case STOP_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
- result = stopStream(stream);
+ data.readInt32(&streamHandle);
+ result = stopStream(streamHandle);
ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case FLUSH_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
- result = flushStream(stream);
+ data.readInt32(&streamHandle);
+ result = flushStream(streamHandle);
ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case REGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
+ data.readInt32(&streamHandle);
data.readInt32(&tid);
data.readInt64(&nanoseconds);
- result = registerAudioThread(stream, tid, nanoseconds);
+ result = registerAudioThread(streamHandle, tid, nanoseconds);
ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case UNREGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&stream);
+ data.readInt32(&streamHandle);
data.readInt32(&tid);
- result = unregisterAudioThread(stream, tid);
+ result = unregisterAudioThread(streamHandle, tid);
ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
- stream, result);
+ streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 071c5b8..30b3ead 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -28,18 +28,24 @@
#include "binding/AudioEndpointParcelable.h"
#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioClient.h"
#include "utility/HandleTracker.h"
namespace android {
#define AAUDIO_SERVICE_NAME "media.aaudio"
-// Interface (our AIDL) - Shared by server and client
+// Interface (our AIDL) - service methods called by client
class IAAudioService : public IInterface {
public:
DECLARE_META_INTERFACE(AAudioService);
+ // Register an object to receive audio input/output change and track notifications.
+ // For a given calling pid, AAudio service disregards any registrations after the first.
+ // Thus the IAAudioClient must be a singleton per process.
+ virtual void registerClient(const sp<IAAudioClient>& client) = 0;
+
/**
* @param request info needed to create the stream
* @param configuration contains information about the created stream
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index e6c779b..bd7169f 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -49,3 +49,23 @@
LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
LOCAL_MODULE := test_open_params
include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-utils) \
+ frameworks/av/media/libaaudio/include \
+ frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_no_close.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_no_close
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-utils) \
+ frameworks/av/media/libaaudio/include \
+ frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_recovery.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_aaudio_recovery
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_no_close.cpp b/media/libaaudio/tests/test_no_close.cpp
new file mode 100644
index 0000000..2dbf153
--- /dev/null
+++ b/media/libaaudio/tests/test_no_close.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Try to create a resource leak in the server by opening a stream and then not closing it.
+// Return 0 if the stream opened, 1 if it failed.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <aaudio/AAudio.h>
+
+int main(int argc, char **argv)
+{
+ (void)argc; // unused
+ (void)argv; // unused
+
+ aaudio_result_t result = AAUDIO_OK;
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ AAudioStream *aaudioStream = nullptr;
+
+ result = AAudio_createStreamBuilder(&aaudioBuilder);
+ if (result != AAUDIO_OK) {
+ goto finish;
+ }
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR could not open AAudio stream, %d\n", result);
+ goto finish;
+ } else {
+ printf("AAudio stream opened successfully.\n");
+ }
+
+ printf("Exit without closing the stream!\n");
+
+finish:
+ return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
new file mode 100644
index 0000000..7268a30
--- /dev/null
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Play silence and recover from dead servers or disconnected devices.
+
+#include <stdio.h>
+
+#include <aaudio/AAudio.h>
+
+
+#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
+
+static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+ const char *modeText = "unknown";
+ switch (mode) {
+ case AAUDIO_SHARING_MODE_EXCLUSIVE:
+ modeText = "EXCLUSIVE";
+ break;
+ case AAUDIO_SHARING_MODE_SHARED:
+ modeText = "SHARED";
+ break;
+ default:
+ break;
+ }
+ return modeText;
+}
+
+int main(int argc, char **argv) {
+ (void) argc;
+ (void *)argv;
+
+ aaudio_result_t result = AAUDIO_OK;
+
+ int32_t triesLeft = 3;
+ int32_t bufferCapacity;
+ int32_t framesPerBurst = 0;
+ float *buffer = nullptr;
+
+ int32_t actualChannelCount = 0;
+ int32_t actualSampleRate = 0;
+ aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
+ aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
+
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ AAudioStream *aaudioStream = nullptr;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ printf("TestRecovery:\n");
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ result = AAudio_createStreamBuilder(&aaudioBuilder);
+ if (result != AAUDIO_OK) {
+ printf("AAudio_createStreamBuilder returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ // Request stream properties.
+ AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
+
+ while (triesLeft-- > 0) {
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStreamBuilder_openStream returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ // Check to see what kind of stream we actually got.
+ actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
+ actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
+ actualDataFormat = AAudioStream_getFormat(aaudioStream);
+
+ printf("-------- chans = %3d, rate = %6d format = %d\n",
+ actualChannelCount, actualSampleRate, actualDataFormat);
+
+ // This is the number of frames that are read in one chunk by a DMA controller
+ // or a DSP or a mixer.
+ framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
+ bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
+ printf(" bufferCapacity = %d, framesPerBurst = %d\n",
+ bufferCapacity, framesPerBurst);
+
+ int samplesPerBurst = framesPerBurst * actualChannelCount;
+ buffer = new float[samplesPerBurst];
+
+ result = AAudioStream_requestStart(aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStart returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ // Play silence for awhile.
+ int32_t framesMax = actualSampleRate * 20;
+ int64_t framesTotal = 0;
+ int64_t printAt = actualSampleRate;
+ while (result == AAUDIO_OK && framesTotal < framesMax) {
+ int32_t framesWritten = AAudioStream_write(aaudioStream,
+ buffer, framesPerBurst,
+ DEFAULT_TIMEOUT_NANOS);
+ if (framesWritten < 0) {
+ result = framesWritten;
+ printf("write() returned %s, frames = %d\n",
+ AAudio_convertResultToText(result), (int)framesTotal);
+ printf(" frames = %d\n", (int)framesTotal);
+ } else if (framesWritten != framesPerBurst) {
+ printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal);
+ result = AAUDIO_ERROR_TIMEOUT;
+ } else {
+ framesTotal += framesWritten;
+ if (framesTotal >= printAt) {
+ printf("frames = %d\n", (int)framesTotal);
+ printAt += actualSampleRate;
+ }
+ }
+ }
+ result = AAudioStream_requestStop(aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStop returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ result = AAudioStream_close(aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_close returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ aaudioStream = nullptr;
+ }
+
+finish:
+ if (aaudioStream != nullptr) {
+ AAudioStream_close(aaudioStream);
+ }
+ AAudioStreamBuilder_delete(aaudioBuilder);
+ delete[] buffer;
+ printf(" result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
new file mode 100644
index 0000000..da7b80f
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <binder/IPCThreadState.h>
+#include <map>
+#include <mutex>
+#include <utils/Singleton.h>
+
+#include "utility/AAudioUtilities.h"
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
+#include "AAudioClientTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker);
+
+AAudioClientTracker::AAudioClientTracker()
+ : Singleton<AAudioClientTracker>() {
+}
+
+// Create a tracker for the client.
+aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
+ const sp<IAAudioClient>& client) {
+ ALOGD("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
+ pid, getpid());
+
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mNotificationClients.count(pid) == 0) {
+ sp<NotificationClient> notificationClient = new NotificationClient(pid);
+ mNotificationClients[pid] = notificationClient;
+
+ sp<IBinder> binder = IInterface::asBinder(client);
+ status_t status = binder->linkToDeath(notificationClient);
+ ALOGW_IF(status != NO_ERROR,
+ "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+ return AAudioConvert_androidToAAudioResult(status);
+ } else {
+ ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+ return AAUDIO_OK; // TODO should this be considered an error
+ }
+}
+
+void AAudioClientTracker::unregisterClient(pid_t pid) {
+ ALOGD("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
+ pid, getpid());
+ std::lock_guard<std::mutex> lock(mLock);
+ mNotificationClients.erase(pid);
+}
+
+aaudio_result_t
+AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
+ aaudio_result_t result = AAUDIO_OK;
+ ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+ std::lock_guard<std::mutex> lock(mLock);
+ sp<NotificationClient> notificationClient = mNotificationClients[pid];
+ if (notificationClient == 0) {
+ // This will get called the first time the audio server registers an internal stream.
+ ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+ notificationClient = new NotificationClient(pid);
+ mNotificationClients[pid] = notificationClient;
+ }
+ notificationClient->registerClientStream(serviceStream);
+ return result;
+}
+
+// Find the tracker for this process and remove it.
+aaudio_result_t
+AAudioClientTracker::unregisterClientStream(pid_t pid,
+ sp<AAudioServiceStreamBase> serviceStream) {
+ ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+ std::lock_guard<std::mutex> lock(mLock);
+ std::map<pid_t, android::sp<NotificationClient>>::iterator it;
+ it = mNotificationClients.find(pid);
+ if (it != mNotificationClients.end()) {
+ it->second->unregisterClientStream(serviceStream);
+ }
+ return AAUDIO_OK;
+}
+
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
+ : mProcessId(pid) {
+ //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+}
+
+AAudioClientTracker::NotificationClient::~NotificationClient() {
+ //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
+ sp<AAudioServiceStreamBase> serviceStream) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mStreams.insert(serviceStream);
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
+ sp<AAudioServiceStreamBase> serviceStream) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mStreams.erase(serviceStream);
+ return AAUDIO_OK;
+}
+
+// Close any open streams for the client.
+void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) {
+ AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
+ if (aaudioService != nullptr) {
+ // Copy the current list of streams to another vector because closing them below
+ // will cause unregisterClientStream() calls back to this object.
+ std::set<android::sp<AAudioServiceStreamBase>> streamsToClose;
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ ALOGV("AAudioClientTracker::binderDied() pid = %d, # streams = %d\n",
+ mProcessId, (int) mStreams.size());
+ for (auto serviceStream : mStreams) {
+ streamsToClose.insert(serviceStream);
+ }
+ }
+
+ for (auto serviceStream : streamsToClose) {
+ aaudio_handle_t handle = serviceStream->getHandle();
+ ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+ aaudioService->closeStream(handle);
+ }
+ // mStreams should be empty now
+ }
+ sp<NotificationClient> keep(this);
+ AAudioClientTracker::getInstance().unregisterClient(mProcessId);
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
new file mode 100644
index 0000000..447665b
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+#define ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+
+#include <map>
+#include <mutex>
+#include <set>
+
+#include <utils/Singleton.h>
+
+#include <aaudio/AAudio.h>
+#include "binding/IAAudioClient.h"
+#include "AAudioService.h"
+
+namespace aaudio {
+
+class AAudioClientTracker : public android::Singleton<AAudioClientTracker>{
+public:
+ AAudioClientTracker();
+ ~AAudioClientTracker() = default;
+
+ aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
+
+ void unregisterClient(pid_t pid);
+
+ aaudio_result_t registerClientStream(pid_t pid,
+ android::sp<AAudioServiceStreamBase> serviceStream);
+
+ aaudio_result_t unregisterClientStream(pid_t pid,
+ android::sp<AAudioServiceStreamBase> serviceStream);
+
+ android::AAudioService *getAAudioService() const {
+ return mAAudioService;
+ }
+
+ void setAAudioService(android::AAudioService *aaudioService) {
+ mAAudioService = aaudioService;
+ }
+
+private:
+ class NotificationClient : public IBinder::DeathRecipient {
+ public:
+ NotificationClient(pid_t pid);
+ virtual ~NotificationClient();
+
+ aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+ aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const android::wp<IBinder>& who);
+
+ protected:
+ std::mutex mLock;
+ const pid_t mProcessId;
+ std::set<android::sp<AAudioServiceStreamBase>> mStreams;
+ };
+
+ std::mutex mLock;
+ std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
+ android::AAudioService *mAAudioService = nullptr;
+};
+
+} /* namespace aaudio */
+
+#endif //ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 5f6d599..94577a6 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -69,6 +69,8 @@
AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId,
aaudio_direction_t direction) {
AAudioServiceEndpoint *endpoint = nullptr;
+ AAudioServiceEndpointCapture *capture = nullptr;
+ AAudioServiceEndpointPlay *player = nullptr;
std::lock_guard<std::mutex> lock(mLock);
// Try to find an existing endpoint.
@@ -83,30 +85,41 @@
assert(false); // There are only two possible directions.
break;
}
+ ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
+ endpoint, deviceId, (int)direction);
// If we can't find an existing one then open a new one.
- if (endpoint != nullptr) {
- ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
- endpoint, deviceId, (int)direction);
-
- } else {
- if (direction == AAUDIO_DIRECTION_INPUT) {
- AAudioServiceEndpointCapture *capture = new AAudioServiceEndpointCapture(audioService);
- if (capture->open(deviceId) != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager::openEndpoint(), open input failed");
- delete capture;
- } else {
- mInputs[deviceId] = capture;
+ if (endpoint == nullptr) {
+ switch(direction) {
+ case AAUDIO_DIRECTION_INPUT:
+ capture = new AAudioServiceEndpointCapture(audioService);
endpoint = capture;
- }
- } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
- AAudioServiceEndpointPlay *player = new AAudioServiceEndpointPlay(audioService);
- if (player->open(deviceId) != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager::openEndpoint(), open output failed");
- delete player;
- } else {
- mOutputs[deviceId] = player;
+ break;
+ case AAUDIO_DIRECTION_OUTPUT:
+ player = new AAudioServiceEndpointPlay(audioService);
endpoint = player;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (endpoint != nullptr) {
+ aaudio_result_t result = endpoint->open(deviceId);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
+ delete endpoint;
+ endpoint = nullptr;
+ } else {
+ switch(direction) {
+ case AAUDIO_DIRECTION_INPUT:
+ mInputs[deviceId] = capture;
+ break;
+ case AAUDIO_DIRECTION_OUTPUT:
+ mOutputs[deviceId] = player;
+ break;
+ default:
+ break;
}
}
ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
@@ -148,6 +161,8 @@
case AAUDIO_DIRECTION_OUTPUT:
mOutputs.erase(deviceId);
break;
+ default:
+ break;
}
serviceEndpoint->close();
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 443f40d..3718bee 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -27,6 +27,7 @@
#include <utils/String16.h>
#include "binding/AAudioServiceMessage.h"
+#include "AAudioClientTracker.h"
#include "AAudioEndpointManager.h"
#include "AAudioService.h"
#include "AAudioServiceStreamMMAP.h"
@@ -49,6 +50,7 @@
: BnAAudioService() {
mCachedProcessId = getpid();
mCachedUserId = getuid(); // TODO consider using geteuid()
+ AAudioClientTracker::getInstance().setAAudioService(this);
}
AAudioService::~AAudioService() {
@@ -71,10 +73,15 @@
return NO_ERROR;
}
+void AAudioService::registerClient(const sp<IAAudioClient>& client) {
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ AAudioClientTracker::getInstance().registerClient(pid, client);
+}
+
aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
aaudio_result_t result = AAUDIO_OK;
- AAudioServiceStreamBase *serviceStream = nullptr;
+ sp<AAudioServiceStreamBase> serviceStream;
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
@@ -89,9 +96,8 @@
result = serviceStream->open(request, configurationOutput);
if (result != AAUDIO_OK) {
// fall back to using a shared stream
- ALOGD("AAudioService::openStream(), EXCLUSIVE mode failed");
- delete serviceStream;
- serviceStream = nullptr;
+ ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+ serviceStream.clear();
} else {
configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
}
@@ -106,17 +112,22 @@
}
if (result != AAUDIO_OK) {
- delete serviceStream;
- ALOGE("AAudioService::openStream(): failed, return %d", result);
+ serviceStream.clear();
+ ALOGE("AAudioService::openStream(): failed, return %d = %s",
+ result, AAudio_convertResultToText(result));
return result;
} else {
const uid_t ownerUserId = request.getUserId(); // only set by service, not by client
serviceStream->setOwnerUserId(ownerUserId);
- aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
- ALOGD("AAudioService::openStream(): handle = 0x%08X owned by %d", handle, ownerUserId);
+ aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
if (handle < 0) {
ALOGE("AAudioService::openStream(): handle table full");
- delete serviceStream;
+ serviceStream.clear();
+ } else {
+ ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+ serviceStream->setHandle(handle);
+ pid_t pid = request.getProcessId();
+ AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
}
return handle;
}
@@ -126,10 +137,11 @@
AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
streamHandle);
- ALOGV("AAudioService.closeStream(0x%08X)", streamHandle);
+ ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
if (serviceStream != nullptr) {
serviceStream->close();
- delete serviceStream;
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
return AAUDIO_OK;
}
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -209,8 +221,8 @@
}
aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
- pid_t clientThreadId,
- int64_t periodNanoseconds) {
+ pid_t clientThreadId,
+ int64_t periodNanoseconds) {
AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream == nullptr) {
ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 9b6b342..f84ac4c 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -46,8 +46,10 @@
virtual status_t dump(int fd, const Vector<String16>& args) override;
+ virtual void registerClient(const sp<IAAudioClient>& client);
+
virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configuration);
+ aaudio::AAudioStreamConfiguration &configurationOutput);
virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index cc2cb44..3815711 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -65,20 +65,20 @@
}
// TODO, maybe use an interface to reduce exposure
-aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
std::lock_guard<std::mutex> lock(mLockStreams);
mRegisteredStreams.push_back(sharedStream);
return AAUDIO_OK;
}
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
std::lock_guard<std::mutex> lock(mLockStreams);
mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
mRegisteredStreams.end());
return AAUDIO_OK;
}
-aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
// TODO use real-time technique to avoid mutex, eg. atomic command FIFO
std::lock_guard<std::mutex> lock(mLockStreams);
mRunningStreams.push_back(sharedStream);
@@ -88,7 +88,7 @@
return AAUDIO_OK;
}
-aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
int numRunningStreams = 0;
{
std::lock_guard<std::mutex> lock(mLockStreams);
@@ -130,11 +130,11 @@
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
- for(AAudioServiceStreamShared *sharedStream : mRunningStreams) {
- sharedStream->onStop();
+ for(auto baseStream : mRunningStreams) {
+ baseStream->onStop();
}
mRunningStreams.clear();
- for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) {
+ for(auto sharedStream : mRegisteredStreams) {
sharedStream->onDisconnect();
}
mRegisteredStreams.clear();
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index c271dbd..090b1dd 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -42,10 +42,10 @@
int32_t getSamplesPerFrame() const { return mStreamInternal->getSamplesPerFrame(); }
int32_t getFramesPerBurst() const { return mStreamInternal->getFramesPerBurst(); }
- aaudio_result_t registerStream(AAudioServiceStreamShared *sharedStream);
- aaudio_result_t unregisterStream(AAudioServiceStreamShared *sharedStream);
- aaudio_result_t startStream(AAudioServiceStreamShared *sharedStream);
- aaudio_result_t stopStream(AAudioServiceStreamShared *sharedStream);
+ aaudio_result_t registerStream(android::sp<AAudioServiceStreamShared> sharedStream);
+ aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamShared> sharedStream);
+ aaudio_result_t startStream(android::sp<AAudioServiceStreamShared> sharedStream);
+ aaudio_result_t stopStream(android::sp<AAudioServiceStreamShared> sharedStream);
aaudio_result_t close();
int32_t getRequestedDeviceId() const { return mRequestedDeviceId; }
@@ -73,8 +73,9 @@
std::mutex mLockStreams;
- std::vector<AAudioServiceStreamShared *> mRegisteredStreams;
- std::vector<AAudioServiceStreamShared *> mRunningStreams;
+ std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
+
+ std::vector<android::sp<AAudioServiceStreamShared>> mRunningStreams;
private:
aaudio_result_t startSharingThread_l();
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 29d6cb9..2bb79bf 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -78,7 +78,7 @@
// Distribute data to each active stream.
{ // use lock guard
std::lock_guard <std::mutex> lock(mLockStreams);
- for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
+ for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
getFramesPerBurst()) {
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index cc09cc3..bbe4788 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -79,7 +79,7 @@
mMixer.clear();
{ // use lock guard
std::lock_guard <std::mutex> lock(mLockStreams);
- for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
+ for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
float volume = 0.5; // TODO get from system
bool underflowed = mMixer.mix(fifo, volume);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index ee0e7ed..c415f25 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,6 +42,7 @@
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
close();
+ ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroyed %p", this);
}
aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
@@ -56,6 +57,7 @@
}
aaudio_result_t AAudioServiceStreamBase::close() {
+ stop();
std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
delete mUpMessageQueue;
mUpMessageQueue = nullptr;
@@ -71,28 +73,34 @@
}
aaudio_result_t AAudioServiceStreamBase::pause() {
- sendCurrentTimestamp();
- mThreadEnabled.store(false);
- aaudio_result_t result = mAAudioThread.stop();
- if (result != AAUDIO_OK) {
- processFatalError();
- return result;
+ aaudio_result_t result = AAUDIO_OK;
+ if (isRunning()) {
+ sendCurrentTimestamp();
+ mThreadEnabled.store(false);
+ result = mAAudioThread.stop();
+ if (result != AAUDIO_OK) {
+ processFatalError();
+ return result;
+ }
+ sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
}
- sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
mState = AAUDIO_STREAM_STATE_PAUSED;
return result;
}
aaudio_result_t AAudioServiceStreamBase::stop() {
- // TODO wait for data to be played out
- sendCurrentTimestamp();
- mThreadEnabled.store(false);
- aaudio_result_t result = mAAudioThread.stop();
- if (result != AAUDIO_OK) {
- processFatalError();
- return result;
+ aaudio_result_t result = AAUDIO_OK;
+ if (isRunning()) {
+ // TODO wait for data to be played out
+ sendCurrentTimestamp();
+ mThreadEnabled.store(false);
+ result = mAAudioThread.stop();
+ if (result != AAUDIO_OK) {
+ processFatalError();
+ return result;
+ }
+ sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
}
- sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
mState = AAUDIO_STREAM_STATE_STOPPED;
return result;
}
@@ -178,4 +186,4 @@
mUpMessageQueue->fillParcelable(parcelable,
parcelable.mUpMessageQueueParcelable);
return getDownDataDescription(parcelable);
-}
\ No newline at end of file
+}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index da0b537..d83d5ab 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -20,6 +20,8 @@
#include <assert.h>
#include <mutex>
+#include <utils/RefBase.h>
+
#include "fifo/FifoBuffer.h"
#include "binding/IAAudioService.h"
#include "binding/AudioEndpointParcelable.h"
@@ -39,7 +41,8 @@
* Base class for a stream in the AAudio service.
*/
class AAudioServiceStreamBase
- : public Runnable {
+ : public virtual android::RefBase
+ , public Runnable {
public:
AAudioServiceStreamBase();
@@ -78,6 +81,9 @@
*/
virtual aaudio_result_t flush();
+ bool isRunning() const {
+ return mState == AAUDIO_STREAM_STATE_STARTED;
+ }
// -------------------------------------------------------------------
/**
@@ -120,6 +126,13 @@
mOwnerUserId = uid;
}
+ aaudio_handle_t getHandle() const {
+ return mHandle;
+ }
+ void setHandle(aaudio_handle_t handle) {
+ mHandle = handle;
+ }
+
protected:
aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
@@ -146,6 +159,8 @@
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED;
uid_t mOwnerUserId = -1;
+private:
+ aaudio_handle_t mHandle = -1;
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 2f3ec27..4083bcc 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -38,7 +38,7 @@
#define AAUDIO_SAMPLE_RATE_DEFAULT 48000
/**
- * Stream that uses an MMAP buffer.
+ * Service Stream that uses an MMAP buffer.
*/
AAudioServiceStreamMMAP::AAudioServiceStreamMMAP()
@@ -244,7 +244,6 @@
return AAudioServiceStreamBase::flush();;
}
-
aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
int64_t *timeNanos) {
struct audio_mmap_position position;
@@ -266,7 +265,7 @@
}
void AAudioServiceStreamMMAP::onTearDown() {
- ALOGE("AAudioServiceStreamMMAP::onTearDown() called - TODO");
+ ALOGD("AAudioServiceStreamMMAP::onTearDown() called"); // TODO what is needed here?
};
void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels,
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index f246fc02..7515ea7 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -52,7 +52,7 @@
int32_t framesPerBurst) {
if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
- ALOGE("AAudioServiceStreamShared::open(), requested capacity %d > max %d",
+ ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -77,7 +77,7 @@
}
// Check for numeric overflow.
if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
- ALOGE("AAudioServiceStreamShared::open(), numeric overflow, capacity = %d * %d",
+ ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
numBursts, framesPerBurst);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -85,11 +85,11 @@
// Final sanity check.
if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
- ALOGE("AAudioServiceStreamShared::open(), calculated capacity %d > max %d",
+ ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
capacityInFrames, MAX_FRAMES_PER_BUFFER);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- ALOGD("AAudioServiceStreamShared::open(), requested capacity = %d frames, actual = %d",
+ ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
requestedCapacityFrames, capacityInFrames);
return capacityInFrames;
}
@@ -97,6 +97,8 @@
aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
+ sp<AAudioServiceStreamShared> keep(this);
+
aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamBase open() returned %d", result);
@@ -110,7 +112,7 @@
AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction);
if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint);
+ ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint);
return AAUDIO_ERROR_UNAVAILABLE;
}
@@ -119,7 +121,7 @@
if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) {
mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
} else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
- ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat);
+ ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", mAudioFormat);
result = AAUDIO_ERROR_INVALID_FORMAT;
goto error;
}
@@ -128,7 +130,7 @@
if (mSampleRate == AAUDIO_UNSPECIFIED) {
mSampleRate = mServiceEndpoint->getSampleRate();
} else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
- ALOGE("AAudioServiceStreamShared::open(), mSampleRate = %d, need %d",
+ ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
mSampleRate, mServiceEndpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
@@ -138,14 +140,14 @@
if (mSamplesPerFrame == AAUDIO_UNSPECIFIED) {
mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame();
} else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
- ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d",
+ ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
- ALOGD("AAudioServiceStreamShared::open(), mSampleRate = %d, mFramesPerBurst = %d",
+ ALOGD("AAudioServiceStreamShared::open() mSampleRate = %d, mFramesPerBurst = %d",
mSampleRate, mFramesPerBurst);
mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(),
@@ -160,7 +162,7 @@
mAudioDataQueue = new SharedRingBuffer();
result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::open(), could not allocate FIFO with %d frames",
+ ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
mCapacityInFrames);
result = AAUDIO_ERROR_NO_MEMORY;
goto error;
@@ -175,7 +177,7 @@
configurationOutput.setAudioFormat(mAudioFormat);
configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
- result = mServiceEndpoint->registerStream(this);
+ result = mServiceEndpoint->registerStream(keep);
if (result != AAUDIO_OK) {
goto error;
}
@@ -263,7 +265,8 @@
// TODO wait for pause() to synchronize
AAudioServiceEndpoint *endpoint = mServiceEndpoint;
if (endpoint != nullptr) {
- endpoint->unregisterStream(this);
+ sp<AAudioServiceStreamShared> keep(this);
+ endpoint->unregisterStream(keep);
AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
mEndpointManager.closeEndpoint(endpoint);
@@ -292,8 +295,7 @@
}
void AAudioServiceStreamShared::onDisconnect() {
- mServiceEndpoint->close();
- mServiceEndpoint = nullptr;
+ processFatalError();
}
void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 12f7e04..a896a7a 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -25,6 +25,7 @@
$(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
SharedMemoryProxy.cpp \
SharedRingBuffer.cpp \
+ AAudioClientTracker.cpp \
AAudioEndpointManager.cpp \
AAudioMixer.cpp \
AAudioService.cpp \