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
Test: CTS test_aaudio.cpp
Change-Id: I44c7e4ecae4ce205611b6b73a72e0ae8a5b243e5
Signed-off-by: Phil Burk <philburk@google.com>
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 */