Merge "aaudio test: test both input and output stream limits" into oc-dr1-dev
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 892792d..f1593fe 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -48,8 +48,8 @@
//aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
//aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
- const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
- //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+ //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
aaudio_sharing_mode_t actualSharingMode;
AAudioStream *aaudioStream = nullptr;
@@ -70,7 +70,7 @@
printf("%s - Monitor input level using AAudio\n", argv[0]);
-// AAudio_setMMapPolicy(AAUDIO_POLICY_ALWAYS);
+ AAudio_setMMapPolicy(AAUDIO_POLICY_ALWAYS);
recorder.setPerformanceMode(requestedPerformanceMode);
recorder.setSharingMode(requestedSharingMode);
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index d4cb407..b9269e6 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -27,15 +27,15 @@
#define SAMPLE_RATE 48000
#define NUM_SECONDS 4
-#define MMAP_POLICY AAUDIO_UNSPECIFIED
+//#define MMAP_POLICY AAUDIO_UNSPECIFIED
//#define MMAP_POLICY AAUDIO_POLICY_NEVER
//#define MMAP_POLICY AAUDIO_POLICY_AUTO
-//#define MMAP_POLICY AAUDIO_POLICY_ALWAYS
+#define MMAP_POLICY AAUDIO_POLICY_ALWAYS
#define REQUESTED_FORMAT AAUDIO_FORMAT_PCM_I16
-#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_SHARED
-//#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
+//#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_SHARED
+#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
int main(int argc, char **argv)
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index e40f4f9..ff13fc2 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -115,6 +115,7 @@
setSampleRate(configuration.getSampleRate());
setSamplesPerFrame(configuration.getSamplesPerFrame());
setDeviceId(configuration.getDeviceId());
+ setSharingMode(configuration.getSharingMode());
// Save device format so we can do format conversion and volume scaling together.
mDeviceFormat = configuration.getAudioFormat();
@@ -286,56 +287,6 @@
}
}
-aaudio_result_t AudioStreamInternal::requestPauseInternal()
-{
- if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
- return AAUDIO_ERROR_INVALID_STATE;
- }
-
- mClockModel.stop(AudioClock::getNanoseconds());
- setState(AAUDIO_STREAM_STATE_PAUSING);
- return AAudioConvert_androidToAAudioResult(pauseWithStatus());
-}
-
-aaudio_result_t AudioStreamInternal::requestPause()
-{
- aaudio_result_t result = stopCallback();
- if (result != AAUDIO_OK) {
- return result;
- }
- result = requestPauseInternal();
- return result;
-}
-
-aaudio_result_t AudioStreamInternal::requestFlush() {
- if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
- return AAUDIO_ERROR_INVALID_STATE;
- }
-
- setState(AAUDIO_STREAM_STATE_FLUSHING);
- return mServiceInterface.flushStream(mServiceStreamHandle);
-}
-
-// TODO for Play only
-void AudioStreamInternal::onFlushFromServer() {
- int64_t readCounter = mAudioEndpoint.getDataReadCounter();
- int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
-
- // Bump offset so caller does not see the retrograde motion in getFramesRead().
- int64_t framesFlushed = writeCounter - readCounter;
- mFramesOffsetFromService += framesFlushed;
- ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
- (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
-
- // Flush written frames by forcing writeCounter to readCounter.
- // This is because we cannot move the read counter in the hardware.
- mAudioEndpoint.setDataWriteCounter(readCounter);
-}
-
aaudio_result_t AudioStreamInternal::requestStopInternal()
{
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index c2c6419..257a702 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -41,13 +41,8 @@
AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService);
virtual ~AudioStreamInternal();
- // =========== Begin ABSTRACT methods ===========================
aaudio_result_t requestStart() override;
- aaudio_result_t requestPause() override;
-
- aaudio_result_t requestFlush() override;
-
aaudio_result_t requestStop() override;
aaudio_result_t getTimestamp(clockid_t clockId,
@@ -55,7 +50,6 @@
int64_t *timeNanoseconds) override;
virtual aaudio_result_t updateStateWhileWaiting() override;
- // =========== End ABSTRACT methods ===========================
aaudio_result_t open(const AudioStreamBuilder &builder) override;
@@ -113,13 +107,12 @@
aaudio_result_t processCommands();
- aaudio_result_t requestPauseInternal();
aaudio_result_t requestStopInternal();
aaudio_result_t stopCallback();
- void onFlushFromServer();
+ virtual void onFlushFromServer() {}
aaudio_result_t onEventFromServer(AAudioServiceMessage *message);
@@ -160,6 +153,8 @@
// The service uses this for SHARED mode.
bool mInService = false; // Is this running in the client or the service?
+ AAudioServiceInterface &mServiceInterface; // abstract interface to the service
+
private:
/*
* Asynchronous write with data conversion.
@@ -175,7 +170,6 @@
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
- AAudioServiceInterface &mServiceInterface; // abstract interface to the service
};
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 76ecbf9..1b18577 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -34,6 +34,55 @@
AudioStreamInternalPlay::~AudioStreamInternalPlay() {}
+aaudio_result_t AudioStreamInternalPlay::requestPauseInternal()
+{
+ if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
+ mServiceStreamHandle);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ mClockModel.stop(AudioClock::getNanoseconds());
+ setState(AAUDIO_STREAM_STATE_PAUSING);
+ return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestPause()
+{
+ aaudio_result_t result = stopCallback();
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+ result = requestPauseInternal();
+ return result;
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestFlush() {
+ if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
+ mServiceStreamHandle);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ setState(AAUDIO_STREAM_STATE_FLUSHING);
+ return mServiceInterface.flushStream(mServiceStreamHandle);
+}
+
+void AudioStreamInternalPlay::onFlushFromServer() {
+ int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+ int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+ // Bump offset so caller does not see the retrograde motion in getFramesRead().
+ int64_t framesFlushed = writeCounter - readCounter;
+ mFramesOffsetFromService += framesFlushed;
+ ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+ (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+ // Flush written frames by forcing writeCounter to readCounter.
+ // This is because we cannot move the read counter in the hardware.
+ mAudioEndpoint.setDataWriteCounter(readCounter);
+}
+
// Write the data, block if needed and timeoutMillis > 0
aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
int64_t timeoutNanoseconds)
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index b043f67..e59d02c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -33,6 +33,10 @@
AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, bool inService = false);
virtual ~AudioStreamInternalPlay();
+ aaudio_result_t requestPause() override;
+
+ aaudio_result_t requestFlush() override;
+
aaudio_result_t write(const void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds) override;
@@ -47,6 +51,11 @@
}
protected:
+
+ aaudio_result_t requestPauseInternal();
+
+ void onFlushFromServer() override;
+
/**
* Low level write that will not block. It will just write as much as it can.
*
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 15c85f9..e5fdcc6 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -48,8 +48,18 @@
* Use waitForStateChange() to wait for completion.
*/
virtual aaudio_result_t requestStart() = 0;
- virtual aaudio_result_t requestPause() = 0;
- virtual aaudio_result_t requestFlush() = 0;
+
+ virtual aaudio_result_t requestPause()
+ {
+ // Only implement this for OUTPUT streams.
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual aaudio_result_t requestFlush() {
+ // Only implement this for OUTPUT streams.
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
virtual aaudio_result_t requestStop() = 0;
virtual aaudio_result_t getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 8a481c0..6c4aa59 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -138,6 +138,12 @@
bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER;
bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS;
+ // TODO Support other performance settings in MMAP mode.
+ // Disable MMAP if low latency not requested.
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
+ allowMMap = false;
+ }
+
result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
if (result == AAUDIO_OK) {
// Open the stream using the parameters from the builder.
@@ -247,4 +253,4 @@
}
return AAUDIO_OK;
-}
\ No newline at end of file
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 156e83d..8e8070c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -55,7 +55,7 @@
// Try to create an AudioRecord
- // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+ // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
@@ -130,8 +130,8 @@
return AAudioConvert_androidToAAudioResult(status);
}
- // Get the actual rate.
- setSampleRate(mAudioRecord->getSampleRate());
+ // Get the actual values from the AudioRecord.
+ setSamplesPerFrame(mAudioRecord->channelCount());
setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
int32_t actualSampleRate = mAudioRecord->getSampleRate();
@@ -223,18 +223,6 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamRecord::requestPause()
-{
- // This does not make sense for an input stream.
- // There is no real difference between pause() and stop().
- return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
-aaudio_result_t AudioStreamRecord::requestFlush() {
- // This does not make sense for an input stream.
- return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
aaudio_result_t AudioStreamRecord::requestStop() {
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 90000fc..2c6a7eb 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -41,8 +41,6 @@
aaudio_result_t close() override;
aaudio_result_t requestStart() override;
- aaudio_result_t requestPause() override;
- aaudio_result_t requestFlush() override;
aaudio_result_t requestStop() override;
virtual aaudio_result_t getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
index d4202db..35ce95a 100644
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ b/media/libaaudio/src/utility/HandleTracker.cpp
@@ -113,7 +113,8 @@
result << "HandleTracker may be deadlocked\n";
}
- result << "Handles:\n";
+ result << "HandleTracker:\n";
+ result << " HandleHeaders:\n";
// atLineStart() can be changed to support an arbitrary line breaking algorithm;
// it should return true when a new line starts.
// For simplicity, we will use a constant 16 items per line.
@@ -125,7 +126,7 @@
for (int i = 0; i < mMaxHandleCount; ++i) {
if (atLineStart(i)) {
- result << " ";
+ result << " ";
}
result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
<< (atLineEnd(i) ? "\n" : " ");
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index cfee943..d808e5b 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -44,6 +44,9 @@
const int32_t kDefaultVideoEncoderDataSpace = HAL_DATASPACE_V0_BT709;
const int kStopTimeoutUs = 300000; // allow 1 sec for shutting down encoder
+// allow maximum 1 sec for stop time offset. This limits the the delay in the
+// input source.
+const int kMaxStopTimeOffsetUs = 1000000;
struct MediaCodecSource::Puller : public AHandler {
explicit Puller(const sp<MediaSource> &source);
@@ -1017,7 +1020,15 @@
if (mEncoder->getInputFormat(&inputFormat) == OK &&
inputFormat->findInt64("android._stop-time-offset-us", &stopTimeOffsetUs) &&
stopTimeOffsetUs > 0) {
+ if (stopTimeOffsetUs > kMaxStopTimeOffsetUs) {
+ ALOGW("Source stopTimeOffsetUs %lld too large, limit at %lld us",
+ (long long)stopTimeOffsetUs, (long long)kMaxStopTimeOffsetUs);
+ stopTimeOffsetUs = kMaxStopTimeOffsetUs;
+ }
timeoutUs += stopTimeOffsetUs;
+ } else {
+ // Use kMaxStopTimeOffsetUs if stop time offset is not provided by input source
+ timeoutUs = kMaxStopTimeOffsetUs;
}
} else {
mPuller->stop();
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 64b2c08..789379a 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -90,46 +90,49 @@
using ::android::IOMXNode;
using ::android::IOMXObserver;
- Mutex::Autolock autoLock(mLock);
- if (mLiveNodes.size() == kMaxNodeInstances) {
- _hidl_cb(toStatus(NO_MEMORY), nullptr);
- return Void();
- }
-
- sp<OMXNodeInstance> instance = new OMXNodeInstance(
- this, new LWOmxObserver(observer), name.c_str());
-
- OMX_COMPONENTTYPE *handle;
- OMX_ERRORTYPE err = mMaster->makeComponentInstance(
- name.c_str(), &OMXNodeInstance::kCallbacks,
- instance.get(), &handle);
-
- if (err != OMX_ErrorNone) {
- LOG(ERROR) << "Failed to allocate omx component "
- "'" << name.c_str() << "' "
- " err=" << asString(err) <<
- "(0x" << std::hex << unsigned(err) << ")";
- _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
- return Void();
- }
- instance->setHandle(handle);
- std::vector<AString> quirkVector;
- if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
- uint32_t quirks = 0;
- for (const AString quirk : quirkVector) {
- if (quirk == "requires-allocate-on-input-ports") {
- quirks |= kRequiresAllocateBufferOnInputPorts;
- }
- if (quirk == "requires-allocate-on-output-ports") {
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- }
+ sp<OMXNodeInstance> instance;
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mLiveNodes.size() == kMaxNodeInstances) {
+ _hidl_cb(toStatus(NO_MEMORY), nullptr);
+ return Void();
}
- instance->setQuirks(quirks);
- }
- mLiveNodes.add(observer.get(), instance);
+ instance = new OMXNodeInstance(
+ this, new LWOmxObserver(observer), name.c_str());
+
+ OMX_COMPONENTTYPE *handle;
+ OMX_ERRORTYPE err = mMaster->makeComponentInstance(
+ name.c_str(), &OMXNodeInstance::kCallbacks,
+ instance.get(), &handle);
+
+ if (err != OMX_ErrorNone) {
+ LOG(ERROR) << "Failed to allocate omx component "
+ "'" << name.c_str() << "' "
+ " err=" << asString(err) <<
+ "(0x" << std::hex << unsigned(err) << ")";
+ _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
+ return Void();
+ }
+ instance->setHandle(handle);
+ std::vector<AString> quirkVector;
+ if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
+ uint32_t quirks = 0;
+ for (const AString quirk : quirkVector) {
+ if (quirk == "requires-allocate-on-input-ports") {
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+ if (quirk == "requires-allocate-on-output-ports") {
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ }
+ instance->setQuirks(quirks);
+ }
+
+ mLiveNodes.add(observer.get(), instance);
+ mNode2Observer.add(instance.get(), observer.get());
+ }
observer->linkToDeath(this, 0);
- mNode2Observer.add(instance.get(), observer.get());
_hidl_cb(toStatus(OK), new TWOmxNode(instance));
return Void();
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 2f6fec8..ef4d745 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -1229,7 +1229,8 @@
ALOGW("Fail to return stopTimeOffsetUs as stop time is not set");
return INVALID_OPERATION;
}
- *stopTimeOffsetUs = mStopTimeUs - mLastFrameTimestampUs;
+ *stopTimeOffsetUs =
+ mLastFrameTimestampUs == -1 ? 0 : mStopTimeUs - mLastFrameTimestampUs;
return OK;
}
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index c0dfc54..c0bea13 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -39,6 +39,28 @@
: Singleton<AAudioClientTracker>() {
}
+
+std::string AAudioClientTracker::dump() const {
+ std::stringstream result;
+ const bool isLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return mLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isLocked) {
+ result << "AAudioClientTracker may be deadlocked\n";
+ }
+
+ result << "AAudioClientTracker:\n";
+ for (const auto& it : mNotificationClients) {
+ result << it.second->dump();
+ }
+
+ if (isLocked) {
+ mLock.unlock();
+ }
+ return result.str();
+}
+
// Create a tracker for the client.
aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
const sp<IAAudioClient>& client) {
@@ -81,12 +103,12 @@
aaudio_result_t
AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
aaudio_result_t result = AAUDIO_OK;
- ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGD("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
std::lock_guard<std::mutex> lock(mLock);
sp<NotificationClient> notificationClient = mNotificationClients[pid];
if (notificationClient == 0) {
// This will get called the first time the audio server registers an internal stream.
- ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+ ALOGD("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
notificationClient = new NotificationClient(pid);
mNotificationClients[pid] = notificationClient;
}
@@ -98,11 +120,16 @@
aaudio_result_t
AAudioClientTracker::unregisterClientStream(pid_t pid,
sp<AAudioServiceStreamBase> serviceStream) {
- ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
std::lock_guard<std::mutex> lock(mLock);
auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
+ ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+ pid, serviceStream.get());
it->second->unregisterClientStream(serviceStream);
+ } else {
+ ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+ pid, serviceStream.get());
}
return AAUDIO_OK;
}
@@ -131,7 +158,11 @@
aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
sp<AAudioServiceStreamBase> serviceStream) {
std::lock_guard<std::mutex> lock(mLock);
+ ALOGD("AAudioClientTracker::NotificationClient() before erase() count = %d\n",
+ (int)mStreams.size());
mStreams.erase(serviceStream);
+ ALOGD("AAudioClientTracker::NotificationClient() after erase() count = %d\n",
+ (int)mStreams.size());
return AAUDIO_OK;
}
@@ -141,7 +172,7 @@
if (aaudioService != nullptr) {
// Copy the current list of streams to another vector because closing them below
// will cause unregisterClientStream() calls back to this object.
- std::set<android::sp<AAudioServiceStreamBase>> streamsToClose;
+ std::set<sp<AAudioServiceStreamBase>> streamsToClose;
{
std::lock_guard<std::mutex> lock(mLock);
@@ -162,3 +193,25 @@
sp<NotificationClient> keep(this);
AAudioClientTracker::getInstance().unregisterClient(mProcessId);
}
+
+
+std::string AAudioClientTracker::NotificationClient::dump() const {
+ std::stringstream result;
+ const bool isLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return mLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isLocked) {
+ result << "AAudioClientTracker::NotificationClient may be deadlocked\n";
+ }
+
+ result << " client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
+ for (auto serviceStream : mStreams) {
+ result << " stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
+ }
+
+ if (isLocked) {
+ mLock.unlock();
+ }
+ return result.str();
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index e74c8bf..accf1a7 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -34,6 +34,18 @@
AAudioClientTracker();
~AAudioClientTracker() = default;
+ /**
+ * Returns information about the state of the this class.
+ *
+ * Will attempt to get the object lock, but will proceed
+ * even if it cannot.
+ *
+ * Each line of information ends with a newline.
+ *
+ * @return a string with useful information
+ */
+ std::string dump() const;
+
aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
void unregisterClient(pid_t pid);
@@ -66,6 +78,8 @@
int32_t getStreamCount();
+ std::string dump() const;
+
aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
@@ -74,12 +88,12 @@
virtual void binderDied(const android::wp<IBinder>& who);
protected:
- std::mutex mLock;
+ mutable std::mutex mLock;
const pid_t mProcessId;
std::set<android::sp<AAudioServiceStreamBase>> mStreams;
};
- std::mutex mLock;
+ mutable std::mutex mLock;
std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
android::AAudioService *mAAudioService = nullptr;
};
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 36e678a..02d4a19 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -48,16 +48,17 @@
result << "EndpointManager may be deadlocked\n";
}
+ result << "AAudioEndpointManager:" << "\n";
size_t inputs = mInputs.size();
- result << "Inputs: " << inputs << "\n";
+ result << "Input Endpoints: " << inputs << "\n";
for (const auto &input : mInputs) {
- result << " Input(" << input << ")\n";
+ result << " Input: " << input->dump() << "\n";
}
size_t outputs = mOutputs.size();
- result << "Outputs: " << outputs << "\n";
+ result << "Output Endpoints: " << outputs << "\n";
for (const auto &output : mOutputs) {
- result << " Output(" << output << ")\n";
+ result << " Output: " << output->dump() << "\n";
}
if (isLocked) {
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 6d3b52b..2511b2f 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -34,14 +34,14 @@
~AAudioEndpointManager() = default;
/**
- * Returns EndpointManager information.
+ * Returns information about the state of the this class.
*
* Will attempt to get the object lock, but will proceed
* even if it cannot.
*
* Each line of information ends with a newline.
*
- * @return a string representing the EndpointManager info
+ * @return a string with useful information
*/
std::string dump() const;
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 91f7885..4ccd2f6 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -69,7 +69,9 @@
result = ss.str();
ALOGW("%s", result.c_str());
} else {
- result = mHandleTracker.dump() + AAudioEndpointManager::getInstance().dump();
+ result = mHandleTracker.dump()
+ + AAudioClientTracker::getInstance().dump()
+ + AAudioEndpointManager::getInstance().dump();
}
(void)write(fd, result.c_str(), result.size());
return NO_ERROR;
@@ -105,7 +107,7 @@
}
if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- serviceStream = new AAudioServiceStreamMMAP();
+ serviceStream = new AAudioServiceStreamMMAP(mCachedUserId);
result = serviceStream->open(request, configurationOutput);
if (result != AAUDIO_OK) {
// fall back to using a shared stream
@@ -148,17 +150,18 @@
}
aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
- // Check permission first.
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+ // Check permission and ownership first.
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream == nullptr) {
ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
+ ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+ // Remove handle from tracker so that we cannot look up the raw address any more.
serviceStream = (AAudioServiceStreamBase *)
mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
streamHandle);
- ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
if (serviceStream != nullptr) {
serviceStream->close();
pid_t pid = serviceStream->getOwnerProcessId();
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 1df2365..b519829 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -18,16 +18,17 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <algorithm>
#include <assert.h>
#include <map>
#include <mutex>
+#include <sstream>
+#include <vector>
+
#include <utils/Singleton.h>
#include "AAudioEndpointManager.h"
#include "AAudioServiceEndpoint.h"
-#include <algorithm>
-#include <mutex>
-#include <vector>
#include "core/AudioStreamBuilder.h"
#include "AAudioServiceEndpoint.h"
@@ -44,6 +45,35 @@
// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
#define DEFAULT_BUFFER_CAPACITY (48 * 8)
+std::string AAudioServiceEndpoint::dump() const {
+ std::stringstream result;
+
+ const bool isLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return mLockStreams.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isLocked) {
+ result << "EndpointManager may be deadlocked\n";
+ }
+
+ AudioStreamInternal *stream = mStreamInternal;
+ if (stream == nullptr) {
+ result << "null stream!" << "\n";
+ } else {
+ result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
+ }
+
+ result << " Registered Streams:" << "\n";
+ for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+ result << sharedStream->dump();
+ }
+
+ if (isLocked) {
+ mLockStreams.unlock();
+ }
+ return result.str();
+}
+
// Set up an EXCLUSIVE MMAP stream that will be shared.
aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
mRequestedDeviceId = configuration.getDeviceId();
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 72015b1..a78d3fa 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -36,6 +36,8 @@
public:
virtual ~AAudioServiceEndpoint() = default;
+ std::string dump() const;
+
virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration);
int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); }
@@ -73,7 +75,7 @@
std::atomic<bool> mCallbackEnabled;
- std::mutex mLockStreams;
+ mutable std::mutex mLockStreams;
std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index c4591b0..2e20287 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -41,8 +41,25 @@
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
- close();
- ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroyed %p", this);
+ ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+ // If the stream is deleted without closing then audio resources will leak.
+ // Not being closed here would indicate an internal error. So we want to find this ASAP.
+ LOG_ALWAYS_FATAL_IF(mState != AAUDIO_STREAM_STATE_CLOSED,
+ "service stream not closed, state = %d", mState);
+}
+
+std::string AAudioServiceStreamBase::dump() const {
+ std::stringstream result;
+
+ result << " -------- handle = 0x" << std::hex << mHandle << std::dec << "\n";
+ result << " state = " << AAudio_convertStreamStateToText(mState) << "\n";
+ result << " format = " << mAudioFormat << "\n";
+ result << " framesPerBurst = " << mFramesPerBurst << "\n";
+ result << " channelCount = " << mSamplesPerFrame << "\n";
+ result << " capacityFrames = " << mCapacityInFrames << "\n";
+ result << " owner uid = " << mOwnerUserId << "\n";
+
+ return result.str();
}
aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
@@ -57,11 +74,13 @@
}
aaudio_result_t AAudioServiceStreamBase::close() {
- stop();
- std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
- delete mUpMessageQueue;
- mUpMessageQueue = nullptr;
-
+ if (mState != AAUDIO_STREAM_STATE_CLOSED) {
+ stopTimestampThread();
+ std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
+ delete mUpMessageQueue;
+ mUpMessageQueue = nullptr;
+ mState = AAUDIO_STREAM_STATE_CLOSED;
+ }
return AAUDIO_OK;
}
@@ -92,9 +111,8 @@
aaudio_result_t result = AAUDIO_OK;
if (isRunning()) {
// TODO wait for data to be played out
- sendCurrentTimestamp();
- mThreadEnabled.store(false);
- result = mAAudioThread.stop();
+ sendCurrentTimestamp(); // warning - this calls a virtual function
+ result = stopTimestampThread();
if (result != AAUDIO_OK) {
disconnect();
return result;
@@ -105,6 +123,15 @@
return result;
}
+aaudio_result_t AAudioServiceStreamBase::stopTimestampThread() {
+ aaudio_result_t result = AAUDIO_OK;
+ // clear flag that tells thread to loop
+ if (mThreadEnabled.exchange(false)) {
+ result = mAAudioThread.stop();
+ }
+ return result;
+}
+
aaudio_result_t AAudioServiceStreamBase::flush() {
sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
mState = AAUDIO_STREAM_STATE_FLUSHED;
@@ -127,6 +154,7 @@
nextTime = timestampScheduler.nextAbsoluteTime();
} else {
// Sleep until it is time to send the next timestamp.
+ // TODO Wait for a signal with a timeout so that we can stop more quickly.
AudioClock::sleepUntilNanoTime(nextTime);
}
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 653b456..eed1a03 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -52,6 +52,8 @@
ILLEGAL_THREAD_ID = 0
};
+ std::string dump() const;
+
// -------------------------------------------------------------------
/**
* Open the device.
@@ -76,6 +78,8 @@
*/
virtual aaudio_result_t stop();
+ aaudio_result_t stopTimestampThread();
+
/**
* Discard any data held by the underlying HAL or Service.
*/
@@ -141,6 +145,7 @@
}
protected:
+
aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
aaudio_result_t sendCurrentTimestamp();
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 40093eb..da18f44 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -41,23 +41,26 @@
* Service Stream that uses an MMAP buffer.
*/
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP()
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(uid_t serviceUid)
: AAudioServiceStreamBase()
, mMmapStreamCallback(new MyMmapStreamCallback(*this))
, mPreviousFrameCounter(0)
- , mMmapStream(nullptr) {
-}
-
-AAudioServiceStreamMMAP::~AAudioServiceStreamMMAP() {
- close();
+ , mMmapStream(nullptr)
+ , mCachedUserId(serviceUid) {
}
aaudio_result_t AAudioServiceStreamMMAP::close() {
- mMmapStream.clear(); // TODO review. Is that all we have to do?
- // Apparently the above close is asynchronous. An attempt to open a new device
- // right after a close can fail. Also some callbacks may still be in flight!
- // FIXME Make closing synchronous.
- AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+ if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ return AAUDIO_OK;
+ }
+
+ if (mMmapStream != 0) {
+ mMmapStream.clear(); // TODO review. Is that all we have to do?
+ // Apparently the above close is asynchronous. An attempt to open a new device
+ // right after a close can fail. Also some callbacks may still be in flight!
+ // FIXME Make closing synchronous.
+ AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+ }
if (mAudioDataFileDescriptor != -1) {
::close(mAudioDataFileDescriptor);
@@ -153,10 +156,29 @@
status);
return AAUDIO_ERROR_UNAVAILABLE;
} else {
- ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d",
+ ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d"
+ "Sharable FD: %s",
status, mMmapBufferinfo.shared_memory_address,
- mMmapBufferinfo.buffer_size_frames,
- mMmapBufferinfo.burst_size_frames);
+ abs(mMmapBufferinfo.buffer_size_frames),
+ mMmapBufferinfo.burst_size_frames,
+ mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
+ }
+
+ mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
+ // FIXME: the audio HAL indicates if the shared memory fd can be shared outside of audioserver
+ // by returning a negative buffer size
+ if (mCapacityInFrames < 0) {
+ // Exclusive mode is possible from any client
+ mCapacityInFrames = -mCapacityInFrames;
+ } else {
+ // exclusive mode is only possible if the final fd destination is inside audioserver
+ if ((mMmapClient.clientUid != mCachedUserId) &&
+ configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ // Fallback is handled by caller but indicate what is possible in case
+ // this is used in the future
+ configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
}
// Get information about the stream and pass it back to the caller.
@@ -166,7 +188,6 @@
mAudioDataFileDescriptor = mMmapBufferinfo.shared_memory_fd;
mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
- mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format);
mSampleRate = config.sample_rate;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index fe75a10..257bea9 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -43,9 +43,8 @@
, public android::MmapStreamCallback {
public:
- AAudioServiceStreamMMAP();
- virtual ~AAudioServiceStreamMMAP();
-
+ AAudioServiceStreamMMAP(uid_t serviceUid);
+ virtual ~AAudioServiceStreamMMAP() = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) override;
@@ -134,6 +133,7 @@
struct audio_mmap_buffer_info mMmapBufferinfo;
android::MmapStreamInterface::Client mMmapClient;
audio_port_handle_t mPortHandle = -1; // TODO review best default
+ uid_t mCachedUserId = -1;
};
} // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 1978ddd..9cc5cbc 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -44,10 +44,6 @@
{
}
-AAudioServiceStreamShared::~AAudioServiceStreamShared() {
- close();
-}
-
int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
int32_t framesPerBurst) {
@@ -260,21 +256,27 @@
}
aaudio_result_t AAudioServiceStreamShared::close() {
- pause();
- // TODO wait for pause() to synchronize
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint != nullptr) {
- sp<AAudioServiceStreamShared> keep(this);
- endpoint->unregisterStream(keep);
-
- AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
- mEndpointManager.closeEndpoint(endpoint);
- mServiceEndpoint = nullptr;
+ if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ return AAUDIO_OK;
}
+
+ AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+ if (endpoint == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ endpoint->stopStream(this);
+
+ endpoint->unregisterStream(this);
+
+ AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
+ mEndpointManager.closeEndpoint(endpoint);
+ mServiceEndpoint = nullptr;
+
if (mAudioDataQueue != nullptr) {
delete mAudioDataQueue;
mAudioDataQueue = nullptr;
}
+
return AAudioServiceStreamBase::close();
}
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 9de502b..742c5af 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -44,7 +44,7 @@
public:
AAudioServiceStreamShared(android::AAudioService &aAudioService);
- virtual ~AAudioServiceStreamShared();
+ virtual ~AAudioServiceStreamShared() = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) override;