PatchPanel: Cleanup and refactoring
* Unified software patch endpoints management code.
* Noticed that Patch::clearConnections is only called before
getting rid of Patch instance, so there is no need
to explicitly clear references to endpoints' Track and Thread.
* Fixed out-of-memory handling when creating tracks for
a software patch.
* Factored out finding HAL Device by module handle.
Test: verify transitions to/from BT while playing media and making calls
Change-Id: If6459c477054d6dff60dfa13f2d99ee2d6e887ad
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index c2cb7ac..5a68960 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -43,12 +43,61 @@
struct audio_patch *patches);
private:
+ template<typename ThreadType, typename TrackType>
+ class Endpoint {
+ public:
+ status_t checkTrack(TrackType *trackOrNull) const {
+ if (trackOrNull == nullptr) return NO_MEMORY;
+ return trackOrNull->initCheck();
+ }
+ audio_patch_handle_t handle() const { return mHandle; }
+ sp<ThreadType> thread() { return mThread; }
+ sp<TrackType> track() { return mTrack; }
+
+ void closeConnections(PatchPanel *panel) {
+ if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
+ panel->releaseAudioPatch(mHandle);
+ mHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ if (mThread != 0) {
+ if (mTrack != 0) {
+ mThread->deletePatchTrack(mTrack);
+ }
+ if (mCloseThread) {
+ panel->mAudioFlinger.closeThreadInternal_l(mThread);
+ }
+ }
+ }
+ audio_patch_handle_t* handlePtr() { return &mHandle; }
+ void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
+ mThread = thread;
+ mCloseThread = closeThread;
+ }
+ void setTrackAndPeer(const sp<TrackType>& track,
+ ThreadBase::PatchProxyBufferProvider *peer) {
+ mTrack = track;
+ mThread->addPatchTrack(mTrack);
+ mTrack->setPeerProxy(peer);
+ }
+ void stopTrack() { if (mTrack) mTrack->stop(); }
+
+ private:
+ sp<ThreadType> mThread;
+ bool mCloseThread = true;
+ audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
+ sp<TrackType> mTrack;
+ };
+
class Patch {
public:
explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+ ~Patch();
status_t createConnections(PatchPanel *panel);
void clearConnections(PatchPanel *panel);
+ bool isSoftware() const {
+ return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
+ mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
// Note that audio_patch::id is only unique within a HAL module
struct audio_patch mAudioPatch;
@@ -58,17 +107,14 @@
// given audio HW module to a sink device on an other audio HW module.
// the objects are created by createConnections() and released by clearConnections()
// playback thread is created if no existing playback thread can be used
- sp<PlaybackThread> mPlaybackThread;
- sp<PlaybackThread::PatchTrack> mPatchTrack;
- sp<RecordThread> mRecordThread;
- sp<RecordThread::PatchRecord> mPatchRecord;
- // handle for audio patch connecting source device to record thread input.
- audio_patch_handle_t mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- // handle for audio patch connecting playback thread output to sink device
- audio_patch_handle_t mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-
+ // connects playback thread output to sink device
+ Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
+ // connects source device to record thread input
+ Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
};
+ sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
+
AudioFlinger &mAudioFlinger;
std::map<audio_patch_handle_t, Patch> mPatches;
};