Merge "add native IPlayer interface implementation" into oc-dev
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 166534f..d853946 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -22,6 +22,8 @@
         "IEffect.cpp",
         "IEffectClient.cpp",
         "ToneGenerator.cpp",
+        "PlayerBase.cpp",
+        "TrackPlayerBase.cpp",
     ],
     shared_libs: [
         "liblog",
@@ -30,6 +32,7 @@
         "libbinder",
         "libdl",
         "libaudioutils",
+        "libaudiomanager",
     ],
     export_shared_lib_headers: ["libbinder"],
 
diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp
new file mode 100644
index 0000000..0ec69db
--- /dev/null
+++ b/media/libaudioclient/PlayerBase.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <binder/IServiceManager.h>
+#include <media/PlayerBase.h>
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+namespace android {
+
+//--------------------------------------------------------------------------------------------------
+PlayerBase::PlayerBase() : BnPlayer(),
+        mPanMultiplierL(1.0f), mPanMultiplierR(1.0f),
+        mVolumeMultiplierL(1.0f), mVolumeMultiplierR(1.0f),
+        mPIId(PLAYER_PIID_INVALID), mLastReportedEvent(PLAYER_STATE_UNKNOWN)
+{
+    ALOGD("PlayerBase::PlayerBase()");
+    // use checkService() to avoid blocking if audio service is not up yet
+    sp<IBinder> binder = defaultServiceManager()->checkService(String16("audio"));
+    if (binder == 0) {
+        ALOGE("PlayerBase(): binding to audio service failed, service up?");
+    } else {
+        mAudioManager = interface_cast<IAudioManager>(binder);
+    }
+}
+
+
+PlayerBase::~PlayerBase() {
+    ALOGD("PlayerBase::~PlayerBase()");
+    baseDestroy();
+}
+
+void PlayerBase::init(player_type_t playerType, audio_usage_t usage) {
+    if (mAudioManager == 0) {
+                ALOGE("AudioPlayer realize: no audio service, player will not be registered");
+    } else {
+        mPIId = mAudioManager->trackPlayer(playerType, usage, AUDIO_CONTENT_TYPE_UNKNOWN, this);
+    }
+}
+
+void PlayerBase::baseDestroy() {
+    serviceReleasePlayer();
+    if (mAudioManager != 0) {
+        mAudioManager.clear();
+    }
+}
+
+//------------------------------------------------------------------------------
+void PlayerBase::servicePlayerEvent(player_state_t event) {
+    if (mAudioManager != 0) {
+        // only report state change
+        Mutex::Autolock _l(mPlayerStateLock);
+        if (event != mLastReportedEvent
+                && mPIId != PLAYER_PIID_INVALID) {
+            mLastReportedEvent = event;
+            mAudioManager->playerEvent(mPIId, event);
+        }
+    }
+}
+
+void PlayerBase::serviceReleasePlayer() {
+    if (mAudioManager != 0
+            && mPIId != PLAYER_PIID_INVALID) {
+        mAudioManager->releasePlayer(mPIId);
+    }
+}
+
+//FIXME temporary method while some AudioTrack state is outside of this class
+void PlayerBase::reportEvent(player_state_t event) {
+    servicePlayerEvent(event);
+}
+
+//------------------------------------------------------------------------------
+// Implementation of IPlayer
+void PlayerBase::start() {
+    if (playerStart() == NO_ERROR) {
+        ALOGD("PlayerBase::start() from IPlayer");
+        servicePlayerEvent(PLAYER_STATE_STARTED);
+    } else {
+        ALOGD("PlayerBase::start() no AudioTrack to start from IPlayer");
+    }
+}
+
+void PlayerBase::pause() {
+    if (playerPause() == NO_ERROR) {
+        ALOGD("PlayerBase::pause() from IPlayer");
+        servicePlayerEvent(PLAYER_STATE_PAUSED);
+    } else {
+        ALOGD("PlayerBase::pause() no AudioTrack to pause from IPlayer");
+    }
+}
+
+
+void PlayerBase::stop() {
+    if (playerStop() == NO_ERROR) {
+        ALOGD("PlayerBase::stop() from IPlayer");
+        servicePlayerEvent(PLAYER_STATE_STOPPED);
+    } else {
+        ALOGD("PlayerBase::stop() no AudioTrack to stop from IPlayer");
+    }
+}
+
+void PlayerBase::setVolume(float vol) {
+    {
+        Mutex::Autolock _l(mSettingsLock);
+        mVolumeMultiplierL = vol;
+        mVolumeMultiplierR = vol;
+    }
+    if (playerSetVolume() == NO_ERROR) {
+        ALOGD("PlayerBase::setVolume() from IPlayer");
+    } else {
+        ALOGD("PlayerBase::setVolume() no AudioTrack for volume control from IPlayer");
+    }
+}
+
+void PlayerBase::setPan(float pan) {
+    {
+        Mutex::Autolock _l(mSettingsLock);
+        pan = min(max(-1.0f, pan), 1.0f);
+        if (pan >= 0.0f) {
+            mPanMultiplierL = 1.0f - pan;
+            mPanMultiplierR = 1.0f;
+        } else {
+            mPanMultiplierL = 1.0f;
+            mPanMultiplierR = 1.0f + pan;
+        }
+    }
+    if (playerSetVolume() == NO_ERROR) {
+        ALOGD("PlayerBase::setPan() from IPlayer");
+    } else {
+        ALOGD("PlayerBase::setPan() no AudioTrack for volume control from IPlayer");
+    }
+}
+
+void PlayerBase::setStartDelayMs(int32_t delayMs __unused) {
+    ALOGW("setStartDelay() is not supported");
+}
+
+void PlayerBase::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration  __unused,
+        const sp<VolumeShaper::Operation>& operation __unused) {
+    ALOGW("applyVolumeShaper() is not supported");
+}
+
+status_t PlayerBase::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnPlayer::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
new file mode 100644
index 0000000..48cd803
--- /dev/null
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <media/TrackPlayerBase.h>
+
+namespace android {
+
+//--------------------------------------------------------------------------------------------------
+TrackPlayerBase::TrackPlayerBase() : PlayerBase(),
+        mPlayerVolumeL(1.0f), mPlayerVolumeR(1.0f)
+{
+    ALOGD("TrackPlayerBase::TrackPlayerBase()");
+}
+
+
+TrackPlayerBase::~TrackPlayerBase() {
+    ALOGD("TrackPlayerBase::~TrackPlayerBase()");
+    doDestroy();
+}
+
+void TrackPlayerBase::init(AudioTrack* pat, player_type_t playerType, audio_usage_t usage) {
+    PlayerBase::init(playerType, usage);
+    mAudioTrack = pat;
+}
+
+void TrackPlayerBase::destroy() {
+    doDestroy();
+    baseDestroy();
+}
+
+void TrackPlayerBase::doDestroy() {
+    if (mAudioTrack != 0) {
+        mAudioTrack->stop();
+        // Note that there may still be another reference in post-unlock phase of SetPlayState
+        mAudioTrack.clear();
+    }
+}
+
+void TrackPlayerBase::setPlayerVolume(float vl, float vr) {
+    {
+        Mutex::Autolock _l(mSettingsLock);
+        mPlayerVolumeL = vl;
+        mPlayerVolumeR = vr;
+    }
+    doSetVolume();
+}
+
+//------------------------------------------------------------------------------
+// Implementation of IPlayer
+status_t TrackPlayerBase::playerStart() {
+    status_t status = NO_INIT;
+    if (mAudioTrack != 0) {
+        status = mAudioTrack->start();
+    }
+    return status;
+}
+
+status_t TrackPlayerBase::playerPause() {
+    status_t status = NO_INIT;
+    if (mAudioTrack != 0) {
+        mAudioTrack->pause();
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+
+status_t TrackPlayerBase::playerStop() {
+    status_t status = NO_INIT;
+    if (mAudioTrack != 0) {
+        mAudioTrack->stop();
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+status_t TrackPlayerBase::playerSetVolume() {
+    return doSetVolume();
+}
+
+status_t TrackPlayerBase::doSetVolume() {
+    status_t status = NO_INIT;
+    if (mAudioTrack != 0) {
+        float tl = mPlayerVolumeL * mPanMultiplierL * mVolumeMultiplierL;
+        float tr = mPlayerVolumeR * mPanMultiplierR * mVolumeMultiplierR;
+        mAudioTrack->setVolume(tl, tr);
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+
+void TrackPlayerBase::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation) {
+    if (mAudioTrack != 0) {
+        ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
+        VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+        if (status < 0) { // a non-negative value is the volume shaper id.
+            ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
+        }
+    } else {
+        ALOGD("TrackPlayerBase::applyVolumeShaper()"
+                " no AudioTrack for volume control from IPlayer");
+    }
+}
+
+} // namespace android
diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h
new file mode 100644
index 0000000..58a7a00
--- /dev/null
+++ b/media/libaudioclient/include/media/PlayerBase.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef __ANDROID_PLAYER_BASE_H__
+#define __ANDROID_PLAYER_BASE_H__
+
+#include <audiomanager/IPlayer.h>
+#include <audiomanager/AudioManager.h>
+#include <audiomanager/IAudioManager.h>
+
+
+namespace android {
+
+class PlayerBase : public BnPlayer
+{
+public:
+    explicit PlayerBase();
+    virtual ~PlayerBase();
+
+    virtual void destroy() = 0;
+
+    //IPlayer implementation
+    virtual void start();
+    virtual void pause();
+    virtual void stop();
+    virtual void setVolume(float vol);
+    virtual void setPan(float pan);
+    virtual void setStartDelayMs(int32_t delayMs);
+    virtual void applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) override;
+
+    virtual status_t onTransact(
+                uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
+
+            //FIXME temporary method while some player state is outside of this class
+            void reportEvent(player_state_t event);
+
+protected:
+
+            void init(player_type_t playerType, audio_usage_t usage);
+            void baseDestroy();
+
+    //IPlayer methods handlers for derived classes
+    virtual status_t playerStart()  { return NO_ERROR; }
+    virtual status_t playerPause()  { return NO_ERROR; }
+    virtual status_t playerStop()  { return NO_ERROR; }
+    virtual status_t playerSetVolume()  { return NO_ERROR; }
+
+    // mutex for IPlayer volume and pan, and player-specific volume
+    Mutex mSettingsLock;
+
+    // volume multipliers coming from the IPlayer volume and pan controls
+    float mPanMultiplierL, mPanMultiplierR;
+    float mVolumeMultiplierL, mVolumeMultiplierR;
+
+private:
+            // report events to AudioService
+            void servicePlayerEvent(player_state_t event);
+            void serviceReleasePlayer();
+
+    // native interface to AudioService
+    android::sp<android::IAudioManager> mAudioManager;
+
+    // player interface ID, uniquely identifies the player in the system
+    audio_unique_id_t mPIId;
+
+    // Mutex for state reporting
+    Mutex mPlayerStateLock;
+    player_state_t mLastReportedEvent;
+};
+
+} // namespace android
+
+#endif /* __ANDROID_PLAYER_BASE_H__ */
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
new file mode 100644
index 0000000..2d113c0
--- /dev/null
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef __ANDROID_TRACK_PLAYER_BASE_H__
+#define __ANDROID_TRACK_PLAYER_BASE_H__
+
+#include <media/AudioTrack.h>
+#include <media/PlayerBase.h>
+
+namespace android {
+
+class TrackPlayerBase : public PlayerBase
+{
+public:
+    explicit TrackPlayerBase();
+    virtual ~TrackPlayerBase();
+
+            void init(AudioTrack* pat, player_type_t playerType, audio_usage_t usage);
+    virtual void destroy();
+
+    //IPlayer implementation
+    virtual void applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation);
+
+    //FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
+    sp<AudioTrack> mAudioTrack;
+
+            void setPlayerVolume(float vl, float vr);
+
+protected:
+
+    //PlayerBase virtuals
+    virtual status_t playerStart();
+    virtual status_t playerPause();
+    virtual status_t playerStop();
+    virtual status_t playerSetVolume();
+
+private:
+            void doDestroy();
+            status_t doSetVolume();
+
+    // volume coming from the player volume API
+    float mPlayerVolumeL, mPlayerVolumeR;
+};
+
+} // namespace android
+
+#endif /* __ANDROID_TRACK_PLAYER_BASE_H__ */