SyncEvent: modernize C++

And add unit test mediasyncevent_tests.

Test: atest mediasyncevent_tests
Bug: 283021652
Change-Id: I37711f4271c68042f178db9370549c0c3260ace8
diff --git a/services/audioflinger/timing/Android.bp b/services/audioflinger/timing/Android.bp
index 17ce8bd..269f796 100644
--- a/services/audioflinger/timing/Android.bp
+++ b/services/audioflinger/timing/Android.bp
@@ -10,6 +10,10 @@
 cc_library {
     name: "libaudioflinger_timing",
 
+    defaults: [
+        "audioflinger_flags_defaults",
+    ],
+
     host_supported: true,
 
     srcs: [
diff --git a/services/audioflinger/timing/SyncEvent.h b/services/audioflinger/timing/SyncEvent.h
index 9912580..b5a3b40 100644
--- a/services/audioflinger/timing/SyncEvent.h
+++ b/services/audioflinger/timing/SyncEvent.h
@@ -16,43 +16,55 @@
 
 #pragma once
 
-namespace android {
+#include <functional>
+#include <mutex>
+
+#include <media/AudioSystem.h>
+#include <utils/RefBase.h>
+
+namespace android::audioflinger {
 
 class SyncEvent;
-
-typedef void (*sync_event_callback_t)(const wp<SyncEvent>& event) ;
+using SyncEventCallback = std::function<void(const wp<SyncEvent>& event)>;
 
 class SyncEvent : public RefBase {
 public:
     SyncEvent(AudioSystem::sync_event_t type,
               audio_session_t triggerSession,
               audio_session_t listenerSession,
-              sync_event_callback_t callBack,
+              const SyncEventCallback& callBack,
               const wp<RefBase>& cookie)
     : mType(type), mTriggerSession(triggerSession), mListenerSession(listenerSession),
-      mCallback(callBack), mCookie(cookie)
+      mCookie(cookie), mCallback(callBack)
     {}
 
-    virtual ~SyncEvent() {}
-
     void trigger() {
-        Mutex::Autolock _l(mLock);
-        if (mCallback) mCallback(wp<SyncEvent>(this));
+        std::lock_guard l(mLock);
+        if (mCallback) mCallback(wp<SyncEvent>::fromExisting(this));
     }
-    bool isCancelled() const { Mutex::Autolock _l(mLock); return (mCallback == NULL); }
-    void cancel() { Mutex::Autolock _l(mLock); mCallback = NULL; }
+
+    bool isCancelled() const {
+        std::lock_guard l(mLock);
+        return mCallback == nullptr;
+    }
+
+    void cancel() {
+        std::lock_guard l(mLock);
+        mCallback = nullptr;
+    }
+
     AudioSystem::sync_event_t type() const { return mType; }
     audio_session_t triggerSession() const { return mTriggerSession; }
     audio_session_t listenerSession() const { return mListenerSession; }
-    wp<RefBase> cookie() const { return mCookie; }
+    const wp<RefBase>& cookie() const { return mCookie; }
 
 private:
       const AudioSystem::sync_event_t mType;
       const audio_session_t mTriggerSession;
       const audio_session_t mListenerSession;
-      sync_event_callback_t mCallback;
       const wp<RefBase> mCookie;
-      mutable Mutex mLock;
+      mutable std::mutex mLock;
+      SyncEventCallback mCallback GUARDED_BY(mLock);
 };
 
-} // namespace android
+} // namespace android::audioflinger
diff --git a/services/audioflinger/timing/tests/Android.bp b/services/audioflinger/timing/tests/Android.bp
index 29267a6..c360799 100644
--- a/services/audioflinger/timing/tests/Android.bp
+++ b/services/audioflinger/timing/tests/Android.bp
@@ -8,6 +8,31 @@
 }
 
 cc_test {
+    name: "mediasyncevent_tests",
+
+    host_supported: true,
+
+    srcs: [
+        "mediasyncevent_tests.cpp"
+    ],
+
+    header_libs: [
+        "libaudioclient_headers",
+    ],
+
+    static_libs: [
+        "liblog",
+        "libutils", // RefBase
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
+
+cc_test {
     name: "monotonicframecounter_tests",
 
     host_supported: true,
diff --git a/services/audioflinger/timing/tests/mediasyncevent_tests.cpp b/services/audioflinger/timing/tests/mediasyncevent_tests.cpp
new file mode 100644
index 0000000..2922d90
--- /dev/null
+++ b/services/audioflinger/timing/tests/mediasyncevent_tests.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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_NDEBUG 0
+#define LOG_TAG "mediasyncevent_tests"
+
+#include "../SyncEvent.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+using namespace android::audioflinger;
+
+namespace {
+
+TEST(MediaSyncEventTests, Basic) {
+    struct Cookie : public RefBase {};
+
+    // These variables are set by trigger().
+    bool triggered = false;
+    wp<SyncEvent> param;
+
+    constexpr auto type = AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE;
+    constexpr auto triggerSession = audio_session_t(10);
+    constexpr auto listenerSession = audio_session_t(11);
+    const SyncEventCallback callback =
+            [&](const wp<SyncEvent>& event) {
+                triggered = true;
+                param = event;
+            };
+    const auto cookie = sp<Cookie>::make();
+
+    // Since the callback uses a weak pointer to this,
+    // don't allocate on the stack.
+    auto syncEvent = sp<SyncEvent>::make(
+            type,
+            triggerSession,
+            listenerSession,
+            callback,
+            cookie);
+
+    ASSERT_EQ(type, syncEvent->type());
+    ASSERT_EQ(triggerSession, syncEvent->triggerSession());
+    ASSERT_EQ(listenerSession, syncEvent->listenerSession());
+    ASSERT_EQ(cookie, syncEvent->cookie());
+    ASSERT_FALSE(triggered);
+
+    syncEvent->trigger();
+    ASSERT_TRUE(triggered);
+    ASSERT_EQ(param, syncEvent);
+
+    ASSERT_FALSE(syncEvent->isCancelled());
+    syncEvent->cancel();
+    ASSERT_TRUE(syncEvent->isCancelled());
+}
+
+} // namespace