}
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();
}
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 {
}
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;
}
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;
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;
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);
}
}
*/
virtual aaudio_result_t stop();
+ aaudio_result_t stopTimestampThread();
+
/**
* Discard any data held by the underlying HAL or Service.
*/
}
protected:
+
aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
aaudio_result_t sendCurrentTimestamp();
, mCachedUserId(serviceUid) {
}
-AAudioServiceStreamMMAP::~AAudioServiceStreamMMAP() {
- close();
-}
-
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);
public:
AAudioServiceStreamMMAP(uid_t serviceUid);
- virtual ~AAudioServiceStreamMMAP();
-
+ virtual ~AAudioServiceStreamMMAP() = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) override;
{
}
-AAudioServiceStreamShared::~AAudioServiceStreamShared() {
- close();
-}
-
int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
int32_t framesPerBurst) {
}
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);
+ if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ return AAUDIO_OK;
+ }
- AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
- mEndpointManager.closeEndpoint(endpoint);
- mServiceEndpoint = nullptr;
+ 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();
}
public:
AAudioServiceStreamShared(android::AAudioService &aAudioService);
- virtual ~AAudioServiceStreamShared();
+ virtual ~AAudioServiceStreamShared() = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) override;