AAudioService: integrated with audioserver
Call the MmapStreamInterface from AudioFlinger instead of the FakeHAL.
Fix sending timestamps from the thread.
Add shared mode in service.
Bug: 35260844
Bug: 33398120
Test: CTS test_aaudio.cpp
Change-Id: I44c7e4ecae4ce205611b6b73a72e0ae8a5b243e5
Signed-off-by: Phil Burk <philburk@google.com>
(cherry picked from commit 7f6b40d78b1976c78d1300e8a51fda36eeb50c5d)
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 1ee73bf..b5bb75f 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -26,6 +26,7 @@
$(LOCAL_PATH)/legacy \
$(LOCAL_PATH)/utility
+# If you add a file here then also add it below in the SHARED target
LOCAL_SRC_FILES = \
core/AudioStream.cpp \
core/AudioStreamBuilder.cpp \
@@ -43,13 +44,14 @@
client/AudioEndpoint.cpp \
client/AudioStreamInternal.cpp \
client/IsochronousClockModel.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp \
- binding/RingBufferParcelable.cpp \
binding/AudioEndpointParcelable.cpp \
+ binding/AAudioBinderClient.cpp \
binding/AAudioStreamRequest.cpp \
binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioService.cpp
+ binding/IAAudioService.cpp \
+ binding/RingBufferParcelable.cpp \
+ binding/SharedMemoryParcelable.cpp \
+ binding/SharedRegionParcelable.cpp
LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
@@ -96,13 +98,14 @@
client/AudioEndpoint.cpp \
client/AudioStreamInternal.cpp \
client/IsochronousClockModel.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp \
- binding/RingBufferParcelable.cpp \
binding/AudioEndpointParcelable.cpp \
+ binding/AAudioBinderClient.cpp \
binding/AAudioStreamRequest.cpp \
binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioService.cpp
+ binding/IAAudioService.cpp \
+ binding/RingBufferParcelable.cpp \
+ binding/SharedMemoryParcelable.cpp \
+ binding/SharedRegionParcelable.cpp
LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
new file mode 100644
index 0000000..8315c40
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 <binder/IServiceManager.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.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 "AAudioBinderClient.h"
+#include "AAudioServiceInterface.h"
+
+using android::String16;
+using android::IServiceManager;
+using android::defaultServiceManager;
+using android::interface_cast;
+using android::IAAudioService;
+using android::Mutex;
+using android::sp;
+
+using namespace aaudio;
+
+static android::Mutex gServiceLock;
+static sp<IAAudioService> gAAudioService;
+
+// 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.
+ if (binder != 0) {
+ break;
+ }
+ } 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);
+ }
+ }
+ return gAAudioService;
+}
+
+
+AAudioBinderClient::AAudioBinderClient()
+ : AAudioServiceInterface() {}
+
+AAudioBinderClient::~AAudioBinderClient() {}
+
+/**
+* @param request info needed to create the stream
+* @param configuration contains information about the created stream
+* @return handle to the stream or a negative error
+*/
+aaudio_handle_t AAudioBinderClient::openStream(const AAudioStreamRequest &request,
+ AAudioStreamConfiguration &configurationOutput) {
+
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->openStream(request, configurationOutput);
+}
+
+aaudio_result_t AAudioBinderClient::closeStream(aaudio_handle_t streamHandle) {
+
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->closeStream(streamHandle);
+}
+
+/* Get an immutable description of the in-memory queues
+* used to communicate with the underlying HAL or Service.
+*/
+aaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) {
+
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->getStreamDescription(streamHandle, parcelable);
+}
+
+/**
+* Start the flow of data.
+*/
+aaudio_result_t AAudioBinderClient::startStream(aaudio_handle_t streamHandle) {
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->startStream(streamHandle);
+}
+
+/**
+* Stop the flow of data such that start() can resume without loss of data.
+*/
+aaudio_result_t AAudioBinderClient::pauseStream(aaudio_handle_t streamHandle) {
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->startStream(streamHandle);
+}
+
+/**
+* Discard any data held by the underlying HAL or Service.
+*/
+aaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) {
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->startStream(streamHandle);
+}
+
+/**
+* Manage the specified thread as a low latency audio thread.
+*/
+aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId,
+ int64_t periodNanoseconds) {
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->registerAudioThread(streamHandle,
+ clientProcessId,
+ clientThreadId,
+ periodNanoseconds);
+}
+
+aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId) {
+ const sp<IAAudioService> &service = getAAudioService();
+ if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ return service->unregisterAudioThread(streamHandle,
+ clientProcessId,
+ clientThreadId);
+}
+
+
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
new file mode 100644
index 0000000..5613d5b
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -0,0 +1,92 @@
+/*
+ * 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 AAUDIO_AAUDIO_BINDER_CLIENT_H
+#define AAUDIO_AAUDIO_BINDER_CLIENT_H
+
+#include <aaudio/AAudioDefinitions.h>
+#include "AAudioServiceDefinitions.h"
+#include "AAudioServiceInterface.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AudioEndpointParcelable.h"
+
+/**
+ * Implements the AAudioServiceInterface by talking to the actual service through Binder.
+ */
+
+namespace aaudio {
+
+class AAudioBinderClient : public AAudioServiceInterface {
+
+public:
+
+ AAudioBinderClient();
+
+ virtual ~AAudioBinderClient();
+
+ /**
+ * @param request info needed to create the stream
+ * @param configuration contains resulting information about the created stream
+ * @return handle to the stream or a negative error
+ */
+ aaudio_handle_t openStream(const AAudioStreamRequest &request,
+ AAudioStreamConfiguration &configurationOutput) override;
+
+ aaudio_result_t closeStream(aaudio_handle_t streamHandle) override;
+
+ /* Get an immutable description of the in-memory queues
+ * used to communicate with the underlying HAL or Service.
+ */
+ aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) override;
+
+ /**
+ * Start the flow of data.
+ * This is asynchronous. When complete, the service will send a STARTED event.
+ */
+ aaudio_result_t startStream(aaudio_handle_t streamHandle) override;
+
+ /**
+ * Stop the flow of data such that start() can resume without loss of data.
+ * This is asynchronous. When complete, the service will send a PAUSED event.
+ */
+ aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override;
+
+ /**
+ * Discard any data held by the underlying HAL or Service.
+ * This is asynchronous. When complete, the service will send a FLUSHED event.
+ */
+ aaudio_result_t flushStream(aaudio_handle_t streamHandle) override;
+
+ /**
+ * Manage the specified thread as a low latency audio thread.
+ * TODO Consider passing this information as part of the startStream() call.
+ */
+ aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId,
+ int64_t periodNanoseconds) override;
+
+ aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId) override;
+};
+
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_AAUDIO_BINDER_CLIENT_H
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index b58d170..0d5bae5 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -48,25 +48,6 @@
#define AAUDIO_HANDLE_INVALID ((aaudio_handle_t) -1)
-enum aaudio_commands_t {
- OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
- CLOSE_STREAM,
- GET_STREAM_DESCRIPTION,
- START_STREAM,
- PAUSE_STREAM,
- FLUSH_STREAM,
- REGISTER_AUDIO_THREAD,
- UNREGISTER_AUDIO_THREAD
-};
-
-// TODO Expand this to include all the open parameters.
-typedef struct AAudioServiceStreamInfo_s {
- int32_t deviceId;
- int32_t samplesPerFrame; // number of channels
- int32_t sampleRate;
- aaudio_audio_format_t audioFormat;
-} AAudioServiceStreamInfo;
-
// This must be a fixed width so it can be in shared memory.
enum RingbufferFlags : uint32_t {
NONE = 0,
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
new file mode 100644
index 0000000..62fd894
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -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.
+ */
+
+#ifndef AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#define AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AudioEndpointParcelable.h"
+
+/**
+ * This has the same methods as IAAudioService but without the Binder features.
+ *
+ * It allows us to abstract the Binder interface and use an AudioStreamInternal
+ * both in the client and in the service.
+ */
+namespace aaudio {
+
+class AAudioServiceInterface {
+public:
+
+ AAudioServiceInterface() {};
+ virtual ~AAudioServiceInterface() = default;
+
+ /**
+ * @param request info needed to create the stream
+ * @param configuration contains information about the created stream
+ * @return handle to the stream or a negative error
+ */
+ virtual aaudio_handle_t openStream(const AAudioStreamRequest &request,
+ AAudioStreamConfiguration &configuration) = 0;
+
+ virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle) = 0;
+
+ /* Get an immutable description of the in-memory queues
+ * used to communicate with the underlying HAL or Service.
+ */
+ virtual aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) = 0;
+
+ /**
+ * Start the flow of data.
+ */
+ virtual aaudio_result_t startStream(aaudio_handle_t streamHandle) = 0;
+
+ /**
+ * Stop the flow of data such that start() can resume without loss of data.
+ */
+ virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle) = 0;
+
+ /**
+ * Discard any data held by the underlying HAL or Service.
+ */
+ virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) = 0;
+
+ /**
+ * Manage the specified thread as a low latency audio thread.
+ */
+ virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId,
+ int64_t periodNanoseconds) = 0;
+
+ virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId) = 0;
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index cc77d59..b74b6c2 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -25,10 +25,11 @@
// TODO move this to an "include" folder for the service.
+// Used to send information about the HAL to the client.
struct AAudioMessageTimestamp {
- int64_t position;
- int64_t deviceOffset; // add to client position to get device position
- int64_t timestamp;
+ int64_t position; // number of frames transferred so far
+ int64_t deviceOffset; // add to client position to get device position
+ int64_t timestamp; // time when that position was reached
};
typedef enum aaudio_service_event_e : uint32_t {
@@ -36,13 +37,14 @@
AAUDIO_SERVICE_EVENT_PAUSED,
AAUDIO_SERVICE_EVENT_FLUSHED,
AAUDIO_SERVICE_EVENT_CLOSED,
- AAUDIO_SERVICE_EVENT_DISCONNECTED
+ AAUDIO_SERVICE_EVENT_DISCONNECTED,
+ AAUDIO_SERVICE_EVENT_VOLUME
} aaudio_service_event_t;
struct AAudioMessageEvent {
aaudio_service_event_t event;
- int32_t data1;
- int64_t data2;
+ double dataDouble;
+ int64_t dataLong;
};
typedef struct AAudioServiceMessage_s {
@@ -54,12 +56,11 @@
code what;
union {
- AAudioMessageTimestamp timestamp;
- AAudioMessageEvent event;
+ AAudioMessageTimestamp timestamp; // what == TIMESTAMP
+ AAudioMessageEvent event; // what == EVENT
};
} AAudioServiceMessage;
-
} /* namespace aaudio */
#endif //AAUDIO_AAUDIO_SERVICE_MESSAGE_H
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index fe3a59f..ba41a3b 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -35,26 +35,50 @@
AAudioStreamConfiguration::~AAudioStreamConfiguration() {}
status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mDeviceId);
- parcel->writeInt32(mSampleRate);
- parcel->writeInt32(mSamplesPerFrame);
- parcel->writeInt32((int32_t) mAudioFormat);
- parcel->writeInt32(mBufferCapacity);
- return NO_ERROR; // TODO check for errors above
+ status_t status;
+ status = parcel->writeInt32(mDeviceId);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mSampleRate);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mSamplesPerFrame);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) mSharingMode);
+ ALOGD("AAudioStreamConfiguration.writeToParcel(): mSharingMode = %d", mSharingMode);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) mAudioFormat);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mBufferCapacity);
+ if (status != NO_ERROR) goto error;
+ return NO_ERROR;
+error:
+ ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
+ return status;
}
status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
int32_t temp;
- parcel->readInt32(&mDeviceId);
- parcel->readInt32(&mSampleRate);
- parcel->readInt32(&mSamplesPerFrame);
- parcel->readInt32(&temp);
+ status_t status = parcel->readInt32(&mDeviceId);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32(&mSampleRate);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32(&mSamplesPerFrame);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32(&temp);
+ if (status != NO_ERROR) goto error;
+ mSharingMode = (aaudio_sharing_mode_t) temp;
+ ALOGD("AAudioStreamConfiguration.readFromParcel(): mSharingMode = %d", mSharingMode);
+ status = parcel->readInt32(&temp);
+ if (status != NO_ERROR) goto error;
mAudioFormat = (aaudio_audio_format_t) temp;
- parcel->readInt32(&mBufferCapacity);
- return NO_ERROR; // TODO check for errors above
+ status = parcel->readInt32(&mBufferCapacity);
+ if (status != NO_ERROR) goto error;
+ return NO_ERROR;
+error:
+ ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
+ return status;
}
-aaudio_result_t AAudioStreamConfiguration::validate() {
+aaudio_result_t AAudioStreamConfiguration::validate() const {
// Validate results of the open.
if (mSampleRate < 0 || mSampleRate >= 8 * 48000) { // TODO review limits
ALOGE("AAudioStreamConfiguration.validate(): invalid sampleRate = %d", mSampleRate);
@@ -84,9 +108,11 @@
return AAUDIO_OK;
}
-void AAudioStreamConfiguration::dump() {
- ALOGD("AAudioStreamConfiguration mSampleRate = %d -----", mSampleRate);
+void AAudioStreamConfiguration::dump() const {
+ ALOGD("AAudioStreamConfiguration mDeviceId = %d", mDeviceId);
+ ALOGD("AAudioStreamConfiguration mSampleRate = %d", mSampleRate);
ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame);
+ ALOGD("AAudioStreamConfiguration mSharingMode = %d", (int)mSharingMode);
ALOGD("AAudioStreamConfiguration mAudioFormat = %d", (int)mAudioFormat);
ALOGD("AAudioStreamConfiguration mBufferCapacity = %d", mBufferCapacity);
}
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
index 57b1c59..b68d8b2 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -66,6 +66,14 @@
mAudioFormat = audioFormat;
}
+ aaudio_sharing_mode_t getSharingMode() const {
+ return mSharingMode;
+ }
+
+ void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+ mSharingMode = sharingMode;
+ }
+
int32_t getBufferCapacity() const {
return mBufferCapacity;
}
@@ -78,14 +86,15 @@
virtual status_t readFromParcel(const Parcel* parcel) override;
- aaudio_result_t validate();
+ aaudio_result_t validate() const;
- void dump();
+ void dump() const;
-protected:
+private:
int32_t mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+ aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
aaudio_audio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
};
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 5202b73..b8a0429 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <stdint.h>
#include <sys/mman.h>
@@ -39,28 +43,48 @@
AAudioStreamRequest::~AAudioStreamRequest() {}
status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32((int32_t) mUserId);
- parcel->writeInt32((int32_t) mProcessId);
- mConfiguration.writeToParcel(parcel);
- return NO_ERROR; // TODO check for errors above
+ status_t status = parcel->writeInt32((int32_t) mUserId);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) mProcessId);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) mDirection);
+ if (status != NO_ERROR) goto error;
+ status = mConfiguration.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ return NO_ERROR;
+
+error:
+ ALOGE("AAudioStreamRequest.writeToParcel(): write failed = %d", status);
+ return status;
}
status_t AAudioStreamRequest::readFromParcel(const Parcel* parcel) {
int32_t temp;
- parcel->readInt32(&temp);
+ status_t status = parcel->readInt32(&temp);
+ if (status != NO_ERROR) goto error;
mUserId = (uid_t) temp;
- parcel->readInt32(&temp);
+ status = parcel->readInt32(&temp);
+ if (status != NO_ERROR) goto error;
mProcessId = (pid_t) temp;
- mConfiguration.readFromParcel(parcel);
- return NO_ERROR; // TODO check for errors above
+ status = parcel->readInt32(&temp);
+ if (status != NO_ERROR) goto error;
+ mDirection = (aaudio_direction_t) temp;
+ status = mConfiguration.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ return NO_ERROR;
+
+error:
+ ALOGE("AAudioStreamRequest.readFromParcel(): read failed = %d", status);
+ return status;
}
-aaudio_result_t AAudioStreamRequest::validate() {
+aaudio_result_t AAudioStreamRequest::validate() const {
return mConfiguration.validate();
}
-void AAudioStreamRequest::dump() {
- ALOGD("AAudioStreamRequest mUserId = %d -----", mUserId);
+void AAudioStreamRequest::dump() const {
+ ALOGD("AAudioStreamRequest mUserId = %d", mUserId);
ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
+ ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
mConfiguration.dump();
}
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 0fd28ba..6546562 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -52,6 +52,18 @@
mProcessId = processId;
}
+ aaudio_direction_t getDirection() const {
+ return mDirection;
+ }
+
+ void setDirection(aaudio_direction_t direction) {
+ mDirection = direction;
+ }
+
+ const AAudioStreamConfiguration &getConstantConfiguration() const {
+ return mConfiguration;
+ }
+
AAudioStreamConfiguration &getConfiguration() {
return mConfiguration;
}
@@ -60,14 +72,15 @@
virtual status_t readFromParcel(const Parcel* parcel) override;
- aaudio_result_t validate();
+ aaudio_result_t validate() const;
- void dump();
+ void dump() const;
protected:
AAudioStreamConfiguration mConfiguration;
- uid_t mUserId;
- pid_t mProcessId;
+ uid_t mUserId;
+ pid_t mProcessId;
+ aaudio_direction_t mDirection;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index f40ee02..ee92ee3 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -14,11 +14,15 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <stdint.h>
-#include <sys/mman.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
+#include <utility/AAudioUtilities.h>
#include "binding/AAudioServiceDefinitions.h"
#include "binding/RingBufferParcelable.h"
@@ -82,13 +86,27 @@
}
aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
- // TODO error check
- mUpMessageQueueParcelable.resolve(mSharedMemories, &descriptor->upMessageQueueDescriptor);
- mDownMessageQueueParcelable.resolve(mSharedMemories,
+ aaudio_result_t result = mUpMessageQueueParcelable.resolve(mSharedMemories,
+ &descriptor->upMessageQueueDescriptor);
+ if (result != AAUDIO_OK) return result;
+ result = mDownMessageQueueParcelable.resolve(mSharedMemories,
&descriptor->downMessageQueueDescriptor);
- mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
- mDownDataQueueParcelable.resolve(mSharedMemories, &descriptor->downDataQueueDescriptor);
- return AAUDIO_OK;
+ if (result != AAUDIO_OK) return result;
+
+ result = mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
+ if (result != AAUDIO_OK) return result;
+ result = mDownDataQueueParcelable.resolve(mSharedMemories,
+ &descriptor->downDataQueueDescriptor);
+ return result;
+}
+
+aaudio_result_t AudioEndpointParcelable::close() {
+ int err = 0;
+ for (int i = 0; i < mNumSharedMemories; i++) {
+ int lastErr = mSharedMemories[i].close();
+ if (lastErr < 0) err = lastErr;
+ }
+ return AAudioConvert_androidToAAudioResult(err);
}
aaudio_result_t AudioEndpointParcelable::validate() {
@@ -100,6 +118,7 @@
for (int i = 0; i < mNumSharedMemories; i++) {
result = mSharedMemories[i].validate();
if (result != AAUDIO_OK) {
+ ALOGE("AudioEndpointParcelable invalid mSharedMemories[%d] = %d", i, result);
return result;
}
}
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index d4646d0..4a1cb72 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -57,6 +57,8 @@
aaudio_result_t validate();
+ aaudio_result_t close();
+
void dump();
public: // TODO add getters
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index c21033e..20cbbc8 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -40,11 +40,13 @@
{
}
- virtual aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configuration) override {
+ virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ aaudio::AAudioStreamConfiguration &configurationOutput) override {
Parcel data, reply;
// send command
data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+ ALOGE("BpAAudioService::client openStream request dump --------------------");
+ request.dump();
request.writeToParcel(&data);
status_t err = remote()->transact(OPEN_STREAM, data, &reply);
if (err != NO_ERROR) {
@@ -53,7 +55,12 @@
// parse reply
aaudio_handle_t stream;
reply.readInt32(&stream);
- configuration.readFromParcel(&reply);
+ err = configurationOutput.readFromParcel(&reply);
+ if (err != NO_ERROR) {
+ ALOGE("BpAAudioService::client openStream readFromParcel failed %d", err);
+ closeStream(stream);
+ return AAudioConvert_androidToAAudioResult(err);
+ }
return stream;
}
@@ -80,16 +87,30 @@
data.writeInt32(streamHandle);
status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
if (err != NO_ERROR) {
+ ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) returns %d", err);
return AAudioConvert_androidToAAudioResult(err);
}
// parse reply
- parcelable.readFromParcel(&reply);
- parcelable.dump();
- aaudio_result_t result = parcelable.validate();
- if (result != AAUDIO_OK) {
+ aaudio_result_t result;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) readInt %d", err);
+ return AAudioConvert_androidToAAudioResult(err);
+ } else if (result != AAUDIO_OK) {
+ ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION passed result %d", result);
return result;
}
- reply.readInt32(&result);
+ err = parcelable.readFromParcel(&reply);;
+ if (err != NO_ERROR) {
+ ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) read endpoint %d", err);
+ return AAudioConvert_androidToAAudioResult(err);
+ }
+ //parcelable.dump();
+ result = parcelable.validate();
+ if (result != AAUDIO_OK) {
+ ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION validation fails %d", result);
+ return result;
+ }
return result;
}
@@ -139,13 +160,16 @@
return res;
}
- virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
+ virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId,
int64_t periodNanoseconds)
override {
Parcel data, reply;
// send command
data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
data.writeInt32(streamHandle);
+ data.writeInt32((int32_t) clientProcessId);
data.writeInt32((int32_t) clientThreadId);
data.writeInt64(periodNanoseconds);
status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
@@ -158,12 +182,15 @@
return res;
}
- virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId)
+ virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId)
override {
Parcel data, reply;
// send command
data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
data.writeInt32(streamHandle);
+ data.writeInt32((int32_t) clientProcessId);
data.writeInt32((int32_t) clientThreadId);
status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
if (err != NO_ERROR) {
@@ -178,7 +205,7 @@
};
// Implement an interface to the service.
-// This is here so that you don't have to link with liboboe static library.
+// This is here so that you don't have to link with libaaudio static library.
IMPLEMENT_META_INTERFACE(AAudioService, "IAAudioService");
// The order of parameters in the Parcels must match with code in BpAAudioService
@@ -189,6 +216,7 @@
aaudio::AAudioStreamRequest request;
aaudio::AAudioStreamConfiguration configuration;
pid_t pid;
+ pid_t tid;
int64_t nanoseconds;
aaudio_result_t result;
ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
@@ -197,8 +225,12 @@
switch(code) {
case OPEN_STREAM: {
request.readFromParcel(&data);
+
+ ALOGD("BnAAudioService::client openStream request dump --------------------");
+ request.dump();
+
stream = openStream(request, configuration);
- ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
+ ALOGV("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
reply->writeInt32(stream);
configuration.writeToParcel(reply);
return NO_ERROR;
@@ -206,7 +238,7 @@
case CLOSE_STREAM: {
data.readInt32(&stream);
- ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
+ ALOGV("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
result = closeStream(stream);
reply->writeInt32(result);
return NO_ERROR;
@@ -214,26 +246,28 @@
case GET_STREAM_DESCRIPTION: {
data.readInt32(&stream);
- ALOGD("BnAAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", stream);
+ ALOGI("BnAAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", stream);
aaudio::AudioEndpointParcelable parcelable;
result = getStreamDescription(stream, parcelable);
+ ALOGI("BnAAudioService::onTransact getStreamDescription() returns %d", result);
if (result != AAUDIO_OK) {
return AAudioConvert_aaudioToAndroidStatus(result);
}
- parcelable.dump();
result = parcelable.validate();
if (result != AAUDIO_OK) {
+ ALOGE("BnAAudioService::onTransact getStreamDescription() returns %d", result);
+ parcelable.dump();
return AAudioConvert_aaudioToAndroidStatus(result);
}
- parcelable.writeToParcel(reply);
reply->writeInt32(result);
+ parcelable.writeToParcel(reply);
return NO_ERROR;
} break;
case START_STREAM: {
data.readInt32(&stream);
result = startStream(stream);
- ALOGD("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
+ ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
stream, result);
reply->writeInt32(result);
return NO_ERROR;
@@ -242,7 +276,7 @@
case PAUSE_STREAM: {
data.readInt32(&stream);
result = pauseStream(stream);
- ALOGD("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
+ ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
stream, result);
reply->writeInt32(result);
return NO_ERROR;
@@ -251,7 +285,7 @@
case FLUSH_STREAM: {
data.readInt32(&stream);
result = flushStream(stream);
- ALOGD("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
+ ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
stream, result);
reply->writeInt32(result);
return NO_ERROR;
@@ -260,9 +294,10 @@
case REGISTER_AUDIO_THREAD: {
data.readInt32(&stream);
data.readInt32(&pid);
+ data.readInt32(&tid);
data.readInt64(&nanoseconds);
- result = registerAudioThread(stream, pid, nanoseconds);
- ALOGD("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
+ result = registerAudioThread(stream, pid, tid, nanoseconds);
+ ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
stream, result);
reply->writeInt32(result);
return NO_ERROR;
@@ -271,8 +306,9 @@
case UNREGISTER_AUDIO_THREAD: {
data.readInt32(&stream);
data.readInt32(&pid);
- result = unregisterAudioThread(stream, pid);
- ALOGD("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
+ data.readInt32(&tid);
+ result = unregisterAudioThread(stream, pid, tid);
+ ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
stream, result);
reply->writeInt32(result);
return NO_ERROR;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 53c3b45..ab7fd1b 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -28,9 +28,12 @@
#include "binding/AudioEndpointParcelable.h"
#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
+#include "utility/HandleTracker.h"
namespace android {
+#define AAUDIO_SERVICE_NAME "media.aaudio"
+
// Interface (our AIDL) - Shared by server and client
class IAAudioService : public IInterface {
public:
@@ -42,8 +45,8 @@
* @param configuration contains information about the created stream
* @return handle to the stream or a negative error
*/
- virtual aaudio::aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configuration) = 0;
+ virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
@@ -55,26 +58,33 @@
/**
* Start the flow of data.
+ * This is asynchronous. When complete, the service will send a STARTED event.
*/
virtual aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) = 0;
/**
* Stop the flow of data such that start() can resume without loss of data.
+ * This is asynchronous. When complete, the service will send a PAUSED event.
*/
virtual aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) = 0;
/**
* Discard any data held by the underlying HAL or Service.
+ * This is asynchronous. When complete, the service will send a FLUSHED event.
*/
virtual aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) = 0;
/**
* Manage the specified thread as a low latency audio thread.
+ * TODO Consider passing this information as part of the startStream() call.
*/
- virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle, pid_t clientThreadId,
+ virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
+ pid_t clientThreadId,
int64_t periodNanoseconds) = 0;
- virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+ virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientProcessId,
pid_t clientThreadId) = 0;
};
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 3a92929..05451f9 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <stdint.h>
#include <binder/Parcelable.h>
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 3f82c79..5fc5d00 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -55,6 +55,8 @@
void setCapacityInFrames(int32_t capacityInFrames);
+ bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
+
/**
* The read and write must be symmetric.
*/
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 1102dec..cfb820f 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -14,12 +14,18 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <stdint.h>
+#include <stdio.h>
#include <sys/mman.h>
#include <aaudio/AAudioDefinitions.h>
#include <binder/Parcelable.h>
+#include <utility/AAudioUtilities.h>
#include "binding/SharedMemoryParcelable.h"
@@ -36,28 +42,55 @@
void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) {
mFd = fd;
mSizeInBytes = sizeInBytes;
+
}
status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mSizeInBytes);
+ status_t status = parcel->writeInt32(mSizeInBytes);
+ if (status != NO_ERROR) return status;
if (mSizeInBytes > 0) {
- parcel->writeDupFileDescriptor(mFd);
+ status = parcel->writeDupFileDescriptor(mFd);
+ ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d", status);
}
- return NO_ERROR; // TODO check for errors above
+ return status;
}
status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
- parcel->readInt32(&mSizeInBytes);
- if (mSizeInBytes > 0) {
- mFd = dup(parcel->readFileDescriptor());
+ status_t status = parcel->readInt32(&mSizeInBytes);
+ if (status != NO_ERROR) {
+ return status;
}
- return NO_ERROR; // TODO check for errors above
+ if (mSizeInBytes > 0) {
+// FIXME mFd = dup(parcel->readFileDescriptor());
+ // Why is the ALSA resource not getting freed?!
+ mFd = fcntl(parcel->readFileDescriptor(), F_DUPFD_CLOEXEC, 0);
+ if (mFd == -1) {
+ status = -errno;
+ ALOGE("SharedMemoryParcelable readFileDescriptor fcntl() failed : %d", status);
+ }
+ }
+ return status;
}
-// TODO Add code to unmmap()
+aaudio_result_t SharedMemoryParcelable::close() {
+ if (mResolvedAddress != nullptr) {
+ int err = munmap(mResolvedAddress, mSizeInBytes);
+ if (err < 0) {
+ ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
+ return AAudioConvert_androidToAAudioResult(err);
+ }
+ mResolvedAddress = nullptr;
+ }
+ if (mFd != -1) {
+ ::close(mFd);
+ mFd = -1;
+ }
+ return AAUDIO_OK;
+}
aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
void **regionAddressPtr) {
+
if (offsetInBytes < 0) {
ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
@@ -68,6 +101,11 @@
return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mResolvedAddress == nullptr) {
+ /* TODO remove
+ int fd = fcntl(mFd, F_DUPFD_CLOEXEC, 0);
+ ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, (%s)",
+ mFd, mSizeInBytes, strerror(errno));
+ */
mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE,
MAP_SHARED, mFd, 0);
if (mResolvedAddress == nullptr) {
@@ -76,8 +114,8 @@
}
}
*regionAddressPtr = mResolvedAddress + offsetInBytes;
- ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
- ALOGD("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
+ ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+ ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
offsetInBytes, *regionAddressPtr);
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 7e0bf1a..22e16f0 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -49,8 +49,14 @@
virtual status_t readFromParcel(const Parcel* parcel) override;
+ // mmap() shared memory
aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
+ // munmap() any mapped memory
+ aaudio_result_t close();
+
+ bool isFileDescriptorSafe();
+
int32_t getSizeInBytes();
aaudio_result_t validate();
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 8ca0023..8e57832 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
#include <stdint.h>
#include <sys/mman.h>
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index d6c2281..5fb2a4c 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -45,6 +45,8 @@
aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
+ bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
+
aaudio_result_t validate();
void dump();
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 90c619c..fe049b2 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -39,11 +39,26 @@
{
}
-static void AudioEndpoint_validateQueueDescriptor(const char *type,
+static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
const RingBufferDescriptor *descriptor) {
- assert(descriptor->capacityInFrames > 0);
- assert(descriptor->bytesPerFrame > 1);
- assert(descriptor->dataAddress != nullptr);
+ if (descriptor == nullptr) {
+ ALOGE("AudioEndpoint_validateQueueDescriptor() NULL descriptor");
+ return AAUDIO_ERROR_NULL;
+ }
+ if (descriptor->capacityInFrames <= 0) {
+ ALOGE("AudioEndpoint_validateQueueDescriptor() bad capacityInFrames = %d",
+ descriptor->capacityInFrames);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ if (descriptor->bytesPerFrame <= 1) {
+ ALOGE("AudioEndpoint_validateQueueDescriptor() bad bytesPerFrame = %d",
+ descriptor->bytesPerFrame);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ if (descriptor->dataAddress == nullptr) {
+ ALOGE("AudioEndpoint_validateQueueDescriptor() NULL dataAddress");
+ return AAUDIO_ERROR_NULL;
+ }
ALOGD("AudioEndpoint_validateQueueDescriptor %s, dataAddress at %p ====================",
type,
descriptor->dataAddress);
@@ -52,11 +67,12 @@
descriptor->writeCounterAddress);
// Try to READ from the data area.
+ // This code will crash if the mmap failed.
uint8_t value = descriptor->dataAddress[0];
ALOGD("AudioEndpoint_validateQueueDescriptor() dataAddress[0] = %d, then try to write",
(int) value);
// Try to WRITE to the data area.
- descriptor->dataAddress[0] = value;
+ descriptor->dataAddress[0] = value * 3;
ALOGD("AudioEndpoint_validateQueueDescriptor() wrote successfully");
if (descriptor->readCounterAddress) {
@@ -73,17 +89,28 @@
*descriptor->writeCounterAddress = counter;
ALOGD("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
}
+ return AAUDIO_OK;
}
-void AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndpointDescriptor) {
- AudioEndpoint_validateQueueDescriptor("msg", &pEndpointDescriptor->upMessageQueueDescriptor);
- AudioEndpoint_validateQueueDescriptor("data", &pEndpointDescriptor->downDataQueueDescriptor);
+aaudio_result_t AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndpointDescriptor) {
+ aaudio_result_t result = AudioEndpoint_validateQueueDescriptor("messages",
+ &pEndpointDescriptor->upMessageQueueDescriptor);
+ if (result == AAUDIO_OK) {
+ result = AudioEndpoint_validateQueueDescriptor("data",
+ &pEndpointDescriptor->downDataQueueDescriptor);
+ }
+ return result;
}
aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor)
{
- aaudio_result_t result = AAUDIO_OK;
- AudioEndpoint_validateDescriptor(pEndpointDescriptor); // FIXME remove after debugging
+ // TODO maybe remove after debugging
+ aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
+ if (result != AAUDIO_OK) {
+ ALOGD("AudioEndpoint_validateQueueDescriptor returned %d %s",
+ result, AAudio_convertResultToText(result));
+ return result;
+ }
const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
assert(descriptor->bytesPerFrame == sizeof(AAudioServiceMessage));
@@ -125,6 +152,7 @@
int64_t *writeCounterAddress = (descriptor->writeCounterAddress == nullptr)
? &mDataWriteCounter
: descriptor->writeCounterAddress;
+
mDownDataQueue = new FifoBuffer(
descriptor->bytesPerFrame,
descriptor->capacityInFrames,
@@ -144,9 +172,19 @@
aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames)
{
+ // TODO Make it easier for the AAudioStreamInternal to scale floats and write shorts
+ // TODO Similar to block adapter write through technique. Add a DataConverter.
return mDownDataQueue->write(buffer, numFrames);
}
+void AudioEndpoint::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
+ mDownDataQueue->getEmptyRoomAvailable(wrappingBuffer);
+}
+
+void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
+ mDownDataQueue->getFifoControllerBase()->advanceWriteIndex(deltaFrames);
+}
+
void AudioEndpoint::setDownDataReadCounter(fifo_counter_t framesRead)
{
mDownDataQueue->setReadCounter(framesRead);
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index caee488..a24a705 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -19,13 +19,13 @@
#include <aaudio/AAudio.h>
-#include "AAudioServiceMessage.h"
-#include "AudioEndpointParcelable.h"
+#include "binding/AAudioServiceMessage.h"
+#include "binding/AudioEndpointParcelable.h"
#include "fifo/FifoBuffer.h"
namespace aaudio {
-#define ENDPOINT_DATA_QUEUE_SIZE_MIN 64
+#define ENDPOINT_DATA_QUEUE_SIZE_MIN 48
/**
* A sink for audio.
@@ -54,15 +54,19 @@
*/
aaudio_result_t writeDataNow(const void *buffer, int32_t numFrames);
+ void getEmptyRoomAvailable(android::WrappingBuffer *wrappingBuffer);
+
+ void advanceWriteIndex(int32_t deltaFrames);
+
/**
* Set the read index in the downData queue.
* This is needed if the reader is not updating the index itself.
*/
- void setDownDataReadCounter(fifo_counter_t framesRead);
- fifo_counter_t getDownDataReadCounter();
+ void setDownDataReadCounter(android::fifo_counter_t framesRead);
+ android::fifo_counter_t getDownDataReadCounter();
- void setDownDataWriteCounter(fifo_counter_t framesWritten);
- fifo_counter_t getDownDataWriteCounter();
+ void setDownDataWriteCounter(android::fifo_counter_t framesWritten);
+ android::fifo_counter_t getDownDataWriteCounter();
/**
* The result is not valid until after configure() is called.
@@ -80,11 +84,11 @@
int32_t getFullFramesAvailable();
private:
- FifoBuffer * mUpCommandQueue;
- FifoBuffer * mDownDataQueue;
- bool mOutputFreeRunning;
- fifo_counter_t mDataReadCounter; // only used if free-running
- fifo_counter_t mDataWriteCounter; // only used if free-running
+ android::FifoBuffer *mUpCommandQueue;
+ android::FifoBuffer *mDownDataQueue;
+ bool mOutputFreeRunning;
+ android::fifo_counter_t mDataReadCounter; // only used if free-running
+ android::fifo_counter_t mDataWriteCounter; // only used if free-running
};
} // namespace aaudio
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 1f9ce4f..3934a6d 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -18,19 +18,24 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <stdint.h>
#include <assert.h>
#include <binder/IServiceManager.h>
-#include <utils/Mutex.h>
#include <aaudio/AAudio.h>
#include <utils/String16.h>
-#include "utility/AudioClock.h"
-#include "AudioStreamInternal.h"
+#include "AudioClock.h"
+#include "AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioService.h"
#include "binding/AAudioServiceMessage.h"
+#include "fifo/FifoBuffer.h"
#include "core/AudioStreamBuilder.h"
+#include "AudioStreamInternal.h"
#define LOG_TIMESTAMPS 0
@@ -39,52 +44,25 @@
using android::defaultServiceManager;
using android::interface_cast;
using android::Mutex;
+using android::WrappingBuffer;
using namespace aaudio;
-static android::Mutex gServiceLock;
-static sp<IAAudioService> gAAudioService;
-
-#define AAUDIO_SERVICE_NAME "AAudioService"
-
#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND)
// Wait at least this many times longer than the operation should take.
#define MIN_TIMEOUT_OPERATIONS 4
-// 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.
- if (binder != 0) {
- break;
- }
- } while (retries-- > 0);
+#define ALOG_CONDITION (mInService == false)
- 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);
- }
- }
- return gAAudioService;
-}
-
-AudioStreamInternal::AudioStreamInternal()
+AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService)
: AudioStream()
, mClockModel()
, mAudioEndpoint()
, mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
, mFramesPerBurst(16)
+ , mServiceInterface(serviceInterface)
+ , mInService(inService)
{
}
@@ -93,9 +71,6 @@
aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
- const sp<IAAudioService>& service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
-
aaudio_result_t result = AAUDIO_OK;
AAudioStreamRequest request;
AAudioStreamConfiguration configuration;
@@ -105,22 +80,31 @@
return result;
}
+ // We have to do volume scaling. So we prefer FLOAT format.
+ if (getFormat() == AAUDIO_UNSPECIFIED) {
+ setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+ }
+
// Build the request to send to the server.
request.setUserId(getuid());
request.setProcessId(getpid());
+ request.setDirection(getDirection());
+
request.getConfiguration().setDeviceId(getDeviceId());
request.getConfiguration().setSampleRate(getSampleRate());
request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
request.getConfiguration().setAudioFormat(getFormat());
+ aaudio_sharing_mode_t sharingMode = getSharingMode();
+ ALOGE("AudioStreamInternal.open(): sharingMode %d", sharingMode);
+ request.getConfiguration().setSharingMode(sharingMode);
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
- request.dump();
- mServiceStreamHandle = service->openStream(request, configuration);
- ALOGD("AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
+ mServiceStreamHandle = mServiceInterface.openStream(request, configuration);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
(unsigned int)mServiceStreamHandle);
if (mServiceStreamHandle < 0) {
result = mServiceStreamHandle;
- ALOGE("AudioStreamInternal.open(): acquireRealtimeStream aaudio_result_t = 0x%08X", result);
+ ALOGE("AudioStreamInternal.open(): openStream() returned %d", result);
} else {
result = configuration.validate();
if (result != AAUDIO_OK) {
@@ -130,17 +114,27 @@
// Save results of the open.
setSampleRate(configuration.getSampleRate());
setSamplesPerFrame(configuration.getSamplesPerFrame());
- setFormat(configuration.getAudioFormat());
+ setDeviceId(configuration.getDeviceId());
- aaudio::AudioEndpointParcelable parcelable;
- result = service->getStreamDescription(mServiceStreamHandle, parcelable);
+ // Save device format so we can do format conversion and volume scaling together.
+ mDeviceFormat = configuration.getAudioFormat();
+
+ result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): getStreamDescriptor(0x%08X) returns %d",
+ mServiceStreamHandle, result);
if (result != AAUDIO_OK) {
ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result);
- service->closeStream(mServiceStreamHandle);
+ mServiceInterface.closeStream(mServiceStreamHandle);
return result;
}
+
// resolve parcelable into a descriptor
- parcelable.resolve(&mEndpointDescriptor);
+ result = mEndPointParcelable.resolve(&mEndpointDescriptor);
+ if (result != AAUDIO_OK) {
+ ALOGE("AudioStreamInternal.open(): resolve() returns %d", result);
+ mServiceInterface.closeStream(mServiceStreamHandle);
+ return result;
+ }
// Configure endpoint based on descriptor.
mAudioEndpoint.configure(&mEndpointDescriptor);
@@ -156,12 +150,12 @@
mCallbackFrames = builder.getFramesPerDataCallback();
if (mCallbackFrames > getBufferCapacity() / 2) {
ALOGE("AudioStreamInternal.open(): framesPerCallback too large");
- service->closeStream(mServiceStreamHandle);
+ mServiceInterface.closeStream(mServiceStreamHandle);
return AAUDIO_ERROR_OUT_OF_RANGE;
} else if (mCallbackFrames < 0) {
ALOGE("AudioStreamInternal.open(): framesPerCallback negative");
- service->closeStream(mServiceStreamHandle);
+ mServiceInterface.closeStream(mServiceStreamHandle);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -181,20 +175,20 @@
}
aaudio_result_t AudioStreamInternal::close() {
- ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
- aaudioService->closeStream(serviceStreamHandle);
+
+ mServiceInterface.closeStream(serviceStreamHandle);
delete[] mCallbackBuffer;
- return AAUDIO_OK;
+ return mEndPointParcelable.close();
} else {
return AAUDIO_ERROR_INVALID_HANDLE;
}
}
+
// Render audio in the application callback and then write the data to the stream.
void *AudioStreamInternal::callbackLoop() {
aaudio_result_t result = AAUDIO_OK;
@@ -254,19 +248,16 @@
aaudio_result_t AudioStreamInternal::requestStart()
{
int64_t startTime;
- ALOGD("AudioStreamInternal(): start()");
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): start()");
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) {
- return AAUDIO_ERROR_NO_SERVICE;
- }
+
startTime = AudioClock::getNanoseconds();
mClockModel.start(startTime);
processTimestamp(0, startTime);
setState(AAUDIO_STREAM_STATE_STARTING);
- aaudio_result_t result = aaudioService->startStream(mServiceStreamHandle);
+ aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);;
if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
// Launch the callback loop thread.
@@ -306,13 +297,10 @@
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) {
- return AAUDIO_ERROR_NO_SERVICE;
- }
+
mClockModel.stop(AudioClock::getNanoseconds());
setState(AAUDIO_STREAM_STATE_PAUSING);
- return aaudioService->pauseStream(mServiceStreamHandle);
+ return mServiceInterface.startStream(mServiceStreamHandle);
}
aaudio_result_t AudioStreamInternal::requestPause()
@@ -325,20 +313,17 @@
}
aaudio_result_t AudioStreamInternal::requestFlush() {
- ALOGD("AudioStreamInternal(): flush()");
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): flush()");
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) {
- return AAUDIO_ERROR_NO_SERVICE;
- }
+
setState(AAUDIO_STREAM_STATE_FLUSHING);
- return aaudioService->flushStream(mServiceStreamHandle);
+ return mServiceInterface.flushStream(mServiceStreamHandle);
}
void AudioStreamInternal::onFlushFromServer() {
- ALOGD("AudioStreamInternal(): onFlushFromServer()");
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): onFlushFromServer()");
int64_t readCounter = mAudioEndpoint.getDownDataReadCounter();
int64_t writeCounter = mAudioEndpoint.getDownDataWriteCounter();
// Bump offset so caller does not see the retrograde motion in getFramesRead().
@@ -366,25 +351,22 @@
}
aaudio_result_t AudioStreamInternal::registerThread() {
- ALOGD("AudioStreamInternal(): registerThread()");
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): registerThread()");
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
- return aaudioService->registerAudioThread(mServiceStreamHandle,
- gettid(),
- getPeriodNanoseconds());
+ return mServiceInterface.registerAudioThread(mServiceStreamHandle,
+ getpid(),
+ gettid(),
+ getPeriodNanoseconds());
}
aaudio_result_t AudioStreamInternal::unregisterThread() {
- ALOGD("AudioStreamInternal(): unregisterThread()");
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): unregisterThread()");
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
- const sp<IAAudioService>& aaudioService = getAAudioService();
- if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
- return aaudioService->unregisterAudioThread(mServiceStreamHandle, gettid());
+ return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid());
}
aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
@@ -410,16 +392,16 @@
static int64_t oldTime = 0;
int64_t framePosition = command.timestamp.position;
int64_t nanoTime = command.timestamp.timestamp;
- ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
(long long) framePosition,
(long long) nanoTime);
int64_t nanosDelta = nanoTime - oldTime;
if (nanosDelta > 0 && oldTime > 0) {
int64_t framesDelta = framePosition - oldPosition;
int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
- ALOGD("AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
- ALOGD("AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
- ALOGD("AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate);
}
oldPosition = framePosition;
oldTime = nanoTime;
@@ -438,29 +420,34 @@
aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
aaudio_result_t result = AAUDIO_OK;
- ALOGD("processCommands() got event %d", message->event.event);
+ ALOGD_IF(ALOG_CONDITION, "processCommands() got event %d", message->event.event);
switch (message->event.event) {
case AAUDIO_SERVICE_EVENT_STARTED:
- ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
+ ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
setState(AAUDIO_STREAM_STATE_STARTED);
break;
case AAUDIO_SERVICE_EVENT_PAUSED:
- ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
+ ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
setState(AAUDIO_STREAM_STATE_PAUSED);
break;
case AAUDIO_SERVICE_EVENT_FLUSHED:
- ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
+ ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
setState(AAUDIO_STREAM_STATE_FLUSHED);
onFlushFromServer();
break;
case AAUDIO_SERVICE_EVENT_CLOSED:
- ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
+ ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
setState(AAUDIO_STREAM_STATE_CLOSED);
break;
case AAUDIO_SERVICE_EVENT_DISCONNECTED:
result = AAUDIO_ERROR_DISCONNECTED;
+ setState(AAUDIO_STREAM_STATE_DISCONNECTED);
ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED");
break;
+ case AAUDIO_SERVICE_EVENT_VOLUME:
+ mVolume = message->event.dataDouble;
+ ALOGD_IF(ALOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", mVolume);
+ break;
default:
ALOGW("WARNING - processCommands() Unrecognized event = %d",
(int) message->event.event);
@@ -474,6 +461,7 @@
aaudio_result_t result = AAUDIO_OK;
while (result == AAUDIO_OK) {
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result);
AAudioServiceMessage message;
if (mAudioEndpoint.readUpCommand(&message) != 1) {
break; // no command this time, no problem
@@ -502,21 +490,26 @@
int64_t timeoutNanoseconds)
{
aaudio_result_t result = AAUDIO_OK;
+ int32_t loopCount = 0;
uint8_t* source = (uint8_t*)buffer;
int64_t currentTimeNanos = AudioClock::getNanoseconds();
int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
int32_t framesLeft = numFrames;
-// ALOGD("AudioStreamInternal::write(%p, %d) at time %08llu , mState = %d ------------------",
-// buffer, numFrames, (unsigned long long) currentTimeNanos, mState);
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write(%p, %d) at time %08llu , mState = %s",
+ // buffer, numFrames, (unsigned long long) currentTimeNanos,
+ // AAudio_convertStreamStateToText(getState()));
// Write until all the data has been written or until a timeout occurs.
while (framesLeft > 0) {
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesLeft = %d, loopCount = %d =====",
+ // framesLeft, loopCount++);
// The call to writeNow() will not block. It will just write as much as it can.
int64_t wakeTimeNanos = 0;
aaudio_result_t framesWritten = writeNow(source, framesLeft,
currentTimeNanos, &wakeTimeNanos);
-// ALOGD("AudioStreamInternal::write() writeNow() framesLeft = %d --> framesWritten = %d", framesLeft, framesWritten);
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesWritten = %d", framesWritten);
if (framesWritten < 0) {
+ ALOGE("AudioStreamInternal::write() loop: writeNow returned %d", framesWritten);
result = framesWritten;
break;
}
@@ -527,18 +520,19 @@
if (timeoutNanoseconds == 0) {
break; // don't block
} else if (framesLeft > 0) {
- //ALOGD("AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos);
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos);
// clip the wake time to something reasonable
if (wakeTimeNanos < currentTimeNanos) {
wakeTimeNanos = currentTimeNanos;
}
if (wakeTimeNanos > deadlineNanos) {
// If we time out, just return the framesWritten so far.
- ALOGE("AudioStreamInternal::write(): timed out after %lld nanos", (long long) timeoutNanoseconds);
+ ALOGE("AudioStreamInternal::write(): timed out after %lld nanos",
+ (long long) timeoutNanoseconds);
break;
}
- //ALOGD("AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
// (long long) (wakeTimeNanos - currentTimeNanos));
AudioClock::sleepForNanos(wakeTimeNanos - currentTimeNanos);
currentTimeNanos = AudioClock::getNanoseconds();
@@ -546,43 +540,52 @@
}
// return error or framesWritten
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() result = %d, framesLeft = %d, #%d",
+ // result, framesLeft, loopCount);
+ (void) loopCount;
return (result < 0) ? result : numFrames - framesLeft;
}
// Write as much data as we can without blocking.
aaudio_result_t AudioStreamInternal::writeNow(const void *buffer, int32_t numFrames,
int64_t currentNanoTime, int64_t *wakeTimePtr) {
+
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow(%p) - enter", buffer);
{
aaudio_result_t result = processCommands();
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - processCommands() returned %d", result);
if (result != AAUDIO_OK) {
return result;
}
}
if (mAudioEndpoint.isOutputFreeRunning()) {
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - update read counter");
// Update data queue based on the timing model.
int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
mAudioEndpoint.setDownDataReadCounter(estimatedReadCounter);
- // If the read index passed the write index then consider it an underrun.
- if (mAudioEndpoint.getFullFramesAvailable() < 0) {
- mXRunCount++;
- }
}
// TODO else query from endpoint cuz set by actual reader, maybe
- // Write some data to the buffer.
- int32_t framesWritten = mAudioEndpoint.writeDataNow(buffer, numFrames);
- if (framesWritten > 0) {
- incrementFramesWritten(framesWritten);
+ // If the read index passed the write index then consider it an underrun.
+ if (mAudioEndpoint.getFullFramesAvailable() < 0) {
+ mXRunCount++;
}
- //ALOGD("AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d",
+
+ // Write some data to the buffer.
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - writeNowWithConversion(%d)", numFrames);
+ int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d",
// numFrames, framesWritten);
// Calculate an ideal time to wake up.
if (wakeTimePtr != nullptr && framesWritten >= 0) {
// By default wake up a few milliseconds from now. // TODO review
- int64_t wakeTime = currentNanoTime + (2 * AAUDIO_NANOS_PER_MILLISECOND);
- switch (getState()) {
+ int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
+ aaudio_stream_state_t state = getState();
+ //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - wakeTime based on %s",
+ // AAudio_convertStreamStateToText(state));
+ switch (state) {
case AAUDIO_STREAM_STATE_OPEN:
case AAUDIO_STREAM_STATE_STARTING:
if (framesWritten != 0) {
@@ -607,13 +610,68 @@
*wakeTimePtr = wakeTime;
}
-// ALOGD("AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
+// ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
// (unsigned long long)currentNanoTime,
// (unsigned long long)mAudioEndpoint.getDownDataReadCounter(),
// (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
return framesWritten;
}
+
+// TODO this function needs a major cleanup.
+aaudio_result_t AudioStreamInternal::writeNowWithConversion(const void *buffer,
+ int32_t numFrames) {
+ // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion(%p, %d)", buffer, numFrames);
+ WrappingBuffer wrappingBuffer;
+ mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer);
+ uint8_t *source = (uint8_t *) buffer;
+ int32_t framesLeft = numFrames;
+
+ mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer);
+
+ // Read data in one or two parts.
+ int partIndex = 0;
+ while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+ int32_t framesToWrite = framesLeft;
+ int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+ if (framesAvailable > 0) {
+ if (framesToWrite > framesAvailable) {
+ framesToWrite = framesAvailable;
+ }
+ int32_t numBytes = getBytesPerFrame();
+ // TODO handle volume scaling
+ if (getFormat() == mDeviceFormat) {
+ // Copy straight through.
+ memcpy(wrappingBuffer.data[partIndex], source, numBytes);
+ } else if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT
+ && mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
+ // Data conversion.
+ AAudioConvert_floatToPcm16(
+ (const float *) source,
+ framesToWrite * getSamplesPerFrame(),
+ (int16_t *) wrappingBuffer.data[partIndex]);
+ } else {
+ // TODO handle more conversions
+ ALOGE("AudioStreamInternal::writeNowWithConversion() unsupported formats: %d, %d",
+ getFormat(), mDeviceFormat);
+ return AAUDIO_ERROR_UNEXPECTED_VALUE;
+ }
+
+ source += numBytes;
+ framesLeft -= framesToWrite;
+ }
+ partIndex++;
+ }
+ int32_t framesWritten = numFrames - framesLeft;
+ mAudioEndpoint.advanceWriteIndex(framesWritten);
+
+ if (framesWritten > 0) {
+ incrementFramesWritten(framesWritten);
+ }
+ // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
+ return framesWritten;
+}
+
void AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) {
mClockModel.processTimestamp( position, time);
}
@@ -654,7 +712,7 @@
} else {
mLastFramesRead = framesRead;
}
- ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
+ ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
return framesRead;
}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 9a15a9b..1aa3b0f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -26,6 +26,8 @@
#include "client/AudioEndpoint.h"
#include "core/AudioStream.h"
+#include "binding/AAudioServiceInterface.h"
+
using android::sp;
using android::IAAudioService;
@@ -35,52 +37,54 @@
class AudioStreamInternal : public AudioStream {
public:
- AudioStreamInternal();
+ AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService = false);
virtual ~AudioStreamInternal();
// =========== Begin ABSTRACT methods ===========================
- virtual aaudio_result_t requestStart() override;
+ aaudio_result_t requestStart() override;
- virtual aaudio_result_t requestPause() override;
+ aaudio_result_t requestPause() override;
- virtual aaudio_result_t requestFlush() override;
+ aaudio_result_t requestFlush() override;
- virtual aaudio_result_t requestStop() override;
+ aaudio_result_t requestStop() override;
// TODO use aaudio_clockid_t all the way down to AudioClock
- virtual aaudio_result_t getTimestamp(clockid_t clockId,
+ aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) override;
+
virtual aaudio_result_t updateStateWhileWaiting() override;
+
// =========== End ABSTRACT methods ===========================
- virtual aaudio_result_t open(const AudioStreamBuilder &builder) override;
+ aaudio_result_t open(const AudioStreamBuilder &builder) override;
- virtual aaudio_result_t close() override;
+ aaudio_result_t close() override;
- virtual aaudio_result_t write(const void *buffer,
+ aaudio_result_t write(const void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds) override;
- virtual aaudio_result_t setBufferSize(int32_t requestedFrames) override;
+ aaudio_result_t setBufferSize(int32_t requestedFrames) override;
- virtual int32_t getBufferSize() const override;
+ int32_t getBufferSize() const override;
- virtual int32_t getBufferCapacity() const override;
+ int32_t getBufferCapacity() const override;
- virtual int32_t getFramesPerBurst() const override;
+ int32_t getFramesPerBurst() const override;
- virtual int64_t getFramesRead() override;
+ int64_t getFramesRead() override;
- virtual int32_t getXRunCount() const override {
+ int32_t getXRunCount() const override {
return mXRunCount;
}
- virtual aaudio_result_t registerThread() override;
+ aaudio_result_t registerThread() override;
- virtual aaudio_result_t unregisterThread() override;
+ aaudio_result_t unregisterThread() override;
// Called internally from 'C'
void *callbackLoop();
@@ -100,10 +104,10 @@
*
* @return the number of frames written or a negative error code.
*/
- virtual aaudio_result_t writeNow(const void *buffer,
- int32_t numFrames,
- int64_t currentTimeNanos,
- int64_t *wakeTimePtr);
+ aaudio_result_t writeNow(const void *buffer,
+ int32_t numFrames,
+ int64_t currentTimeNanos,
+ int64_t *wakeTimePtr);
void onFlushFromServer();
@@ -115,19 +119,41 @@
int64_t calculateReasonableTimeout(int32_t framesPerOperation);
private:
- IsochronousClockModel mClockModel;
- AudioEndpoint mAudioEndpoint;
- aaudio_handle_t mServiceStreamHandle;
- EndpointDescriptor mEndpointDescriptor;
+ /*
+ * Asynchronous write with data conversion.
+ * @param buffer
+ * @param numFrames
+ * @return fdrames written or negative error
+ */
+ aaudio_result_t writeNowWithConversion(const void *buffer,
+ int32_t numFrames);
+ void processTimestamp(uint64_t position, int64_t time);
+
+ // Adjust timing model based on timestamp from service.
+
+ IsochronousClockModel mClockModel; // timing model for chasing the HAL
+ AudioEndpoint mAudioEndpoint; // sink for writes
+ aaudio_handle_t mServiceStreamHandle; // opaque handle returned from service
+
+ AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
+ EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
+
+ aaudio_audio_format_t mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+
uint8_t *mCallbackBuffer = nullptr;
int32_t mCallbackFrames = 0;
// Offset from underlying frame position.
- int64_t mFramesOffsetFromService = 0;
- int64_t mLastFramesRead = 0;
- int32_t mFramesPerBurst;
- int32_t mXRunCount = 0;
- void processTimestamp(uint64_t position, int64_t time);
+ int64_t mFramesOffsetFromService = 0; // offset for timestamps
+ int64_t mLastFramesRead = 0; // used to prevent retrograde motion
+ int32_t mFramesPerBurst; // frames per HAL transfer
+ int32_t mXRunCount = 0; // how many underrun events?
+ float mVolume = 1.0; // volume that the server told us to use
+
+ AAudioServiceInterface &mServiceInterface; // abstract interface to the service
+
+ // The service uses this for SHARED mode.
+ bool mInService = false; // Are running in the client or the service?
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index bc2f281..d91d0e4 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -49,10 +49,13 @@
AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
switch (returnCode) {
AAUDIO_CASE_ENUM(AAUDIO_OK);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_INCOMPATIBLE);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNEXPECTED_STATE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNEXPECTED_VALUE);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_QUERY);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
@@ -62,9 +65,10 @@
AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_ORDER);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
}
return "Unrecognized AAudio error.";
}
@@ -82,6 +86,7 @@
AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
}
@@ -102,7 +107,6 @@
AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
{
- ALOGD("AAudio_createStreamBuilder(): check sHandleTracker.isInitialized ()");
AudioStreamBuilder *audioStreamBuilder = new AudioStreamBuilder();
if (audioStreamBuilder == nullptr) {
return AAUDIO_ERROR_NO_MEMORY;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 68579fd..7c0b5ae 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -45,6 +45,7 @@
mDeviceId = builder.getDeviceId();
mFormat = builder.getFormat();
mDirection = builder.getDirection();
+ mSharingMode = builder.getSharingMode();
// callbacks
mFramesPerDataCallback = builder.getFramesPerDataCallback();
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 1485d20..da71906 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -22,8 +22,8 @@
#include <stdint.h>
#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-#include "MonotonicCounter.h"
+#include "utility/AAudioUtilities.h"
+#include "utility/MonotonicCounter.h"
namespace aaudio {
@@ -266,11 +266,14 @@
mState = state;
}
+ void setDeviceId(int32_t deviceId) {
+ mDeviceId = deviceId;
+ }
+
std::mutex mStreamMutex;
std::atomic<bool> mCallbackEnabled;
-
protected:
MonotonicCounter mFramesWritten;
MonotonicCounter mFramesRead;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 858ae80..c0b59bb 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -24,12 +24,18 @@
#include <aaudio/AAudioDefinitions.h>
#include <aaudio/AAudio.h>
+#include "binding/AAudioBinderClient.h"
#include "client/AudioStreamInternal.h"
#include "core/AudioStream.h"
#include "core/AudioStreamBuilder.h"
#include "legacy/AudioStreamRecord.h"
#include "legacy/AudioStreamTrack.h"
+// Enable a mixer in AAudio service that will mix stream to an ALSA MMAP buffer.
+#define MMAP_SHARED_ENABLED 0
+// Enable AAUDIO_SHARING_MODE_EXCLUSIVE that uses an ALSA MMAP buffer.
+#define MMAP_EXCLUSIVE_ENABLED 1
+
using namespace aaudio;
/*
@@ -43,9 +49,11 @@
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
AudioStream* audioStream = nullptr;
+ AAudioBinderClient *aaudioClient = nullptr;
const aaudio_sharing_mode_t sharingMode = getSharingMode();
- ALOGE("AudioStreamBuilder.build() sharingMode = %d", sharingMode);
+ ALOGD("AudioStreamBuilder.build() sharingMode = %d", sharingMode);
switch (getDirection()) {
+
case AAUDIO_DIRECTION_INPUT:
switch (sharingMode) {
case AAUDIO_SHARING_MODE_SHARED:
@@ -57,26 +65,37 @@
break;
}
break;
+
case AAUDIO_DIRECTION_OUTPUT:
switch (sharingMode) {
case AAUDIO_SHARING_MODE_SHARED:
+#if MMAP_SHARED_ENABLED
+ aaudioClient = new AAudioBinderClient();
+ audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
+#else
audioStream = new(std::nothrow) AudioStreamTrack();
+#endif
break;
+#if MMAP_EXCLUSIVE_ENABLED
case AAUDIO_SHARING_MODE_EXCLUSIVE:
- audioStream = new(std::nothrow) AudioStreamInternal();
+ aaudioClient = new AAudioBinderClient();
+ audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
break;
+#endif
default:
ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
break;
}
break;
+
default:
ALOGE("AudioStreamBuilder(): bad direction = %d", getDirection());
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
break;
}
if (audioStream == nullptr) {
+ delete aaudioClient;
return AAUDIO_ERROR_NO_MEMORY;
}
ALOGD("AudioStreamBuilder(): created audioStream = %p", audioStream);
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index c5489f1..857780c 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -17,6 +17,7 @@
#include <cstring>
#include <unistd.h>
+
#define LOG_TAG "FifoBuffer"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -26,6 +27,8 @@
#include "FifoControllerIndirect.h"
#include "FifoBuffer.h"
+using namespace android; // TODO just import names needed
+
FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
: mFrameCapacity(capacityInFrames)
, mBytesPerFrame(bytesPerFrame)
@@ -79,80 +82,102 @@
return frames * mBytesPerFrame;
}
-fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
- size_t numBytes;
- fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
- fifo_frames_t framesToRead = numFrames;
- // Is there enough data in the FIFO
- if (framesToRead > framesAvailable) {
- framesToRead = framesAvailable;
- }
- if (framesToRead == 0) {
- return 0;
- }
+void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
+ int32_t framesAvailable,
+ int32_t startIndex) {
+ wrappingBuffer->data[1] = nullptr;
+ wrappingBuffer->numFrames[1] = 0;
+ if (framesAvailable > 0) {
- fifo_frames_t readIndex = mFifo->getReadIndex();
- uint8_t *destination = (uint8_t *) buffer;
- uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
- if ((readIndex + framesToRead) > mFrameCapacity) {
- // read in two parts, first part here
- fifo_frames_t frames1 = mFrameCapacity - readIndex;
- int32_t numBytes = convertFramesToBytes(frames1);
- memcpy(destination, source, numBytes);
- destination += numBytes;
- // read second part
- source = &mStorage[0];
- fifo_frames_t frames2 = framesToRead - frames1;
- numBytes = convertFramesToBytes(frames2);
- memcpy(destination, source, numBytes);
+ uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
+ // Does the available data cross the end of the FIFO?
+ if ((startIndex + framesAvailable) > mFrameCapacity) {
+ wrappingBuffer->data[0] = source;
+ wrappingBuffer->numFrames[0] = mFrameCapacity - startIndex;
+ wrappingBuffer->data[1] = &mStorage[0];
+ wrappingBuffer->numFrames[1] = mFrameCapacity - startIndex;
+
+ } else {
+ wrappingBuffer->data[0] = source;
+ wrappingBuffer->numFrames[0] = framesAvailable;
+ }
} else {
- // just read in one shot
- numBytes = convertFramesToBytes(framesToRead);
- memcpy(destination, source, numBytes);
+ wrappingBuffer->data[0] = nullptr;
+ wrappingBuffer->numFrames[0] = 0;
}
- mFifo->advanceReadIndex(framesToRead);
- return framesToRead;
}
-fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t framesToWrite) {
+void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
+ fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
+ fifo_frames_t startIndex = mFifo->getReadIndex();
+ fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+}
+
+void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
-// ALOGD("FifoBuffer::write() framesToWrite = %d, framesAvailable = %d",
-// framesToWrite, framesAvailable);
- if (framesToWrite > framesAvailable) {
- framesToWrite = framesAvailable;
- }
- if (framesToWrite <= 0) {
- return 0;
- }
+ fifo_frames_t startIndex = mFifo->getWriteIndex();
+ fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+}
- size_t numBytes;
- fifo_frames_t writeIndex = mFifo->getWriteIndex();
- int byteIndex = convertFramesToBytes(writeIndex);
- const uint8_t *source = (const uint8_t *) buffer;
- uint8_t *destination = &mStorage[byteIndex];
- if ((writeIndex + framesToWrite) > mFrameCapacity) {
- // write in two parts, first part here
- fifo_frames_t frames1 = mFrameCapacity - writeIndex;
- numBytes = convertFramesToBytes(frames1);
- memcpy(destination, source, numBytes);
-// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
- // read second part
- source += convertFramesToBytes(frames1);
- destination = &mStorage[0];
- fifo_frames_t framesLeft = framesToWrite - frames1;
- numBytes = convertFramesToBytes(framesLeft);
-// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
- memcpy(destination, source, numBytes);
- } else {
- // just write in one shot
- numBytes = convertFramesToBytes(framesToWrite);
-// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
- memcpy(destination, source, numBytes);
- }
- mFifo->advanceWriteIndex(framesToWrite);
+fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
+ WrappingBuffer wrappingBuffer;
+ uint8_t *destination = (uint8_t *) buffer;
+ fifo_frames_t framesLeft = numFrames;
- return framesToWrite;
+ getFullDataAvailable(&wrappingBuffer);
+
+ // Read data in one or two parts.
+ int partIndex = 0;
+ while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+ fifo_frames_t framesToRead = framesLeft;
+ fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+ //ALOGD("FifoProcessor::read() framesAvailable = %d, partIndex = %d",
+ // framesAvailable, partIndex);
+ if (framesAvailable > 0) {
+ if (framesToRead > framesAvailable) {
+ framesToRead = framesAvailable;
+ }
+ int32_t numBytes = convertFramesToBytes(framesToRead);
+ memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
+
+ destination += numBytes;
+ framesLeft -= framesToRead;
+ }
+ partIndex++;
+ }
+ fifo_frames_t framesRead = numFrames - framesLeft;
+ mFifo->advanceReadIndex(framesRead);
+ return framesRead;
+}
+
+fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) {
+ WrappingBuffer wrappingBuffer;
+ uint8_t *source = (uint8_t *) buffer;
+ fifo_frames_t framesLeft = numFrames;
+
+ getEmptyRoomAvailable(&wrappingBuffer);
+
+ // Read data in one or two parts.
+ int partIndex = 0;
+ while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+ fifo_frames_t framesToWrite = framesLeft;
+ fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+ if (framesAvailable > 0) {
+ if (framesToWrite > framesAvailable) {
+ framesToWrite = framesAvailable;
+ }
+ int32_t numBytes = convertFramesToBytes(framesToWrite);
+ memcpy(wrappingBuffer.data[partIndex], source, numBytes);
+
+ source += numBytes;
+ framesLeft -= framesToWrite;
+ }
+ partIndex++;
+ }
+ fifo_frames_t framesWritten = numFrames - framesLeft;
+ mFifo->advanceWriteIndex(framesWritten);
+ return framesWritten;
}
fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index faa9ae2..2b262a1 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -21,15 +21,29 @@
#include "FifoControllerBase.h"
+namespace android {
+
+/**
+ * Structure that represents a region in a circular buffer that might be at the
+ * end of the array and split in two.
+ */
+struct WrappingBuffer {
+ enum {
+ SIZE = 2
+ };
+ void *data[SIZE];
+ int32_t numFrames[SIZE];
+};
+
class FifoBuffer {
public:
FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames);
- FifoBuffer(int32_t bytesPerFrame,
- fifo_frames_t capacityInFrames,
- fifo_counter_t * readCounterAddress,
- fifo_counter_t * writeCounterAddress,
- void * dataStorageAddress);
+ FifoBuffer(int32_t bytesPerFrame,
+ fifo_frames_t capacityInFrames,
+ fifo_counter_t *readCounterAddress,
+ fifo_counter_t *writeCounterAddress,
+ void *dataStorageAddress);
~FifoBuffer();
@@ -40,10 +54,33 @@
fifo_frames_t write(const void *source, fifo_frames_t framesToWrite);
fifo_frames_t getThreshold();
+
void setThreshold(fifo_frames_t threshold);
fifo_frames_t getBufferCapacityInFrames();
+ /**
+ * Return pointer to available full frames in data1 and set size in numFrames1.
+ * if the data is split across the end of the FIFO then set data2 and numFrames2.
+ * Other wise set them to null
+ * @param wrappingBuffer
+ */
+ void getFullDataAvailable(WrappingBuffer *wrappingBuffer);
+
+ /**
+ * Return pointer to available empty frames in data1 and set size in numFrames1.
+ * if the room is split across the end of the FIFO then set data2 and numFrames2.
+ * Other wise set them to null
+ * @param wrappingBuffer
+ */
+ void getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer);
+
+ /**
+ * Copy data from the FIFO into the buffer.
+ * @param buffer
+ * @param numFrames
+ * @return
+ */
fifo_frames_t readNow(void *buffer, fifo_frames_t numFrames);
int64_t getNextReadTime(int32_t frameRate);
@@ -73,15 +110,21 @@
}
private:
+
+ void fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
+ int32_t framesAvailable, int32_t startIndex);
+
const fifo_frames_t mFrameCapacity;
- const int32_t mBytesPerFrame;
- uint8_t * mStorage;
- bool mStorageOwned; // did this object allocate the storage?
+ const int32_t mBytesPerFrame;
+ uint8_t *mStorage;
+ bool mStorageOwned; // did this object allocate the storage?
FifoControllerBase *mFifo;
- fifo_counter_t mFramesReadCount;
- fifo_counter_t mFramesUnderrunCount;
- int32_t mUnderrunCount; // need? just use frames
- int32_t mLastReadSize;
+ fifo_counter_t mFramesReadCount;
+ fifo_counter_t mFramesUnderrunCount;
+ int32_t mUnderrunCount; // need? just use frames
+ int32_t mLastReadSize;
};
+} // android
+
#endif //FIFO_FIFO_BUFFER_H
diff --git a/media/libaaudio/src/fifo/FifoController.h b/media/libaaudio/src/fifo/FifoController.h
index 7434634..79d98a1 100644
--- a/media/libaaudio/src/fifo/FifoController.h
+++ b/media/libaaudio/src/fifo/FifoController.h
@@ -22,6 +22,8 @@
#include "FifoControllerBase.h"
+namespace android {
+
/**
* A FIFO with counters contained in the class.
*/
@@ -55,5 +57,6 @@
std::atomic<fifo_counter_t> mWriteCounter;
};
+} // android
#endif //FIFO_FIFO_CONTROLLER_H
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
index 33a253e..14a2be1 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.cpp
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -21,6 +21,8 @@
#include <stdint.h>
#include "FifoControllerBase.h"
+using namespace android; // TODO just import names needed
+
FifoControllerBase::FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold)
: mCapacity(capacity)
, mThreshold(threshold)
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.h b/media/libaaudio/src/fifo/FifoControllerBase.h
index c543519..64af777 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.h
+++ b/media/libaaudio/src/fifo/FifoControllerBase.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace android {
+
typedef int64_t fifo_counter_t;
typedef int32_t fifo_frames_t;
@@ -118,4 +120,6 @@
fifo_frames_t mThreshold;
};
+} // android
+
#endif // FIFO_FIFO_CONTROLLER_BASE_H
diff --git a/media/libaaudio/src/fifo/FifoControllerIndirect.h b/media/libaaudio/src/fifo/FifoControllerIndirect.h
index 1aaf9ea..5832d9c 100644
--- a/media/libaaudio/src/fifo/FifoControllerIndirect.h
+++ b/media/libaaudio/src/fifo/FifoControllerIndirect.h
@@ -22,6 +22,8 @@
#include "FifoControllerBase.h"
+namespace android {
+
/**
* A FifoControllerBase with counters external to the class.
*
@@ -66,4 +68,6 @@
std::atomic<fifo_counter_t> * mWriteCounterAddress;
};
+} // android
+
#endif //FIFO_FIFO_CONTROLLER_INDIRECT_H
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 3b79953..8d60678 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,7 +22,7 @@
#include <media/AudioTrack.h>
#include <aaudio/AAudio.h>
-#include "AudioClock.h"
+#include "utility/AudioClock.h"
#include "legacy/AudioStreamLegacy.h"
#include "legacy/AudioStreamTrack.h"
#include "utility/FixedBlockReader.h"
@@ -142,6 +142,7 @@
}
setState(AAUDIO_STREAM_STATE_OPEN);
+ setDeviceId(mAudioTrack->getRoutedDeviceId());
return AAUDIO_OK;
}