Introduce murphy control plugin.
authorKrisztian Litkey <krisztian.litkey@intel.com>
Fri, 7 Mar 2014 16:02:29 +0000 (18:02 +0200)
committerJaska Uimonen <jaska.uimonen@helsinki.fi>
Thu, 11 Sep 2014 07:29:47 +0000 (10:29 +0300)
Change-Id: I24e835d7f9da200864a8ebc8a6cabb7d4fd416f1

19 files changed:
PluginControlInterfaceMurphy/CMakeLists.txt [new file with mode: 0644]
PluginControlInterfaceMurphy/include/CAmControlSenderMurphy.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/Connection.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/Event.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/MurphyInterface.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/MurphyMainloop.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/StateMachine.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/Transition.h [new file with mode: 0644]
PluginControlInterfaceMurphy/include/TransitionRoutines.h [new file with mode: 0644]
PluginControlInterfaceMurphy/src/CAmControlSenderMurphy.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/Connection.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/Event.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/MurphyInterface.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/MurphyMainloop.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/StateMachine.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/Transition.cpp [new file with mode: 0644]
PluginControlInterfaceMurphy/src/TransitionRoutines.cpp [new file with mode: 0644]
cmake/FindMURPHY.cmake [new file with mode: 0644]
packaging/genivi-audio-manager.spec

diff --git a/PluginControlInterfaceMurphy/CMakeLists.txt b/PluginControlInterfaceMurphy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e93df19
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright (c) 2012 BMW
+#
+# author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
+#
+# copyright
+# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# For further information see http://www.genivi.org/.
+#
+
+cmake_minimum_required(VERSION 2.6)
+
+PROJECT(PluginControlInterfaceMurphy)
+
+OPTION (WITH_CONTROL_INTERFACE_MURPHY
+        "Build with control interface Murphy plugin" ON)
+
+IF (WITH_CONTROL_INTERFACE_MURPHY)
+
+set(LIBRARY_OUTPUT_PATH ${PLUGINS_OUTPUT_PATH}/control)
+set(DOC_OUTPUT_PATH ${DOC_OUTPUT_PATH}/ControlPlugin)
+set(INCLUDE_FOLDER "include")
+
+SET(SHARED_FOLDER "${CMAKE_INSTALL_PREFIX}/share")
+FILE(READ "${AUDIO_INCLUDE_FOLDER}/control/IAmControlSend.h" VERSION_BUFFER LIMIT 6000)
+STRING(REGEX MATCH "ControlSendVersion*.[^0-9]*[0-9].[0-9]*[0-9]" LIB_INTERFACE_VERSION_STRING ${VERSION_BUFFER})
+STRING(REGEX REPLACE "ControlSendVersion*.." "" LIB_INTERFACE_VERSION ${LIB_INTERFACE_VERSION_STRING})
+MESSAGE(STATUS "Building against control interface version ${LIB_INTERFACE_VERSION}")
+
+FIND_PACKAGE(MURPHY REQUIRED)
+FIND_PACKAGE(NSM REQUIRED)
+
+INCLUDE_DIRECTORIES(
+       ${CMAKE_SOURCE_DIR}
+       ${CMAKE_CURRENT_BINARY_DIR}
+       ${MURPHY_INCLUDE_DIR}
+       ${AUDIO_INCLUDE_FOLDER}
+       ${PROJECT_INCLUDE_FOLDER}
+       ${INCLUDE_FOLDER}
+        ${NSM_INCLUDE_DIR}
+)
+
+# all source files go here
+file(GLOB PLUGIN_CONTROL_MURPHY_SRCS_CXX "src/*.cpp")
+
+add_library(PluginControlInterfaceMurphy SHARED ${PLUGIN_CONTROL_MURPHY_SRCS_CXX})
+
+SET_TARGET_PROPERTIES(PluginControlInterfaceMurphy PROPERTIES
+                                            SOVERSION "${LIB_INTERFACE_VERSION}"
+)
+
+TARGET_LINK_LIBRARIES(PluginControlInterfaceMurphy
+    ${DLT_LIBRARIES}
+    ${MURPHY_LIBRARY}
+)
+
+IF(WITH_TESTS)
+       add_subdirectory (test)
+ENDIF(WITH_TESTS)
+
+INSTALL(TARGETS PluginControlInterfaceMurphy
+        DESTINATION "lib/${LIB_INSTALL_SUFFIX}/control"
+        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
+        COMPONENT sampleplugins
+)
+
+SET(ADD_DEPEND "audiomanager-bin" "libmurphy-common")
+set_property(GLOBAL APPEND PROPERTY sampleplugins_prop "${ADD_DEPEND}")
+
+ENDIF (WITH_CONTROL_INTERFACE_MURPHY)
diff --git a/PluginControlInterfaceMurphy/include/CAmControlSenderMurphy.h b/PluginControlInterfaceMurphy/include/CAmControlSenderMurphy.h
new file mode 100644 (file)
index 0000000..ec70930
--- /dev/null
@@ -0,0 +1,217 @@
+/**
+ *  Copyright (c) 2012 BMW
+ *
+ *  \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
+ *
+ *  \copyright
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction,
+ *  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ *  subject to the following conditions:
+ *  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ *  THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *  For further information see http://www.genivi.org/.
+ */
+
+#ifndef CONTROLSENDERMURPHY_H_
+#define CONTROLSENDERMURPHY_H_
+
+#include "control/IAmControlSend.h"
+#include "MurphyInterface.h"
+
+#include <list>
+
+namespace am
+{
+
+class CAmControlSenderMurphy: public IAmControlSend
+{
+public:
+    CAmControlSenderMurphy();
+    virtual ~CAmControlSenderMurphy();
+    am_Error_e startupController(IAmControlReceive* controlreceiveinterface);
+    void setControllerReady();
+    void setControllerRundown(const int16_t signal);
+    am_Error_e hookUserConnectionRequest(const am_sourceID_t sourceID, const am_sinkID_t sinkID, am_mainConnectionID_t& mainConnectionID);
+    am_Error_e hookUserDisconnectionRequest(const am_mainConnectionID_t connectionID);
+    am_Error_e hookUserSetMainSinkSoundProperty(const am_sinkID_t sinkID, const am_MainSoundProperty_s& soundProperty);
+    am_Error_e hookUserSetMainSourceSoundProperty(const am_sourceID_t sourceID, const am_MainSoundProperty_s& soundProperty);
+    am_Error_e hookUserSetSystemProperty(const am_SystemProperty_s& property);
+    am_Error_e hookUserVolumeChange(const am_sinkID_t SinkID, const am_mainVolume_t newVolume);
+    am_Error_e hookUserVolumeStep(const am_sinkID_t SinkID, const int16_t increment);
+    am_Error_e hookUserSetSinkMuteState(const am_sinkID_t sinkID, const am_MuteState_e muteState);
+    am_Error_e hookSystemRegisterDomain(const am_Domain_s& domainData, am_domainID_t& domainID);
+    am_Error_e hookSystemDeregisterDomain(const am_domainID_t domainID);
+    void hookSystemDomainRegistrationComplete(const am_domainID_t domainID);
+    am_Error_e hookSystemRegisterSink(const am_Sink_s& sinkData, am_sinkID_t& sinkID);
+    am_Error_e hookSystemDeregisterSink(const am_sinkID_t sinkID);
+    am_Error_e hookSystemRegisterSource(const am_Source_s& sourceData, am_sourceID_t& sourceID);
+    am_Error_e hookSystemDeregisterSource(const am_sourceID_t sourceID);
+    am_Error_e hookSystemRegisterGateway(const am_Gateway_s& gatewayData, am_gatewayID_t& gatewayID);
+    am_Error_e hookSystemDeregisterGateway(const am_gatewayID_t gatewayID);
+    am_Error_e hookSystemRegisterCrossfader(const am_Crossfader_s& crossfaderData, am_crossfaderID_t& crossfaderID);
+    am_Error_e hookSystemDeregisterCrossfader(const am_crossfaderID_t crossfaderID);
+    void hookSystemSinkVolumeTick(const am_Handle_s handle, const am_sinkID_t sinkID, const am_volume_t volume);
+    void hookSystemSourceVolumeTick(const am_Handle_s handle, const am_sourceID_t sourceID, const am_volume_t volume);
+    void hookSystemInterruptStateChange(const am_sourceID_t sourceID, const am_InterruptState_e interruptState);
+    void hookSystemSinkAvailablityStateChange(const am_sinkID_t sinkID, const am_Availability_s& availability);
+    void hookSystemSourceAvailablityStateChange(const am_sourceID_t sourceID, const am_Availability_s& availability);
+    void hookSystemDomainStateChange(const am_domainID_t domainID, const am_DomainState_e state);
+    void hookSystemReceiveEarlyData(const std::vector<am_EarlyData_s>& data);
+    void hookSystemSpeedChange(const am_speed_t speed);
+    void hookSystemTimingInformationChanged(const am_mainConnectionID_t mainConnectionID, const am_timeSync_t time);
+    void cbAckConnect(const am_Handle_s handle, const am_Error_e errorID);
+    void cbAckDisconnect(const am_Handle_s handle, const am_Error_e errorID);
+    void cbAckCrossFade(const am_Handle_s handle, const am_HotSink_e hostsink, const am_Error_e error);
+    void cbAckSetSinkVolumeChange(const am_Handle_s handle, const am_volume_t volume, const am_Error_e error);
+    void cbAckSetSourceVolumeChange(const am_Handle_s handle, const am_volume_t voulme, const am_Error_e error);
+    void cbAckSetSourceState(const am_Handle_s handle, const am_Error_e error);
+    void cbAckSetSourceSoundProperties(const am_Handle_s handle, const am_Error_e error);
+    void cbAckSetSourceSoundProperty(const am_Handle_s handle, const am_Error_e error);
+    void cbAckSetSinkSoundProperties(const am_Handle_s handle, const am_Error_e error);
+    void cbAckSetSinkSoundProperty(const am_Handle_s handle, const am_Error_e error);
+    am_Error_e getConnectionFormatChoice(const am_sourceID_t sourceID, const am_sinkID_t sinkID, const am_Route_s listRoute, const std::vector<am_CustomConnectionFormat_t> listPossibleConnectionFormats, std::vector<am_CustomConnectionFormat_t>& listPrioConnectionFormats);
+    void getInterfaceVersion(std::string& version) const;
+    void confirmCommandReady(const am_Error_e error) ;
+    void confirmRoutingReady(const am_Error_e error) ;
+    void confirmCommandRundown(const am_Error_e error) ;
+    void confirmRoutingRundown(const am_Error_e error) ;
+    am_Error_e hookSystemUpdateSink(const am_sinkID_t sinkID, const am_sinkClass_t sinkClassID, const std::vector<am_SoundProperty_s>& listSoundProperties, const std::vector<am_CustomConnectionFormat_t>& listConnectionFormats, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties) ;
+    am_Error_e hookSystemUpdateSource(const am_sourceID_t sourceID, const am_sourceClass_t sourceClassID, const std::vector<am_SoundProperty_s>& listSoundProperties, const std::vector<am_CustomConnectionFormat_t>& listConnectionFormats, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties) ;
+    am_Error_e hookSystemUpdateGateway(const am_gatewayID_t gatewayID, const std::vector<am_CustomConnectionFormat_t>& listSourceConnectionFormats, const std::vector<am_CustomConnectionFormat_t>& listSinkConnectionFormats, const std::vector<bool>& convertionMatrix) ;
+    void cbAckSetVolumes(const am_Handle_s handle, const std::vector<am_Volumes_s>& listVolumes, const am_Error_e error) ;
+    void cbAckSetSinkNotificationConfiguration(const am_Handle_s handle, const am_Error_e error) ;
+    void cbAckSetSourceNotificationConfiguration(const am_Handle_s handle, const am_Error_e error) ;
+    void hookSinkNotificationDataChanged(const am_sinkID_t sinkID, const am_NotificationPayload_s& payload) ;
+    void hookSourceNotificationDataChanged(const am_sourceID_t sourceID, const am_NotificationPayload_s& payload) ;
+    am_Error_e hookUserSetMainSinkNotificationConfiguration(const am_sinkID_t sinkID, const am_NotificationConfiguration_s& notificationConfiguration) ;
+    am_Error_e hookUserSetMainSourceNotificationConfiguration(const am_sourceID_t sourceID, const am_NotificationConfiguration_s& notificationConfiguration) ;
+    void hookSystemNodeStateChanged(const NsmNodeState_e NodeStateId) ;
+    void hookSystemNodeApplicationModeChanged(const NsmApplicationMode_e ApplicationModeId) ;
+    void hookSystemSessionStateChanged(const std::string& sessionName, const NsmSeat_e seatID, const NsmSessionState_e sessionStateID) ;
+    NsmErrorStatus_e hookSystemLifecycleRequest(const uint32_t Request, const uint32_t RequestId) ;
+
+
+    am_Error_e CreateConnection(const am_sourceID_t source,
+                                const am_sinkID_t sink,
+                                uint32_t rset, am_mainConnectionID_t &id);
+
+    // These could be MainConnection methods as well...
+    void ExecuteActions();
+    void ExecuteConnect(mctl::MainConnection *conn);
+    void ExecuteDisconnect(mctl::MainConnection *conn);
+    void ExecuteSuspend(mctl::MainConnection *conn);
+    void ExecuteTeardown(mctl::MainConnection *conn);
+    void ExecuteNoOp(mctl::MainConnection *conn);
+
+private:
+    mctl::MurphyInterface *mMif;
+
+    bool ConnectionRoutes(const am_sourceID_t source, const am_sinkID_t sink,
+                          std::vector<am_Route_s> &routes);
+    bool ConnectionExists(const am_sourceID_t source, const am_sinkID_t sink);
+
+    std::string SourceName(const am_sourceID_t source);
+    std::string SinkName(const am_sinkID_t sink);
+
+    void disconnect(am_mainConnectionID_t connectionID);
+    void connect(am_sourceID_t sourceID, am_sinkID_t sinkID, am_mainConnectionID_t mainConnectionID);
+
+    struct handleStatus
+    {
+        bool status;
+        am_Handle_s handle;
+    };
+
+    struct mainConnectionSet
+    {
+        am_mainConnectionID_t connectionID;
+        std::vector<handleStatus> listHandleStaus;
+    };
+
+    struct mainVolumeSet
+    {
+        am_sinkID_t sinkID;
+        am_Handle_s handle;
+        am_mainVolume_t mainVolume;
+    };
+
+    struct mainSinkSoundPropertySet
+    {
+        am_sinkID_t sinkID;
+        am_Handle_s handle;
+        am_MainSoundProperty_s mainSoundProperty;
+    };
+
+    class findHandle
+    {
+        handleStatus mHandle;
+    public:
+        explicit findHandle(handleStatus handle) :
+                mHandle(handle)
+        {
+        }
+        bool operator()(const handleStatus& handle) const
+        {
+            return (handle.handle.handle == mHandle.handle.handle);
+        }
+    };
+
+    struct checkHandle
+    {
+
+        handleStatus mHandleStatus;
+        explicit checkHandle(const handleStatus& value) :
+                mHandleStatus(value)
+        {
+        }
+
+        bool operator()(const handleStatus &value)
+        {
+            return !value.status;
+        }
+    };
+
+    struct checkMainConnectionID
+    {
+        am_MainConnection_s mMainConnection;
+        explicit checkMainConnectionID(const am_MainConnection_s& mainConnection) :
+                mMainConnection(mainConnection)
+        {
+        }
+        bool operator()(const am_MainConnection_s& mainConnection)
+        {
+            if (mMainConnection.mainConnectionID == mainConnection.mainConnectionID)
+                return true;
+            return false;
+        }
+    };
+
+    struct cs_connectData_s
+    {
+        am_mainConnectionID_t currentMainConnection;
+        am_mainConnectionID_t newMainConnection;
+        am_sourceID_t oldSourceID;
+        am_sinkID_t sinkID;
+        am_sourceID_t sourceID;
+    };
+
+    void callStateFlowHandler();
+
+    IAmControlReceive * mControlReceiveInterface;
+
+    std::vector<mainConnectionSet> mListOpenConnections;
+    std::vector<mainConnectionSet> mListOpenDisconnections;
+    std::vector<mainVolumeSet> mListOpenVolumeChanges;
+    std::vector<mainSinkSoundPropertySet> mListMainSoundPropertyChanges;
+
+    cs_connectData_s mConnectData;
+
+    // for creating static pulse sources
+    am_Source_s getIcoSourceData(am_domainID_t domainId);
+    am_Source_s getWrtSourceData(am_domainID_t domainId);
+};
+}
+#endif /* CONTROLSENDERMURPHY_H_ */
diff --git a/PluginControlInterfaceMurphy/include/Connection.h b/PluginControlInterfaceMurphy/include/Connection.h
new file mode 100644 (file)
index 0000000..061ff4c
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __MCTL_CONNECTION_H__
+#define __MCTL_CONNECTION_H__
+
+#include <control/IAmControlSend.h>
+#include <control/IAmControlReceive.h>
+
+#include <map>
+#include <vector>
+
+#include "StateMachine.h"
+
+
+namespace mctl {
+    class MainConnection;
+
+    class DomainConnection {
+        friend class MainConnection;
+
+    public:
+        virtual ~DomainConnection();
+
+        am::am_ConnectionState_e getState();
+
+        static DomainConnection *findDomainConnection(const am::am_connectionID_t connectionID);
+
+    private:
+        DomainConnection(MainConnection *mainConnection,
+                         am::am_RoutingElement_s& routingElement);
+        bool connect();
+        bool disconnect();
+
+        void connectionIsUp();
+        void connectionIsDown();
+
+        bool operator ==(DomainConnection& dconn);
+
+        MainConnection *mMainConnection;
+        am::am_connectionID_t mConnectionID;
+        am::am_Handle_s mHandle;
+        am::am_domainID_t mDomainID;
+        am::am_sourceID_t mSourceID;
+        am::am_sinkID_t mSinkID;
+        am::am_CustomConnectionFormat_t mConnectionFormat;
+        am::am_ConnectionState_e mState;
+
+        static uint16_t getHandle(const am::am_Handle_s& handle);
+        static DomainConnection *findDomainConnection(const am::am_Handle_s& handle);
+
+        static std::map<am::am_connectionID_t, DomainConnection *> mIdMap;
+        static std::map<uint16_t, DomainConnection *> mHandleMap;
+    };
+
+    class MainConnection: public StateMachine {
+        friend class DomainConnection;
+
+    public:
+        MainConnection(const char *name,
+                       am::IAmControlSend *mSender,
+                       am::IAmControlReceive *mReceiver,
+                       am::am_sourceID_t mainSourceID,
+                       am::am_sinkID_t mainSinkID,
+                       uint32_t rsetID = 0);
+        virtual ~MainConnection();
+
+        am::am_mainConnectionID_t getID();
+
+        size_t size();
+        DomainConnection *domainConnection(const size_t index);
+        DomainConnection *operator [](const size_t index);
+
+        bool setupDomainConnections(NewRouteEvent& ev);
+        bool domainConnectionIsUp(DomainConnUpEvent& ev);
+        bool tearDownDomainConnections();
+        bool domainConnectionIsDown(DomainConnDownEvent& ev);
+
+        bool setState(const am::am_ConnectionState_e state);
+
+        static MainConnection *findMainConnection(const am::am_mainConnectionID_t mainConnectionID);
+        static MainConnection *findMainConnection(const am::am_Handle_s& handle);
+
+        // These can be dug out also using size() and [], but still...
+        am::am_sourceID_t mainSourceID() { return mMainSourceID; }
+        am::am_sinkID_t mainSinkID() { return mMainSinkID; }
+
+        uint32_t rsetID() { return mRsetID; }
+        void setRoute(am::am_Route_s &route) { mRoute = route; }
+        void getRoute(am::am_Route_s &route) { route = mRoute; }
+
+    private:
+        am::IAmControlSend *mSender;
+        am::IAmControlReceive *mReceiver;
+
+        am::am_sourceID_t mMainSourceID;
+        am::am_sinkID_t mMainSinkID;
+        uint32_t mRsetID;
+        am::am_mainConnectionID_t mMainConnectionID;
+        am::am_Route_s mRoute;
+
+        std::vector<DomainConnection *> mDomainConnections;
+
+        static std::map<am::am_mainConnectionID_t, MainConnection *>  mIdMap;
+    };
+}
+
+#endif // __MCTL_CONNECTION_H__
diff --git a/PluginControlInterfaceMurphy/include/Event.h b/PluginControlInterfaceMurphy/include/Event.h
new file mode 100644 (file)
index 0000000..c5aed98
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __MCTL_EVENT_H__
+#define __MCTL_EVENT_H__
+
+#include <stdint.h>
+
+#include <audiomanagertypes.h>
+
+#include <ios>
+#include <string>
+#include <vector>
+
+
+namespace mctl {
+
+    typedef enum {
+        EVENT_TYPE_CONNECT = 0,
+        EVENT_TYPE_REMOVE,
+        EVENT_TYPE_DOMAIN_CONN_UP,
+        EVENT_TYPE_DOMAIN_CONN_DOWN,
+        EVENT_TYPE_PLAY,
+        EVENT_TYPE_STOP,
+        EVENT_TYPE_NEW_ROUTE,
+        EVENT_TYPE_NO_ROUTE,
+        EVENT_TYPE_ROUTE_READY,
+        EVENT_TYPE_ROUTE_DELETED,
+        EVENT_TYPE_DONE,
+        EVENT_TYPE_MAX
+    } EventType;
+
+    class Event {
+    public:
+        Event(const Event& ev);
+        virtual ~Event();
+
+        EventType getType();
+
+        operator const char * ();
+
+    protected:
+        Event(EventType type);
+
+        virtual void copyMembers(const Event& ev);
+
+        EventType mType;
+        std::string mString;
+    };
+
+
+    class ConnectEvent: public Event {
+    public:
+        ConnectEvent(std::vector<am::am_Route_s>& routeList);
+        ConnectEvent(const ConnectEvent& ev);
+
+        size_t size();
+        am::am_Route_s& route(const size_t index);
+        am::am_Route_s& operator [](const size_t index);
+
+    private:
+        std::vector<am::am_Route_s> mRouteList;
+    };
+
+    class RemoveEvent: public Event {
+    public:
+        RemoveEvent();
+        RemoveEvent(const RemoveEvent& ev);
+    };
+
+    class DomainConnUpEvent: public Event {
+    public:
+        DomainConnUpEvent(const am::am_Handle_s& handle);
+        DomainConnUpEvent(const DomainConnUpEvent& ev);
+
+        am::am_Handle_s& getHandle();
+
+    private:
+        am::am_Handle_s mHandle;
+    };
+
+    class DomainConnDownEvent: public Event {
+    public:
+        DomainConnDownEvent(const am::am_Handle_s& handle);
+        DomainConnDownEvent(const DomainConnDownEvent& ev);
+
+        am::am_Handle_s& getHandle();
+
+    private:
+        am::am_Handle_s mHandle;
+    };
+
+    class PlayEvent: public Event {
+    public:
+        PlayEvent();
+        PlayEvent(const PlayEvent& ev);
+    };
+
+    class StopEvent: public Event {
+    public:
+        StopEvent();
+        StopEvent(const StopEvent& ev);
+    };
+
+    class NewRouteEvent: public Event {
+    public:
+        NewRouteEvent(const am::am_Route_s& route);
+        NewRouteEvent(const NewRouteEvent& ev);
+
+        am::am_sourceID_t mainSourceID();
+        am::am_sinkID_t mainSinkID();
+
+        size_t size();
+        am::am_RoutingElement_s& routingElement(const size_t index);
+        am::am_RoutingElement_s& operator [](const size_t index);
+
+    private:
+        am::am_sourceID_t mMainSourceID;
+        am::am_sinkID_t mMainSinkID;
+        std::vector<am::am_RoutingElement_s> mRoute;
+    };
+
+    class NoRouteEvent: public Event {
+    public:
+        NoRouteEvent();
+        NoRouteEvent(const NoRouteEvent& ev);
+    };
+
+    class RouteReadyEvent: public Event {
+    public:
+        RouteReadyEvent();
+        RouteReadyEvent(const RouteReadyEvent& ev);
+    };
+
+    class RouteDeletedEvent: public Event {
+    public:
+        RouteDeletedEvent();
+        RouteDeletedEvent(const RouteDeletedEvent& ev);
+    };
+
+    class DoneEvent: public Event {
+    public:
+        DoneEvent();
+        DoneEvent(const DoneEvent& ev);
+    };
+
+
+}
+
+#endif // __MCTL_EVENT_H__
diff --git a/PluginControlInterfaceMurphy/include/MurphyInterface.h b/PluginControlInterfaceMurphy/include/MurphyInterface.h
new file mode 100644 (file)
index 0000000..0b51c9b
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * XXX TODO: add an appropriate copyright and license notice
+ */
+
+#ifndef MURPHYINTERFACE_H_
+#define MURPHYINTERFACE_H_
+
+#include <murphy/common/mainloop.h>
+#include <murphy/domain-control/client.h>
+
+#include "config.h"
+#include "shared/CAmSocketHandler.h"
+#include "control/IAmControlReceive.h"
+#include "control/IAmControlSend.h"
+#include "MurphyMainloop.h"
+#include "Connection.h"
+
+namespace am {
+  class CAmControlSenderMurphy;
+}
+
+namespace mctl
+{
+  class MurphyInterface;
+
+  class MurphyInterface
+  {
+  public:
+    static void setSocketHandler(am::CAmSocketHandler *socketHandler);
+    static MurphyInterface *getMurphyInterface();
+    void setControlReceiver(am::IAmControlReceive *receiver);
+    void setControlSender(am::CAmControlSenderMurphy *sender);
+
+    virtual ~MurphyInterface();
+
+  private:
+    MurphyInterface();
+
+    void CreateMainloop();
+    void CreateDomainController();
+    void DestroyMainloop();
+    void DestroyDomainController();
+    bool RegisterDomainFunctions();
+
+    static am::CAmSocketHandler *mSocketHandler;
+    static MurphyInterface *mMurphyInterface;
+    am::IAmControlReceive *mControlReceiver;
+    am::CAmControlSenderMurphy *mControlSender;
+    mrp_mainloop_t *mMainloop;
+    mrp_domctl_t *mDomCtl;
+
+    static void DomainConnectionCB(mrp_domctl_t *ctl, int connected, int errcode,
+                                   const char *errmsg, void *user_data);
+    static void DataImportCB(mrp_domctl_t *ctl, mrp_domctl_data_t *tables,
+                             int ntable, void *user_data);
+    static void DataExportCB(mrp_domctl_t *ctl, int errcode, const char *errmsg,
+                             void *user_data);
+
+  public:
+    void ScheduleSinkAndSourceUpdate();
+    void CancelSinkAndSourceUpdate();
+    void ExportSinksAndSources();
+    bool ConnectSourceToSink(am::am_sourceID_t source, am::am_sinkID_t sink,
+                             uint32_t rset, am::am_mainConnectionID_t & conn);
+    void ExpectSinkAndSourceChanges(bool more);
+
+  private:
+    mrp_timer_t *mSsuTimer;
+    bool         mSsuExpectMore;
+
+  public:
+    bool RequestRoute(MainConnection *conn, std::vector<am::am_Route_s> routes);
+bool NotifyDisconnect(MainConnection *conn);
+
+    void ProcessRouteRequestReply(MainConnection *conn,
+                                  uint16_t *path, size_t len);
+
+  private:
+    mrp_domctl_data_t *mTables;
+    int                mNtable;
+
+  public:
+    enum Decision {
+      DECISION_TEARDOWN,
+      DECISION_NOOP,
+      DECISION_DISCONNECT,
+      DECISION_CONNECT,
+      DECISION_SUSPEND
+    };
+
+
+    void SetDecisions(mrp_domctl_data_t *tables, int ntable);
+    void ClearDecisions();
+
+    Decision Verdict(MainConnection *conn);
+  };
+}
+
+#endif /* MURPHYINTERFACE_H_ */
diff --git a/PluginControlInterfaceMurphy/include/MurphyMainloop.h b/PluginControlInterfaceMurphy/include/MurphyMainloop.h
new file mode 100644 (file)
index 0000000..f5b7334
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * XXX TODO: add suitable license and copyright
+ */
+
+#ifndef MURPHY_MAINLOOP_H_
+#define MURPHY_MAINLOOP_H_
+
+#include <string>
+#include <list>
+#include <map>
+#include "config.h"
+#include "shared/CAmSocketHandler.h"
+
+#include <murphy/common/mainloop.h>
+
+using namespace am;
+
+namespace mctl
+{
+
+  class MurphyMainloop
+  {
+  public:
+    virtual ~MurphyMainloop();
+    static mrp_mainloop_t *getMurphyMainloop(CAmSocketHandler *sh);
+    mrp_mainloop_t *get_mainloop() { return m_ml; };
+
+    void *addIO(int fd, int16_t events, void *iop);
+    void delIO(void *handlep);
+    void *addTimer(unsigned int msecs, void *tp);
+    void delTimer(void *tp);
+    void modTimer(unsigned int msecs, void *handlep);
+    void *addDefer(void *tp);
+    void delDefer(void *tp);
+
+  private:
+    MurphyMainloop(CAmSocketHandler *sh);
+
+    CAmSocketHandler *m_sh;
+    mrp_mainloop_t   *m_ml;
+
+    bool registerMainloop();
+    void unregisterMainloop();
+
+    TAmShPollPrepare<MurphyMainloop> m_io_prepare_cb;
+    TAmShPollCheck<MurphyMainloop> m_io_check_cb;
+    TAmShPollFired<MurphyMainloop> m_io_fire_cb;
+    TAmShPollDispatch<MurphyMainloop> m_io_dispatch_cb;
+    TAmShTimerCallBack<MurphyMainloop> m_timer_cb;
+    TAmShTimerCallBack<MurphyMainloop> m_defer_cb;
+
+    void ioPrepareCB(const sh_pollHandle_t h, void* userData);
+    bool ioCheckCB(const sh_pollHandle_t h, void *userData);
+    void ioFireCB(const pollfd pfd, const sh_pollHandle_t h, void *userData);
+    bool ioDispatchCB(const sh_pollHandle_t h, void *userData);
+    void timerCB(sh_timerHandle_t h, void *userData);
+    void deferCB(sh_timerHandle_t h, void *userData);
+
+    void registerLogger();
+  };
+}
+
+#endif /* MURPHY_MAINLOOP_H_ */
diff --git a/PluginControlInterfaceMurphy/include/StateMachine.h b/PluginControlInterfaceMurphy/include/StateMachine.h
new file mode 100644 (file)
index 0000000..2d01b08
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __MCTL_STATE_MACHINE_H__
+#define __MCTL_STATE_MACHINE_H__
+
+#include "Event.h"
+
+#include <list>
+
+
+namespace mctl {
+    class StateMachine;
+    class Transition;
+
+    typedef enum {
+        STATE_START = 0,
+        STATE_INITIAL_CONNECT,
+        STATE_CONNECTING,
+        STATE_CONNECTED,
+        STATE_SUSPENDED,
+        STATE_DISCONNECTING,
+        STATE_DISCONNECTED,
+        STATE_REROUTE,
+        STATE_REMOVE,
+        STATE_END,
+        STATE_MAX
+    } StateId;
+
+    class StateMachine {
+    public:
+        StateMachine(const char *name);
+        ~StateMachine();
+
+        void queueEvent(Event& event);
+        const char *getName();
+        StateId getStateID();
+        void setCanPlay(bool canPlay) { mCanPlay = canPlay; }
+        bool getCanPlay() { return mCanPlay; }
+
+        operator const char * (); // prints the state name
+
+        static void freeTransitions();
+
+    private:
+        void processEvents();
+
+        std::string mName;
+        bool mBusy;
+        StateId mStateID;
+        bool mCanPlay;
+        std::list<Event *> mQueue;
+
+        static Transition *mTransitions[int(STATE_MAX)][int(EVENT_TYPE_MAX)];
+    };
+}
+
+#endif // __MCTL_STATE_MACHINE_H__
diff --git a/PluginControlInterfaceMurphy/include/Transition.h b/PluginControlInterfaceMurphy/include/Transition.h
new file mode 100644 (file)
index 0000000..500a858
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __MCTL_TRANSITION_H__
+#define __MCTL_TRANSITION_H__
+
+#include <stdbool.h>
+
+#include <list>
+
+#include "StateMachine.h"
+
+namespace mctl {
+    typedef bool (*TransitionFunction)(StateMachine& sm, Event& ev);
+    typedef bool (*ConditionFunction)(StateMachine& sm, Event& ev);
+
+    class Transition {
+    public:
+        virtual ~Transition();
+
+        operator const char * ();
+
+        virtual StateId function(StateMachine &sm, Event &ev);
+
+    protected:
+        Transition();
+
+        std::string mString;
+    };
+
+    class NoTransition: public Transition {
+    public:
+        NoTransition();
+
+        virtual StateId function(StateMachine& sm, Event& ev);
+    };
+
+    class DirectTransition: public Transition {
+    public:
+        DirectTransition(StateId nextState);
+
+        virtual StateId function(StateMachine &sm, Event &ev);
+
+    private:
+        StateId mNextState;
+    };
+
+
+    class BasicTransition: public Transition {
+    public:
+        BasicTransition(StateId nextState,
+                        TransitionFunction function,
+                        const char *functionName);
+
+        virtual StateId function(StateMachine &sm, Event &ev);
+
+    private:
+        StateId mNextState;
+        TransitionFunction mFunction;
+    };
+
+
+    class AlternativeTransition {
+    public:
+        AlternativeTransition(ConditionFunction condition,
+                              StateId nextState);
+        AlternativeTransition(ConditionFunction condition,
+                              StateId nextState,
+                              TransitionFunction function,
+                              const char *functionName);
+
+        virtual ~AlternativeTransition();
+
+        operator const char * ();
+
+        bool function(StateMachine& sm, Event& ev, StateId& nextState);
+
+    private:
+        ConditionFunction mCondition;
+        Transition *mTransition;
+    };
+
+
+    class ConditionalTransition: public Transition {
+    public:
+        ConditionalTransition(std::list<AlternativeTransition *> *alternatives);
+        virtual ~ConditionalTransition();
+
+        virtual StateId function(StateMachine& sm, Event& ev);
+
+    private:
+        std::list<AlternativeTransition *> *mAlternatives;
+    };
+}
+
+#endif // __MCTL_TRANSITION_H__
diff --git a/PluginControlInterfaceMurphy/include/TransitionRoutines.h b/PluginControlInterfaceMurphy/include/TransitionRoutines.h
new file mode 100644 (file)
index 0000000..859071d
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __MCTL_TRANSITION_ROUTINES_H__
+#define __MCTL_TRANSITION_ROUTINES_H__
+
+#include "Transition.h"
+
+namespace mctl {
+    //
+    // Condition functions
+    //
+    bool CanPlay(StateMachine& sm, Event& ev);
+    bool CannotPlay(StateMachine& sm, Event& ev);
+
+    //
+    // Transition routines
+    //
+    bool RouteAndPlaybackRequest(StateMachine& sm, Event& ev);
+    bool RouteAndPlaybackRelease(StateMachine& sm, Event& ev);
+    bool SavePlaybackGrant(StateMachine& sm, Event& ev);
+
+    bool SetupDomainConnections(StateMachine& sm, Event& ev);
+    bool TearDownDomainConnections(StateMachine& sm, Event& ev);
+    bool DomainConnectionIsUp(StateMachine& sm, Event& ev);
+    bool DomainConnectionIsDown(StateMachine& sm, Event& ev);
+
+    bool FinishMainConnection(StateMachine& sm, Event& ev);
+    bool ConnectMainConnection(StateMachine& sm, Event& ev);
+    bool SuspendMainConnection(StateMachine& sm, Event& ev);
+    bool ResumeMainConnection(StateMachine& sm, Event& ev);
+    bool DisconnectMainConnection(StateMachine& sm, Event& ev);
+
+    bool FinishAndConnectMainConnection(StateMachine& sm, Event& ev);
+    bool FinishAndSuspendMainConnection(StateMachine& sm, Event& ev);
+    bool FinishAndDisconnectMainConnection(StateMachine& sm, Event& ev);
+
+    bool MarkPlay(StateMachine& sm, Event& ev);
+}
+
+#endif // __MCTL_TRANSITION_ROUTINES_H__
diff --git a/PluginControlInterfaceMurphy/src/CAmControlSenderMurphy.cpp b/PluginControlInterfaceMurphy/src/CAmControlSenderMurphy.cpp
new file mode 100644 (file)
index 0000000..c060ef8
--- /dev/null
@@ -0,0 +1,1224 @@
+/**
+ * XXX TODO: add an appropriate copyright and license notice
+ */
+
+#include <sstream>
+
+#include <cassert>
+#include <algorithm>
+
+#include <murphy/common/debug.h>
+
+#include "CAmControlSenderMurphy.h"
+#include "shared/CAmDltWrapper.h"
+#include "control/IAmControlReceive.h"
+
+#include "Connection.h"
+#include "MurphyInterface.h"
+
+#define AM_UNUSED(var) (void)var
+
+#define FUNCTION   __FUNCTION__, "(): "
+#define LOCATION   __FILE__, ":", __LINE__, " "
+#define WHERE      ""
+
+#define INFO(...)  log(&MRPC, DLT_LOG_INFO , WHERE, __VA_ARGS__)
+#define ERROR(...) log(&MRPC, DLT_LOG_ERROR, WHERE, __VA_ARGS__)
+#define WARN(...)  log(&MRPC, DLT_LOG_WARN , WHERE, __VA_ARGS__)
+#define DEBUG(...) mrp_debug(__VA_ARGS__)
+
+namespace am
+{
+  DLT_DECLARE_CONTEXT(MRPC)
+
+  extern "C" IAmControlSend* PluginControlInterfaceMurphyFactory()
+  {
+    CAmDltWrapper::instance()->registerContext(MRPC, "MRPC",
+                                               "Murphy Control Interface");
+    return (new CAmControlSenderMurphy());
+  }
+
+  extern "C" void destroyControlPluginInterface(IAmControlSend* csif)
+  {
+    delete csif;
+  }
+
+  CAmControlSenderMurphy::CAmControlSenderMurphy() :
+    mMif(NULL),
+    mControlReceiveInterface(NULL)
+  {
+  }
+
+  CAmControlSenderMurphy::~CAmControlSenderMurphy()
+  {
+  }
+
+  am_Error_e CAmControlSenderMurphy::startupController(IAmControlReceive *crif)
+  {
+    CAmSocketHandler *handler;
+    am_Error_e err;
+
+    INFO("Starting Murphy control interface");
+
+    assert(crif);
+    mControlReceiveInterface = crif;
+
+    if ((err = crif->getSocketHandler(handler)) != E_OK)
+      return err;
+
+    mctl::MurphyInterface::setSocketHandler(handler);
+    mMif = mctl::MurphyInterface::getMurphyInterface();
+    assert(mMif);
+
+    mMif->setControlReceiver(mControlReceiveInterface);
+    mMif->setControlSender(this);
+
+    return E_OK;
+  }
+
+  void CAmControlSenderMurphy::setControllerReady()
+  {
+    INFO("Setting Murphy control interface ready");
+
+    //here is a good place to insert Source and SinkClasses into the database...
+    mControlReceiveInterface->setRoutingReady();
+    mControlReceiveInterface->setCommandReady();
+  }
+
+
+    am_Source_s CAmControlSenderMurphy::getIcoSourceData(am_domainID_t domainID)
+  {
+    am_Source_s sourceData;
+    am_SoundProperty_s soundProperty;
+    am_CustomConnectionFormat_t connectionFormat;
+    am_MainSoundProperty_s mainSoundProperty;
+
+    sourceData.sourceID = 0;
+    sourceData.domainID = domainID;
+    sourceData.name = "icoApplication";
+    sourceData.sourceClassID = 67;
+    sourceData.sourceState = am::SS_UNKNNOWN;
+    sourceData.volume = 32767;
+    sourceData.visible = true;
+    sourceData.available.availability = am::A_AVAILABLE;
+    sourceData.available.availabilityReason = am::AR_UNKNOWN;
+    sourceData.interruptState = am::IS_OFF;
+
+    soundProperty.type = am::SP_GENIVI_TREBLE;
+    soundProperty.value = 0;
+    sourceData.listSoundProperties.push_back(soundProperty);
+    soundProperty.type = am::SP_GENIVI_MID;
+    soundProperty.value = 0;
+    sourceData.listSoundProperties.push_back(soundProperty);
+
+    connectionFormat = am::CF_GENIVI_MONO;
+    sourceData.listConnectionFormats.push_back(connectionFormat);
+
+    mainSoundProperty.type = am::MSP_GENIVI_TREBLE;
+    mainSoundProperty.value = 0;
+    sourceData.listMainSoundProperties.push_back(mainSoundProperty);
+    mainSoundProperty.type = am::MSP_GENIVI_MID;
+    mainSoundProperty.value = 0;
+    sourceData.listMainSoundProperties.push_back(mainSoundProperty);
+
+    return (sourceData);
+  }
+
+  am_Source_s CAmControlSenderMurphy::getWrtSourceData(am_domainID_t domainID)
+  {
+    am_Source_s sourceData;
+    am_SoundProperty_s soundProperty;
+    am_CustomConnectionFormat_t connectionFormat;
+    am_MainSoundProperty_s mainSoundProperty;
+
+    sourceData.sourceID = 0;
+    sourceData.domainID = domainID;
+    sourceData.name = "wrtApplication";
+    sourceData.sourceClassID = 67;
+    sourceData.sourceState = am::SS_UNKNNOWN;
+    sourceData.volume = 32767;
+    sourceData.visible = true;
+    sourceData.available.availability = am::A_AVAILABLE;
+    sourceData.available.availabilityReason = am::AR_UNKNOWN;
+    sourceData.interruptState = IS_OFF;
+
+    soundProperty.type = am::SP_GENIVI_TREBLE;
+    soundProperty.value = 0;
+    sourceData.listSoundProperties.push_back(soundProperty);
+    soundProperty.type = am::SP_GENIVI_MID;
+    soundProperty.value = 0;
+    sourceData.listSoundProperties.push_back(soundProperty);
+
+    connectionFormat = am::CF_GENIVI_MONO;
+    sourceData.listConnectionFormats.push_back(connectionFormat);
+
+    mainSoundProperty.type = am::MSP_GENIVI_TREBLE;
+    mainSoundProperty.value = 0;
+    sourceData.listMainSoundProperties.push_back(mainSoundProperty);
+    mainSoundProperty.type = am::MSP_GENIVI_MID;
+    mainSoundProperty.value = 0;
+    sourceData.listMainSoundProperties.push_back(mainSoundProperty);
+
+    return (sourceData);
+  }
+
+  void CAmControlSenderMurphy::ExecuteConnect(mctl::MainConnection *conn)
+  {
+    am::am_Route_s route;
+
+    INFO("Executing connect for connection ", conn->getID());
+
+    conn->getRoute(route);
+
+    std::vector<am::am_Route_s> routes;
+    routes.push_back(route);
+
+    mctl::ConnectEvent connect(routes);
+
+    conn->queueEvent(connect);
+
+    mctl::PlayEvent play;
+
+    conn->queueEvent(play);
+
+    if (conn->getStateID() == mctl::STATE_END)
+      delete conn;
+  }
+
+  void CAmControlSenderMurphy::ExecuteDisconnect(mctl::MainConnection *conn)
+  {
+    mctl::RemoveEvent disconnect;
+
+    INFO("Executing disconnect for connection ", conn->getID());
+
+    mMif->NotifyDisconnect(conn);
+    conn->queueEvent(disconnect);
+
+    if (conn->getStateID() == mctl::STATE_END)
+      delete conn;
+  }
+
+  void CAmControlSenderMurphy::ExecuteSuspend(mctl::MainConnection *conn)
+  {
+    mctl::StopEvent stop;
+
+    INFO("Executing suspend (stop) for connection ", conn->getID());
+
+    conn->queueEvent(stop);
+
+    if (conn->getStateID() == mctl::STATE_END)
+      delete conn;
+  }
+
+  void CAmControlSenderMurphy::ExecuteNoOp(mctl::MainConnection *conn)
+  {
+    INFO("Executing NoOp (<not yet>) for connection ", conn->getID());
+  }
+
+  void CAmControlSenderMurphy::ExecuteTeardown(mctl::MainConnection *conn)
+  {
+    mctl::RemoveEvent evt;
+
+    INFO("Executing teardown for connection ", conn->getID());
+
+    mMif->NotifyDisconnect(conn);
+    conn->queueEvent(evt);
+
+    if (conn->getStateID() == mctl::STATE_END)
+      delete conn;
+  }
+
+  void CAmControlSenderMurphy::ExecuteActions()
+  {
+    std::vector<am_MainConnection_s> connections;
+    mctl::MainConnection *conn;
+
+    INFO("Executing policy actions");
+
+    mControlReceiveInterface->getListMainConnections(connections);
+
+    std::vector<am_MainConnection_s>::iterator c(connections.begin());
+    while (c != connections.end()) {
+      INFO("Checking disconnect/teardown/suspend for connection ",
+           c->mainConnectionID);
+
+      conn = mctl::MainConnection::findMainConnection(c->mainConnectionID);
+
+      if (conn != NULL) {
+        switch (mMif->Verdict(conn)) {
+        case mctl::MurphyInterface::DECISION_DISCONNECT:
+          ExecuteDisconnect(conn);
+          break;
+        case mctl::MurphyInterface::DECISION_TEARDOWN:
+          ExecuteTeardown(conn);
+          break;
+        case mctl::MurphyInterface::DECISION_SUSPEND:
+          ExecuteSuspend(conn);
+          break;
+        case mctl::MurphyInterface::DECISION_CONNECT:
+          break;
+        case mctl::MurphyInterface::DECISION_NOOP:
+          ExecuteNoOp(conn);
+          break;
+        }
+      }
+
+      c++;
+    }
+
+    c = connections.begin();
+    while (c != connections.end()) {
+      INFO("Checking connect for connection ", c->mainConnectionID);
+
+      conn = mctl::MainConnection::findMainConnection(c->mainConnectionID);
+
+      if (conn != NULL) {
+        switch (mMif->Verdict(conn)) {
+        case mctl::MurphyInterface::DECISION_CONNECT:
+          ExecuteConnect(conn);
+          break;
+        case mctl::MurphyInterface::DECISION_DISCONNECT:
+          break;
+        case mctl::MurphyInterface::DECISION_TEARDOWN:
+          break;
+        case mctl::MurphyInterface::DECISION_SUSPEND:
+          break;
+        }
+      }
+
+      c++;
+    }
+  }
+
+
+  bool CAmControlSenderMurphy::ConnectionRoutes(const am_sourceID_t source,
+                                                const am_sinkID_t sink,
+                                                std::vector<am_Route_s> &routes)
+  {
+    mControlReceiveInterface->getRoute(false, source, sink, routes);
+
+    return !routes.empty();
+  }
+
+
+  bool CAmControlSenderMurphy::ConnectionExists(const am_sourceID_t source,
+                                                const am_sinkID_t sink)
+  {
+    std::vector<am_MainConnection_s> existing;
+    mControlReceiveInterface->getListMainConnections(existing);
+
+    std::vector<am_MainConnection_s>::iterator conn(existing.begin());
+    while (conn != existing.end()) {
+      if (conn->sinkID == sink && conn->sourceID == source)
+        return true;
+
+      conn++;
+    }
+
+    return false;
+  }
+
+
+  std::string CAmControlSenderMurphy::SourceName(const am_sourceID_t source)
+  {
+    std::vector<am_Source_s> sources;
+    std::ostringstream ostr;
+    std::string name;
+
+    if (mControlReceiveInterface->getListSources(sources) == E_OK) {
+      std::vector<am_Source_s>::iterator s(sources.begin());
+
+      while (s != sources.end()) {
+        if (s->sourceID == source)
+          return s->name;
+
+        s++;
+      }
+    }
+
+    ostr << source;
+    name = ostr.str();
+
+    return name;
+  }
+
+
+  std::string CAmControlSenderMurphy::SinkName(const am_sinkID_t sink)
+  {
+    std::vector<am_Sink_s> sinks;
+    std::ostringstream ostr;
+    std::string name;
+
+    if (mControlReceiveInterface->getListSinks(sinks) == E_OK) {
+      std::vector<am_Sink_s>::iterator s(sinks.begin());
+
+      while (s != sinks.end()) {
+        if (s->sinkID == sink)
+          return s->name;
+
+        s++;
+      }
+    }
+
+    ostr << sink;
+    name = ostr.str();
+
+    return name;
+  }
+
+
+  am_Error_e CAmControlSenderMurphy::CreateConnection(const am_sourceID_t source,
+                                                      const am_sinkID_t sink,
+                                                      uint32_t rset,
+                                                      am_mainConnectionID_t &id)
+  {
+      mctl::MainConnection *conn;
+
+      std::vector<am_MainConnection_s> connections;
+      std::vector<am_Route_s> routes;
+      std::ostringstream name;
+
+      INFO("CreateConnection: ", source, " -> ", sink);
+
+      if (ConnectionExists(source, sink))
+        return E_ALREADY_EXISTS;
+
+      if (!ConnectionRoutes(source, sink, routes))
+        return E_NOT_POSSIBLE;
+
+      name << SourceName(source) << " ->" << SinkName(sink);
+
+      conn = new mctl::MainConnection(name.str().c_str(),
+                                      static_cast<IAmControlSend *>(this),
+                                      mControlReceiveInterface, source, sink,
+                                      rset);
+
+      id = conn->getID();
+
+      if (!mMif->RequestRoute(conn, routes)) {
+        delete conn;
+        return E_UNKNOWN;
+      }
+
+      return E_OK;
+  }
+
+
+  am_Error_e CAmControlSenderMurphy::hookUserConnectionRequest(const am_sourceID_t sourceID, const am_sinkID_t sinkID, am_mainConnectionID_t & mainConnectionID)
+  {
+
+
+
+    return CreateConnection(sourceID, sinkID, 0, mainConnectionID);
+
+
+
+#if 0
+      std::vector<am_connectionID_t> listConnectionIDs;
+      std::vector<am_MainConnection_s> listAllMainConnections;
+      std::vector<am_Route_s> listRoutes;
+      std::vector<am_Source_s> listSources;
+      std::vector<am_Sink_s> listSinks;
+      std::ostringstream name;
+      am_Error_e err;
+      bool found;
+
+      INFO("User connection request: ", sourceID, " -> ", sinkID);
+
+      mControlReceiveInterface->getRoute(false, sourceID, sinkID, listRoutes);
+      if (listRoutes.empty())
+          return (E_NOT_POSSIBLE);
+
+      mControlReceiveInterface->getListMainConnections(listAllMainConnections);
+
+      std::vector<am_MainConnection_s>::iterator itAll(listAllMainConnections.begin());
+      for (; itAll != listAllMainConnections.end(); ++itAll)
+          {
+              if (itAll->sinkID == sinkID && itAll->sourceID == sourceID)
+                  return (E_ALREADY_EXISTS);
+          }
+
+
+      if ((err = mControlReceiveInterface->getListSources(listSources)) != E_OK)
+          return err;
+      else {
+          std::vector<am_Source_s>::iterator it(listSources.begin());
+          for (found = false; it != listSources.end();  ++it) {
+              if (sourceID == it->sourceID) {
+                  found = true;
+                  name << it->name;
+                  break;
+              }
+          }
+      }
+      if (!found)
+          name << sourceID;
+
+      name << "->";
+
+      if ((err = mControlReceiveInterface->getListSinks(listSinks)) != E_OK)
+          return err;
+      else {
+          std::vector<am_Sink_s>::iterator it(listSinks.begin());
+          for (found = false; it != listSinks.end();  ++it) {
+              if (sinkID == it->sinkID) {
+                  found = true;
+                  name << it->name;
+                  break;
+              }
+          }
+      }
+      if (!found)
+          name << sinkID;
+
+      mctl::MainConnection *conn = new mctl::MainConnection(name.str().c_str(),
+                                                            static_cast<IAmControlSend *>(this),
+                                                            mControlReceiveInterface,
+                                                            sourceID,
+                                                            sinkID);
+      mainConnectionID = conn->getID();
+
+#if 0
+      mctl::ConnectEvent connev(listRoutes);
+      conn->queueEvent(connev);
+
+      if (conn->getStateID() == mctl::STATE_END)
+          delete conn;
+#else
+      if (!mMif->RequestRoute(conn, listRoutes)) {
+        delete conn;
+        return E_UNKNOWN;
+      }
+#endif
+
+      return (E_OK);
+#endif
+  }
+
+
+  am_Error_e CAmControlSenderMurphy::hookUserDisconnectionRequest(const am_mainConnectionID_t connectionID)
+  {
+      mctl::MainConnection *conn = mctl::MainConnection::findMainConnection(connectionID);
+      mctl::RemoveEvent remev;
+
+      INFO("User disconnect request for connection ", connectionID);
+
+      if (conn == NULL) {
+        ERROR("can't find connection ", connectionID);
+        return E_NON_EXISTENT;
+      }
+
+      mMif->NotifyDisconnect(conn);
+      conn->queueEvent(remev);
+
+      if (conn->getStateID() == mctl::STATE_END)
+          delete conn;
+
+      return (E_OK);
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetMainSinkSoundProperty(const am_sinkID_t sinkID, const am_MainSoundProperty_s & soundProperty)
+  {
+    AM_UNUSED(sinkID);
+    AM_UNUSED(soundProperty);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetMainSourceSoundProperty(const am_sourceID_t sourceID, const am_MainSoundProperty_s & soundProperty)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(soundProperty);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetSystemProperty(const am_SystemProperty_s & property)
+  {
+    AM_UNUSED(property);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserVolumeChange(const am_sinkID_t sinkID, const am_mainVolume_t newVolume)
+  {
+    assert(sinkID!=0);
+    mainVolumeSet set;
+    set.sinkID = sinkID;
+    set.mainVolume = newVolume;
+    am_Error_e error;
+
+    std::vector<mainVolumeSet>::iterator it(mListOpenVolumeChanges.begin());
+    for (; it != mListOpenVolumeChanges.end(); ++it)
+    {
+        if (it->sinkID == sinkID)
+            return E_NOT_POSSIBLE;
+    }
+
+    am_Sink_s sinkData;
+    mControlReceiveInterface->getSinkInfoDB(sinkID, sinkData);
+
+    if (sinkData.mainVolume == newVolume)
+        return E_NO_CHANGE;
+
+    if ((error = mControlReceiveInterface->setSinkVolume(set.handle, sinkID, (newVolume-10)*6, RAMP_UNKNOWN, 20)) != E_OK)
+    {
+        return error;
+    }
+    mListOpenVolumeChanges.push_back(set);
+    return E_OK;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserVolumeStep(const am_sinkID_t sinkID, const int16_t increment)
+  {
+    assert(sinkID!=0);
+    mainVolumeSet set;
+    set.sinkID = sinkID;
+    am_Error_e error;
+    am_Sink_s sink;
+    std::vector<mainVolumeSet>::iterator it(mListOpenVolumeChanges.begin());
+    for (; it != mListOpenVolumeChanges.end(); ++it)
+    {
+        if (it->sinkID == sinkID)
+            return E_NOT_POSSIBLE;
+    }
+    mControlReceiveInterface->getSinkInfoDB(sinkID, sink);
+    set.mainVolume = sink.mainVolume + increment;
+    if ((error = mControlReceiveInterface->setSinkVolume(set.handle, sinkID, (set.mainVolume-10)*6, RAMP_UNKNOWN, 20)) != E_OK)
+    {
+        return error;
+    }
+    mListOpenVolumeChanges.push_back(set);
+    return E_OK;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetSinkMuteState(const am_sinkID_t sinkID, const am_MuteState_e muteState)
+  {
+    assert(sinkID!=0);
+
+    mainVolumeSet set;
+    set.sinkID = sinkID;
+    am_Error_e error;
+    am_Sink_s sink;
+    mControlReceiveInterface->getSinkInfoDB(sinkID, sink);
+
+    if (muteState == MS_MUTED)
+    {
+        set.mainVolume = sink.mainVolume;
+        if ((error = mControlReceiveInterface->setSinkVolume(set.handle, sinkID, 0, RAMP_GENIVI_DIRECT, 20)) != E_OK)
+        {
+            return error;
+        }
+    }
+    else
+    {
+        set.mainVolume = sink.mainVolume;
+        if ((error = mControlReceiveInterface->setSinkVolume(set.handle, sinkID, set.mainVolume, RAMP_GENIVI_DIRECT, 20)) != E_OK)
+        {
+            return error;
+        }
+    }
+    mListOpenVolumeChanges.push_back(set);
+    mControlReceiveInterface->changeSinkMuteStateDB(muteState, sinkID);
+    return (E_OK);
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemRegisterDomain(const am_Domain_s & domainData, am_domainID_t & domainID)
+  {
+    am_Error_e error;
+
+    error = mControlReceiveInterface->enterDomainDB(domainData, domainID);
+
+    DEBUG("domain %s register%s as %u", domainData.name.c_str(),
+          domainData.complete ? "ed" : "ing", domainID);
+
+    if (error == E_OK && domainData.name == "PULSE") {
+      am_sourceID_t sourceID = 0;
+      am_Source_s sourceDataIco(getIcoSourceData(domainID));
+      am_Source_s sourceDataWrt(getWrtSourceData(domainID));
+
+      error = mControlReceiveInterface->enterSourceDB(sourceDataIco, sourceID);
+
+      if (!error)
+        DEBUG("domain %u registered static source '%s' as %u",
+              sourceDataIco.domainID, sourceDataIco.name.c_str(), sourceID);
+      else
+        DEBUG("domain %u failed to register static source '%s'",
+              sourceDataIco.domainID, sourceDataIco.name.c_str());
+
+      error = mControlReceiveInterface->enterSourceDB(sourceDataWrt, sourceID);
+
+      if (!error)
+        DEBUG("domain %u registered static source '%s' as %u",
+              sourceDataWrt.domainID, sourceDataWrt.name.c_str(), sourceID);
+      else
+        DEBUG("domain %u failed to register static source '%s'",
+              sourceDataWrt.domainID, sourceDataWrt.name.c_str());
+    }
+
+    mMif->ExpectSinkAndSourceChanges(true);
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemDeregisterDomain(const am_domainID_t domainID)
+  {
+    am_Error_e error;
+
+    error = mControlReceiveInterface->removeDomainDB(domainID);
+
+    DEBUG("domain %u deregistered", domainID);
+
+    return error;
+  }
+
+  void CAmControlSenderMurphy::hookSystemDomainRegistrationComplete(const am_domainID_t domainID)
+  {
+    DEBUG("registration of domain %u complete", domainID);
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemRegisterSink(const am_Sink_s & sinkData, am_sinkID_t & sinkID)
+  {
+    am_Error_e error;
+
+    error = mControlReceiveInterface->enterSinkDB(sinkData, sinkID);
+
+    if (!error)
+      DEBUG("domain %u registered sink '%s' as %u", sinkData.domainID,
+            sinkData.name.c_str(), sinkID);
+    else
+      DEBUG("domain %u failed to register sink '%s'", sinkData.domainID,
+            sinkData.name.c_str());
+
+    mMif->ScheduleSinkAndSourceUpdate();
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemDeregisterSink(const am_sinkID_t sinkID)
+  {
+    am_Error_e error;
+    std::vector<am_connectionID_t> listConnectionIDs;
+    std::vector<am_MainConnection_s> listAllMainConnections;
+    bool found = false;
+
+    mControlReceiveInterface->getListMainConnections(listAllMainConnections);
+
+    /* find possible connection */
+    std::vector<am_MainConnection_s>::iterator itAll(listAllMainConnections.begin());
+    for (; itAll != listAllMainConnections.end(); ++itAll)
+    {
+        if (itAll->sinkID == sinkID) {
+            found = true;
+            break;
+        }
+    }
+
+    if (found)
+        mControlReceiveInterface->removeMainConnectionDB(itAll->mainConnectionID);
+
+    error = mControlReceiveInterface->removeSinkDB(sinkID);
+
+    if (!error)
+      DEBUG("sink %u deregistered", sinkID);
+    else
+      DEBUG("deregistration of sink %u failed", sinkID);
+
+    mMif->ScheduleSinkAndSourceUpdate();
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemRegisterSource(const am_Source_s & sourceData, am_sourceID_t & sourceID)
+  {
+    am_Error_e error;
+    std::vector<am_Source_s> listSourcesShadowDarknessOfScorchedEarth;
+
+    mControlReceiveInterface->getListSources(listSourcesShadowDarknessOfScorchedEarth);
+
+    std::vector<am_Source_s>::iterator itAll(listSourcesShadowDarknessOfScorchedEarth.begin());
+    for (; itAll != listSourcesShadowDarknessOfScorchedEarth.end(); ++itAll)
+    {
+        if (itAll->name == sourceData.name) {
+            sourceID = itAll->sourceID;
+            mControlReceiveInterface->changeSourceAvailabilityDB(sourceData.available, sourceID);
+            mMif->ScheduleSinkAndSourceUpdate();
+            return E_OK;
+        }
+    }
+
+    error = mControlReceiveInterface->enterSourceDB(sourceData, sourceID);
+
+    if (!error)
+      DEBUG("domain %u registered source '%s' as %u", sourceData.domainID,
+            sourceData.name.c_str(), sourceID);
+    else
+      DEBUG("domain %u failed to register source '%s'", sourceData.domainID,
+            sourceData.name.c_str());
+
+    mMif->ScheduleSinkAndSourceUpdate();
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemDeregisterSource(const am_sourceID_t sourceID)
+  {
+    am_Error_e error;
+    std::vector<am_connectionID_t> listConnectionIDs;
+    std::vector<am_MainConnection_s> listAllMainConnections;
+    bool found = false;
+    am_Availability_s available = {A_UNAVAILABLE, AR_GENIVI_NOMEDIA};
+
+    mControlReceiveInterface->getListMainConnections(listAllMainConnections);
+
+    /* find possible connection */
+    std::vector<am_MainConnection_s>::iterator itAll(listAllMainConnections.begin());
+    for (; itAll != listAllMainConnections.end(); ++itAll)
+    {
+        if (itAll->sourceID == sourceID) {
+            found = true;
+            break;
+        }
+    }
+
+    /*
+    if (found)
+        mControlReceiveInterface->removeMainConnectionDB(itAll->mainConnectionID);
+    */
+
+    /* error = mControlReceiveInterface->removeSourceDB(sourceID); */
+    error = mControlReceiveInterface->changeSourceAvailabilityDB(available, sourceID);
+
+    if (!error)
+      DEBUG("source %u deregistered", sourceID);
+    else
+      DEBUG("deregistration of source %u failed", sourceID);
+
+    mMif->ScheduleSinkAndSourceUpdate();
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemRegisterGateway(const am_Gateway_s & gatewayData, am_gatewayID_t & gatewayID)
+  {
+    am_Error_e error;
+
+    error = mControlReceiveInterface->enterGatewayDB(gatewayData, gatewayID);
+
+    DEBUG("domain '%s' registered as %u", gatewayData.name.c_str(), gatewayID);
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemDeregisterGateway(const am_gatewayID_t gatewayID)
+  {
+    am_Error_e error;
+
+    error = mControlReceiveInterface->removeGatewayDB(gatewayID);
+
+    if (!error)
+      DEBUG("gateway %u deregistered", gatewayID);
+    else
+      DEBUG("failed to deregister gateway %u", gatewayID);
+
+    return error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemRegisterCrossfader(const am_Crossfader_s & crossfaderData, am_crossfaderID_t & crossfaderID)
+  {
+    return mControlReceiveInterface->enterCrossfaderDB(crossfaderData, crossfaderID);
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemDeregisterCrossfader(const am_crossfaderID_t crossfaderID)
+  {
+    return mControlReceiveInterface->removeCrossfaderDB(crossfaderID);
+  }
+
+  void CAmControlSenderMurphy::hookSystemSinkVolumeTick(const am_Handle_s handle, const am_sinkID_t sinkID, const am_volume_t volume)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(sinkID);
+    AM_UNUSED(volume);
+  }
+
+  void CAmControlSenderMurphy::hookSystemSourceVolumeTick(const am_Handle_s handle, const am_sourceID_t sourceID, const am_volume_t volume)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(sourceID);
+    AM_UNUSED(volume);
+  }
+
+  void CAmControlSenderMurphy::hookSystemInterruptStateChange(const am_sourceID_t sourceID, const am_InterruptState_e interruptState)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(interruptState);
+  }
+
+  void CAmControlSenderMurphy::hookSystemSinkAvailablityStateChange(const am_sinkID_t sinkID, const am_Availability_s & availability)
+  {
+    INFO("sink ", sinkID, " is now ",
+         availability.availability != A_AVAILABLE ? "unavailable" : "available");
+
+    mMif->ScheduleSinkAndSourceUpdate();
+  }
+
+  void CAmControlSenderMurphy::hookSystemSourceAvailablityStateChange(const am_sourceID_t sourceID, const am_Availability_s & availability)
+  {
+    INFO("source ", sourceID, " is now ",
+         availability.availability != A_AVAILABLE ? "unavailable" : "available");
+
+    mMif->ScheduleSinkAndSourceUpdate();
+  }
+
+  void CAmControlSenderMurphy::hookSystemDomainStateChange(const am_domainID_t domainID, const am_DomainState_e state)
+  {
+    AM_UNUSED(domainID);
+    AM_UNUSED(state);
+  }
+
+  void CAmControlSenderMurphy::hookSystemReceiveEarlyData(const std::vector<am_EarlyData_s> & data)
+  {
+    AM_UNUSED(data);
+  }
+
+  void CAmControlSenderMurphy::hookSystemSpeedChange(const am_speed_t speed)
+  {
+    AM_UNUSED(speed);
+  }
+  void CAmControlSenderMurphy::hookSystemTimingInformationChanged(const am_mainConnectionID_t mainConnectionID, const am_timeSync_t time)
+  {
+    AM_UNUSED(mainConnectionID);
+    AM_UNUSED(time);
+  }
+
+  void CAmControlSenderMurphy::cbAckConnect(const am_Handle_s handle, const am_Error_e errorID)
+  {
+    AM_UNUSED(errorID);
+
+    mctl::MainConnection *conn = mctl::MainConnection::findMainConnection(handle);
+
+    if (!conn) {
+      ERROR("CAmControlSenderMurphy::cbAckConnect: can't find connection for handle ", handle.handleType, "/", handle.handle);
+      return;
+    }
+
+    mctl::DomainConnUpEvent upev(handle);
+    conn->queueEvent(upev);
+  }
+
+  void CAmControlSenderMurphy::cbAckDisconnect(const am_Handle_s handle, const am_Error_e errorID)
+  {
+    AM_UNUSED(errorID);
+
+    mctl::MainConnection *conn = mctl::MainConnection::findMainConnection(handle);
+
+    if (!conn) {
+      ERROR("CAmControlSenderMurphy::cbAckDisconnect: can't find connection for handle ", handle.handleType, "/", handle.handle);
+      return;
+    }
+
+    mctl::DomainConnDownEvent downev(handle);
+    conn->queueEvent(downev);
+
+    if (conn->getStateID() == mctl::STATE_END)
+      delete conn;
+  }
+
+  void CAmControlSenderMurphy::cbAckCrossFade(const am_Handle_s handle, const am_HotSink_e hostsink, const am_Error_e error)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(hostsink);
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSinkVolumeChange(const am_Handle_s handle, const am_volume_t volume, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+    AM_UNUSED(volume);
+    //\todo:error checking
+    std::vector<mainVolumeSet>::iterator it(mListOpenVolumeChanges.begin());
+    for (; it != mListOpenVolumeChanges.end(); ++it)
+    {
+        if (handle.handle == it->handle.handle)
+        {
+            mControlReceiveInterface->changeSinkMainVolumeDB(it->mainVolume, it->sinkID);
+            mListOpenVolumeChanges.erase(it);
+            break;
+        }
+    }
+
+    callStateFlowHandler();
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSourceVolumeChange(const am_Handle_s handle, const am_volume_t volume, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+    AM_UNUSED(volume);
+    AM_UNUSED(handle);
+
+    callStateFlowHandler();
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSourceState(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+    AM_UNUSED(handle);
+
+    callStateFlowHandler();
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSourceSoundProperty(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+    AM_UNUSED(handle);
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSinkSoundProperty(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+
+    //\todo:error checking
+    std::vector<mainSinkSoundPropertySet>::iterator it(mListMainSoundPropertyChanges.begin());
+    for (; it != mListMainSoundPropertyChanges.end(); ++it)
+    {
+        if (handle.handle == it->handle.handle)
+        {
+            mControlReceiveInterface->changeMainSinkSoundPropertyDB(it->mainSoundProperty, it->sinkID);
+            mListMainSoundPropertyChanges.erase(it);
+            break;
+        }
+    }
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSourceSoundProperties(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(error);
+    AM_UNUSED(handle);
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSinkSoundProperties(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::setControllerRundown(const int16_t signal)
+  {
+    INFO("Shutting down Murphy control interface");
+
+    mctl::StateMachine::freeTransitions();
+
+    mControlReceiveInterface->confirmControllerRundown(E_OK);
+  }
+
+  am_Error_e CAmControlSenderMurphy::getConnectionFormatChoice(const am_sourceID_t sourceID, const am_sinkID_t sinkID, const am_Route_s listRoute, const std::vector<am_CustomConnectionFormat_t> listPossibleConnectionFormats, std::vector<am_CustomConnectionFormat_t> & listPrioConnectionFormats)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(sinkID);
+    AM_UNUSED(listRoute);
+
+    listPrioConnectionFormats = listPossibleConnectionFormats;
+
+    return E_OK;
+  }
+
+  void CAmControlSenderMurphy::getInterfaceVersion(std::string & version) const
+  {
+    version = ControlSendVersion;
+  }
+
+
+  void CAmControlSenderMurphy::disconnect(am_mainConnectionID_t connectionID)
+  {
+    am_MainConnection_s mainConnection;
+    am_Error_e error;
+    std::vector<handleStatus> listHandleStaus;
+    mainConnectionSet set;
+
+    if ((error = mControlReceiveInterface->getMainConnectionInfoDB(connectionID, mainConnection)) != E_OK)
+    {
+      ERROR("getInfo for connection ", connectionID, " failed (", error, ")");
+      return;
+    }
+
+    std::vector<am_connectionID_t>::iterator it(mainConnection.listConnectionID.begin());
+
+    for (; it != mainConnection.listConnectionID.end(); ++it)
+    {
+        handleStatus status;
+        status.status = false;
+        if ((error = mControlReceiveInterface->disconnect(status.handle, *it)))
+        {
+          ERROR("Could not disconnect (error: ", error, ")");
+        }
+        listHandleStaus.push_back(status);
+    }
+
+    set.connectionID = connectionID;
+    set.listHandleStaus = listHandleStaus;
+    mListOpenDisconnections.push_back(set);
+  }
+
+  void CAmControlSenderMurphy::connect(am_sourceID_t sourceID, am_sinkID_t sinkID, am_mainConnectionID_t mainConnectionID)
+  {
+    std::vector<am_Route_s> listRoutes;
+    std::vector<am_connectionID_t> listConnectionIDs;
+    am_Handle_s handle;
+    std::vector<handleStatus> listHandleStaus;
+    mainConnectionSet set;
+
+    mControlReceiveInterface->getRoute(false, sourceID, sinkID, listRoutes);
+
+    if (listRoutes.empty())
+      ERROR("No routes, connect not possible.");
+
+    std::vector<am_RoutingElement_s>::iterator it(listRoutes[0].route.begin());
+
+    for (; it != listRoutes[0].route.end(); ++it)
+    {
+        am_connectionID_t connectionID;
+        mControlReceiveInterface->connect(handle, connectionID, it->connectionFormat, it->sourceID, it->sinkID);
+        handleStatus status;
+        status.handle = handle;
+        status.status = false;
+        listHandleStaus.push_back(status);
+        listConnectionIDs.push_back(connectionID);
+    }
+
+    set.connectionID = mainConnectionID;
+    set.listHandleStaus = listHandleStaus;
+    mControlReceiveInterface->changeMainConnectionRouteDB(mainConnectionID,listConnectionIDs);
+    mListOpenConnections.push_back(set);
+  }
+
+  void CAmControlSenderMurphy::callStateFlowHandler()
+  {
+  }
+
+  void CAmControlSenderMurphy::confirmCommandReady(const am_Error_e error)
+  {
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::confirmRoutingReady(const am_Error_e error)
+  {
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::confirmCommandRundown(const am_Error_e error)
+  {
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::confirmRoutingRundown(const am_Error_e error)
+  {
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::hookSystemNodeStateChanged(const NsmNodeState_e NodeStateId)
+  {
+    AM_UNUSED(NodeStateId);
+  }
+
+  void CAmControlSenderMurphy::hookSystemNodeApplicationModeChanged(const NsmApplicationMode_e ApplicationModeId)
+  {
+    AM_UNUSED(ApplicationModeId);
+  }
+
+
+  void CAmControlSenderMurphy::cbAckSetSinkNotificationConfiguration(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::cbAckSetSourceNotificationConfiguration(const am_Handle_s handle, const am_Error_e error)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(error);
+  }
+
+
+  NsmErrorStatus_e CAmControlSenderMurphy::hookSystemLifecycleRequest(const uint32_t Request, const uint32_t RequestId)
+  {
+    AM_UNUSED(Request);
+    AM_UNUSED(RequestId);
+
+    return NsmErrorStatus_Error;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemUpdateSink(const am_sinkID_t sinkID, const am_sinkClass_t sinkClassID, const std::vector<am_SoundProperty_s>& listSoundProperties, const std::vector<am_CustomConnectionFormat_t>& listConnectionFormats, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties)
+  {
+    AM_UNUSED(sinkID);
+    AM_UNUSED(sinkClassID);
+    AM_UNUSED(listMainSoundProperties);
+    AM_UNUSED(listConnectionFormats);
+    AM_UNUSED(listSoundProperties);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemUpdateSource(const am_sourceID_t sourceID, const am_sourceClass_t sourceClassID, const std::vector<am_SoundProperty_s>& listSoundProperties, const std::vector<am_CustomConnectionFormat_t>& listConnectionFormats, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(sourceClassID);
+    AM_UNUSED(listMainSoundProperties);
+    AM_UNUSED(listConnectionFormats);
+    AM_UNUSED(listSoundProperties);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookSystemUpdateGateway(const am_gatewayID_t gatewayID, const std::vector<am_CustomConnectionFormat_t>& listSourceConnectionFormats, const std::vector<am_CustomConnectionFormat_t>& listSinkConnectionFormats, const std::vector<bool>& convertionMatrix)
+  {
+    AM_UNUSED(gatewayID);
+    AM_UNUSED(listSourceConnectionFormats);
+    AM_UNUSED(listSinkConnectionFormats);
+    AM_UNUSED(convertionMatrix);
+
+    return E_NOT_USED;
+  }
+
+  void CAmControlSenderMurphy::cbAckSetVolumes(const am_Handle_s handle, const std::vector<am_Volumes_s>& listVolumes, const am_Error_e error)
+  {
+    AM_UNUSED(handle);
+    AM_UNUSED(listVolumes);
+    AM_UNUSED(error);
+  }
+
+  void CAmControlSenderMurphy::hookSinkNotificationDataChanged(const am_sinkID_t sinkID, const am_NotificationPayload_s& payload)
+  {
+    AM_UNUSED(sinkID);
+    AM_UNUSED(payload);
+  }
+
+  void CAmControlSenderMurphy::hookSourceNotificationDataChanged(const am_sourceID_t sourceID, const am_NotificationPayload_s& payload)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(payload);
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetMainSinkNotificationConfiguration(const am_sinkID_t sinkID, const am_NotificationConfiguration_s& notificationConfiguration)
+  {
+    AM_UNUSED(sinkID);
+    AM_UNUSED(notificationConfiguration);
+
+    return E_NOT_USED;
+  }
+
+  am_Error_e CAmControlSenderMurphy::hookUserSetMainSourceNotificationConfiguration(const am_sourceID_t sourceID, const am_NotificationConfiguration_s& notificationConfiguration)
+  {
+    AM_UNUSED(sourceID);
+    AM_UNUSED(notificationConfiguration);
+
+    return E_NOT_USED;
+  }
+
+  void CAmControlSenderMurphy::hookSystemSessionStateChanged(const std::string& sessionName, const NsmSeat_e seatID, const NsmSessionState_e sessionStateID)
+  {
+    AM_UNUSED(sessionName);
+    AM_UNUSED(seatID);
+    AM_UNUSED(sessionStateID);
+  }
+
+}
diff --git a/PluginControlInterfaceMurphy/src/Connection.cpp b/PluginControlInterfaceMurphy/src/Connection.cpp
new file mode 100644 (file)
index 0000000..f71f2bc
--- /dev/null
@@ -0,0 +1,358 @@
+#include <iostream>
+
+#include "Connection.h"
+
+
+using namespace mctl;
+
+
+std::map<am::am_mainConnectionID_t, MainConnection *>  MainConnection::mIdMap;
+std::map<am::am_connectionID_t, DomainConnection *>  DomainConnection::mIdMap;
+std::map<uint16_t, DomainConnection *> DomainConnection::mHandleMap;
+
+DomainConnection::DomainConnection(MainConnection *mainConnection,
+                                   am::am_RoutingElement_s& routingElement):
+    mMainConnection(mainConnection),
+    mConnectionID(0),
+    mDomainID(routingElement.domainID),
+    mSourceID(routingElement.sourceID),
+    mSinkID(routingElement.sinkID),
+    mConnectionFormat(routingElement.connectionFormat),
+    mState(am::CS_UNKNOWN)
+{
+    std::cout << mainConnection->getName() << ": setting up domain connection "
+              << mSourceID << "->" << mSinkID
+              << std::endl;
+
+    mHandle.handleType = am::H_UNKNOWN;
+    mHandle.handle = 0;
+
+    if (connect())
+        mIdMap[mConnectionID] = this;
+}
+
+DomainConnection::~DomainConnection()
+{
+    uint16_t handle = getHandle(mHandle);
+
+    mIdMap.erase(mConnectionID);
+
+    std::cout << mMainConnection->getName() << ": destroying connection "
+              << mConnectionID << " ("<< mSourceID << "->" << mSinkID << ")"
+              << std::endl;
+
+    if (handle > 0) {
+        mMainConnection->mReceiver->abortAction(mHandle);
+        mHandleMap.erase(handle);
+    }
+
+
+    if (mConnectionID > 0) {
+        disconnect();
+    }
+}
+
+uint16_t DomainConnection::getHandle(const am::am_Handle_s& h)
+{
+    if (h.handle > 0) {
+        return (uint16_t(h.handleType) & 0x003f) << 10 |
+               (uint16_t(h.handle) & 0x03ff);
+    }
+
+    return 0;
+}
+
+am::am_ConnectionState_e DomainConnection::getState()
+{
+    return mState;
+}
+
+
+bool DomainConnection::operator ==(DomainConnection& dcon)
+{
+    return mConnectionID == dcon.mConnectionID;
+}
+
+
+bool DomainConnection::connect()
+{
+    am::IAmControlReceive *receiver = mMainConnection->mReceiver;
+    bool success = true;
+
+    if (mState != am::CS_UNKNOWN) {
+        std::cout << mMainConnection->getName()
+                  << "subsequent connection request for connection "
+                  << mConnectionID << " (" << mSourceID << "->" << mSinkID << ")"
+                  << std::endl;
+        success = false;
+    }
+    else {
+        am::am_Error_e err = receiver->connect(mHandle, mConnectionID,
+                                               mConnectionFormat,
+                                               mSourceID, mSinkID);
+        if (err != am::E_OK) {
+            std::cout << mMainConnection->getName() << ": failed to connect ("
+                      << mSourceID << "->" << mSinkID << ")"
+                      << std::endl;
+
+            mState = am::CS_UNKNOWN;
+            mHandle.handle = 0;
+            mConnectionID = 0;
+
+            success = false;
+        }
+        else {
+            mState = am::CS_CONNECTING;
+            mHandleMap[getHandle(mHandle)] = this;
+        }
+    }
+
+    return success;
+}
+
+bool DomainConnection::disconnect()
+{
+    am::IAmControlReceive *receiver = mMainConnection->mReceiver;
+    bool success = true;
+    uint16_t handle = getHandle(mHandle);
+
+    if (handle > 0) {
+        std::cout << mMainConnection->getName()
+                  << ": aborting pending operation on connection "
+                  << mConnectionID << "(" << mSourceID << "->" << mSinkID << ")"
+                  << std::endl;
+        receiver->abortAction(mHandle);
+        mHandle.handle = 0;
+        mHandleMap.erase(handle);
+    }
+
+    if (mConnectionID > 0 && mState == am::CS_CONNECTED) {
+        std::cout << mMainConnection->getName() << ": disconnecting connection "
+                  << mConnectionID << "(" << mSourceID << "->" << mSinkID << ")"
+                  << std::endl;
+        am::am_Error_e err = receiver->disconnect(mHandle, mConnectionID);
+
+        if (err != am::E_OK) {
+            std::cout << mMainConnection->getName()
+                      << "disconnect request failed: error " << err
+                      << std::endl;
+
+            if (mConnectionID > 0)
+                mIdMap.erase(mConnectionID);
+
+            mState = am::CS_UNKNOWN;
+            mHandle.handle = 0;
+            mConnectionID = 0;
+
+            success = false;
+        }
+        else {
+            mState = am::CS_DISCONNECTING;
+            mHandleMap[getHandle(mHandle)] = this;
+        }
+    }
+
+    return success;
+}
+
+
+void DomainConnection::connectionIsUp()
+{
+    if (mState != am::CS_CONNECTING) {
+        std::cout << mMainConnection->getName() << ": attempt to finalise connection "
+                  << mConnectionID << " when not in connecting state" << std::endl;
+    }
+    else {
+        mState = am::CS_CONNECTED;
+
+        std::cout << mMainConnection->getName() << ": connection "
+                  << mConnectionID << " is up" << std::endl;
+    }
+
+    if (mHandle.handle > 0) {
+        mHandleMap.erase(getHandle(mHandle));
+        mHandle.handle = 0;
+    }
+}
+
+void DomainConnection::connectionIsDown()
+{
+    if (mState != am::CS_DISCONNECTING) {
+        std::cout << mMainConnection->getName() << ": attempt to dismantle connection "
+                  << mConnectionID << " when not in disconnecting state" << std::endl;
+    }
+    else {
+        mState = am::CS_DISCONNECTED;
+
+        std::cout << mMainConnection->getName() << ": connection "
+                  << mConnectionID << " is down" << std::endl;
+    }
+
+    if (mHandle.handle > 0) {
+        mHandleMap.erase(getHandle(mHandle));
+        mHandle.handle = 0;
+    }
+}
+
+bool MainConnection::setState(const am::am_ConnectionState_e state)
+{
+    am::am_Error_e err = mReceiver->changeMainConnectionStateDB(mMainConnectionID, state);
+
+    if (err != am::E_OK) {
+        std::cout << getName() << ": failed to set state " << state << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+
+DomainConnection *DomainConnection::findDomainConnection(const am::am_connectionID_t connectionID)
+{
+    return mIdMap[connectionID];
+}
+
+DomainConnection *DomainConnection::findDomainConnection(const am::am_Handle_s& handle)
+{
+    uint16_t h = getHandle(handle);
+
+    if (h > 0)
+        return mHandleMap[h];
+
+    return NULL;
+}
+
+
+MainConnection::MainConnection(const char *name,
+                               am::IAmControlSend *sender,
+                               am::IAmControlReceive *receiver,
+                               const am::am_sourceID_t mainSourceID,
+                               const am::am_sinkID_t mainSinkID,
+                               uint32_t rsetID) :
+    StateMachine(name),
+    mSender(sender),
+    mReceiver(receiver),
+    mMainSourceID(mainSourceID),
+    mMainSinkID(mainSinkID),
+    mRsetID(rsetID),
+    mMainConnectionID(0)
+{
+    am::am_MainConnection_s connData;
+
+    connData.mainConnectionID = 0;
+    connData.sinkID = mMainSinkID;
+    connData.sourceID = mMainSourceID;
+    connData.connectionState = am::CS_CONNECTING;
+    connData.delay = 0;
+
+    mReceiver->enterMainConnectionDB(connData, mMainConnectionID);
+
+    mIdMap[mMainConnectionID] = this;
+}
+
+
+MainConnection::~MainConnection()
+{
+    std::cout << getName() << ": main connection " << mMainConnectionID
+              << " is going to be destroyed" << std::endl;
+
+    mReceiver->removeMainConnectionDB(mMainConnectionID);
+
+    for (size_t i = 0;  i < mDomainConnections.size();   i++)
+        delete mDomainConnections[i];
+
+    mIdMap.erase(mMainConnectionID);
+}
+
+
+am::am_mainConnectionID_t MainConnection::getID()
+{
+    return mMainConnectionID;
+}
+
+size_t MainConnection::size()
+{
+    return mDomainConnections.size();
+}
+
+DomainConnection * MainConnection::domainConnection(const size_t index)
+{
+    if (index < mDomainConnections.size())
+        return mDomainConnections[index];
+
+    return NULL;
+}
+
+DomainConnection * MainConnection::operator [](const size_t index)
+{
+    return domainConnection(index);
+}
+
+bool MainConnection::setupDomainConnections(NewRouteEvent& ev)
+{
+    if (!mDomainConnections.empty()) {
+        std::cout << __FUNCTION__ << "(): refuse to deal with NewRoute request for existing main connection" << std::endl;
+        return false;
+    }
+
+    for (size_t i = 0;  i < ev.size();   i++)
+        mDomainConnections.push_back(new DomainConnection(this, ev[i]));
+
+    return true;
+}
+
+bool MainConnection::domainConnectionIsUp(DomainConnUpEvent& ev)
+{
+    DomainConnection *domainConnection = DomainConnection::findDomainConnection(ev.getHandle());
+
+    domainConnection->connectionIsUp();
+
+    return true;
+}
+
+
+bool MainConnection::tearDownDomainConnections()
+{
+    if (mDomainConnections.empty()) {
+        std::cout << __FUNCTION__ << "(): refuse to deal with teardown request for main connection" << std::endl;
+        return false;
+    }
+
+    for (size_t i = 0;  i < mDomainConnections.size();   i++)
+        mDomainConnections[i]->disconnect();
+
+    return true;
+}
+
+bool MainConnection::domainConnectionIsDown(DomainConnDownEvent& ev)
+{
+    DomainConnection *domainConnection = DomainConnection::findDomainConnection(ev.getHandle());
+
+    std::vector<DomainConnection *>::iterator it = mDomainConnections.begin();
+    for (;  it != mDomainConnections.end();  it++) {
+        if (*domainConnection == **it) {
+            (*it)->connectionIsDown();
+            mDomainConnections.erase(it);
+            delete domainConnection;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+
+MainConnection *MainConnection::findMainConnection(const am::am_mainConnectionID_t mainConnectionID)
+{
+    return mIdMap[mainConnectionID];
+}
+
+MainConnection *MainConnection::findMainConnection(const am::am_Handle_s& handle)
+{
+    DomainConnection *domainConnection = DomainConnection::findDomainConnection(handle);
+
+    if (domainConnection != NULL)
+        return domainConnection->mMainConnection;
+
+    return NULL;
+}
diff --git a/PluginControlInterfaceMurphy/src/Event.cpp b/PluginControlInterfaceMurphy/src/Event.cpp
new file mode 100644 (file)
index 0000000..0a098e5
--- /dev/null
@@ -0,0 +1,253 @@
+#include <iostream>
+#include <sstream>
+
+#include <audiomanagertypes.h>
+
+#include "Event.h"
+
+using namespace mctl;
+
+Event::Event(EventType type)
+{
+    mType = type;
+}
+
+Event::Event(const Event& ev)
+{
+    copyMembers(ev);
+}
+
+
+Event::~Event()
+{
+}
+
+void Event::copyMembers(const Event& ev)
+{
+    mType = ev.mType;
+    mString = ev.mString;
+}
+
+
+EventType Event::getType()
+{
+    return mType;
+}
+
+
+Event::operator const char * ()
+{
+    return mString.c_str();
+}
+
+
+ConnectEvent::ConnectEvent(std::vector<am::am_Route_s>& routeList):
+    Event(EVENT_TYPE_CONNECT),
+    mRouteList(routeList)
+{
+    mString = "Connect";
+}
+
+ConnectEvent::ConnectEvent(const ConnectEvent& ev):
+    Event(ev)
+{
+    mRouteList = ev.mRouteList;
+}
+
+size_t ConnectEvent::size()
+{
+    return mRouteList.size();
+}
+
+am::am_Route_s& ConnectEvent::route(const size_t index)
+{
+    static am::am_Route_s emptyRoute;
+
+    if (index >= mRouteList.size())
+        return emptyRoute;
+
+    return mRouteList[index];
+}
+
+am::am_Route_s& ConnectEvent::operator [](const size_t index)
+{
+    return route(index);
+}
+
+RemoveEvent::RemoveEvent():
+    Event(EVENT_TYPE_REMOVE)
+{
+    mString = "Remove";
+}
+
+RemoveEvent::RemoveEvent(const RemoveEvent& ev):
+    Event(ev)
+{
+}
+
+DomainConnUpEvent::DomainConnUpEvent(const am::am_Handle_s& handle):
+    Event(EVENT_TYPE_DOMAIN_CONN_UP),
+    mHandle(handle)
+{
+    mString = "Domain Connection Up";
+}
+
+DomainConnUpEvent::DomainConnUpEvent(const DomainConnUpEvent& ev):
+    Event(ev)
+{
+    mHandle = ev.mHandle;
+}
+
+am::am_Handle_s& DomainConnUpEvent::getHandle()
+{
+    return mHandle;
+}
+
+
+DomainConnDownEvent::DomainConnDownEvent(const am::am_Handle_s& handle):
+    Event(EVENT_TYPE_DOMAIN_CONN_DOWN),
+    mHandle(handle)
+{
+    mString = "Domain Connection Down";
+}
+
+DomainConnDownEvent::DomainConnDownEvent(const DomainConnDownEvent& ev):
+    Event(ev)
+{
+    mHandle = ev.mHandle;
+}
+
+am::am_Handle_s& DomainConnDownEvent::getHandle()
+{
+    return mHandle;
+}
+
+PlayEvent::PlayEvent():
+    Event(EVENT_TYPE_PLAY)
+{
+    mString = "Play";
+}
+
+PlayEvent::PlayEvent(const PlayEvent& ev):
+    Event(ev)
+{
+}
+
+StopEvent::StopEvent():
+    Event(EVENT_TYPE_STOP)
+{
+    mString = "Stop";
+}
+
+StopEvent::StopEvent(const StopEvent& ev):
+    Event(ev)
+{
+}
+
+NewRouteEvent::NewRouteEvent(const am::am_Route_s& route):
+    Event(EVENT_TYPE_NEW_ROUTE)
+{
+    std::ostringstream str;
+
+    mMainSourceID = route.sourceID;
+    mMainSinkID = route.sinkID;
+    mRoute = route.route;
+
+    str << "New Route (" << mMainSourceID << ", " << mMainSinkID << ", [";
+    for (size_t i = 0;  i < size();   i++) {
+        am::am_RoutingElement_s rtel = mRoute[i];
+        if (i > 0)
+            str << ",";
+        str << rtel.sourceID << "->" << rtel.sinkID << "@" << rtel.domainID;
+    }
+    str << "])";
+
+    mString = str.str();
+}
+
+NewRouteEvent::NewRouteEvent(const NewRouteEvent& ev):
+    Event(ev)
+{
+    mMainSourceID = ev.mMainSourceID;
+    mMainSinkID = ev.mMainSinkID;
+    mRoute = ev.mRoute;
+}
+
+
+am::am_sourceID_t NewRouteEvent::mainSourceID()
+{
+    return mMainSourceID;
+}
+
+am::am_sinkID_t NewRouteEvent::mainSinkID()
+{
+    return mMainSinkID;
+}
+
+size_t NewRouteEvent::size()
+{
+    return mRoute.size();
+}
+
+am::am_RoutingElement_s& NewRouteEvent::routingElement(const size_t index)
+{
+    static am::am_RoutingElement_s emptyRoute;
+
+    if (index >= mRoute.size())
+        return emptyRoute;
+
+    return mRoute[index];
+}
+
+
+am::am_RoutingElement_s& NewRouteEvent::operator [](const size_t index)
+{
+    return routingElement(index);
+}
+
+
+NoRouteEvent::NoRouteEvent():
+    Event(EVENT_TYPE_NO_ROUTE)
+{
+    mString = "No Route";
+}
+
+NoRouteEvent::NoRouteEvent(const NoRouteEvent& ev):
+    Event(ev)
+{
+}
+
+RouteReadyEvent::RouteReadyEvent():
+    Event(EVENT_TYPE_ROUTE_READY)
+{
+    mString = "Route Ready";
+}
+
+RouteReadyEvent::RouteReadyEvent(const RouteReadyEvent& ev):
+    Event(ev)
+{
+}
+
+RouteDeletedEvent::RouteDeletedEvent():
+    Event(EVENT_TYPE_ROUTE_DELETED)
+{
+    mString = "Route Deleted";
+}
+
+RouteDeletedEvent::RouteDeletedEvent(const RouteDeletedEvent& ev):
+    Event(ev)
+{
+}
+
+DoneEvent::DoneEvent():
+    Event(EVENT_TYPE_DONE)
+{
+    mString = "Done";
+}
+
+DoneEvent::DoneEvent(const DoneEvent& ev):
+    Event(ev)
+{
+}
+
+
diff --git a/PluginControlInterfaceMurphy/src/MurphyInterface.cpp b/PluginControlInterfaceMurphy/src/MurphyInterface.cpp
new file mode 100644 (file)
index 0000000..25a2b5e
--- /dev/null
@@ -0,0 +1,719 @@
+/**
+ * XXX TODO: add an appropriate copyright and license notice
+ */
+
+#include <cassert>
+#include <sstream>
+
+#include <murphy/common/log.h>
+#include <murphy/common/mm.h>
+
+#include "CAmControlSenderMurphy.h"
+
+#include "MurphyInterface.h"
+#include "Connection.h"
+
+//
+// tables we export to and import from Murphy
+//
+#define AM_SINK_TABLE_ID   0
+#define AM_SINK_TABLE     "audio_manager_sinks"
+#define AM_SINK_NCOLUMN    4
+#define AM_SINK_COLUMNS   "id        integer    ," \
+                          "name      varchar(32)," \
+                          "available integer    ," \
+                          "visible   integer     "
+#define AM_SINK_INDEX     "id"
+
+#define AM_SOURCE_TABLE_ID 1
+#define AM_SOURCE_TABLE   "audio_manager_sources"
+#define AM_SOURCE_NCOLUMN  4
+#define AM_SOURCE_COLUMNS "id        integer    ," \
+                          "name      varchar(32)," \
+                          "available integer    ," \
+                          "visible   integer     "
+#define AM_SOURCE_INDEX   "id"
+
+#define PLAYBACK_TABLE_ID  0
+#define PLAYBACK_TABLE     "audio_playback_users"
+#define PLAYBACK_COLUMNS   "rsetid,source_id,sink_id,connid,decision"
+#define PLAYBACK_RSETID    0
+#define PLAYBACK_CONNID    3
+#define PLAYBACK_VERDICT   4
+#define PLAYBACK_SELECT    NULL
+
+#define RECORDING_TABLE_ID 1
+#define RECORDING_TABLE    "audio_recording_users"
+#define RECORDING_COLUMNS  "rsetid,source_id,sink_id,connid,decision"
+#define RECORDING_CONNID   3
+#define RECORDING_VERDICT  4
+#define RECORDING_SELECT   NULL
+
+using namespace mctl;
+
+am::CAmSocketHandler *MurphyInterface::mSocketHandler = NULL;
+MurphyInterface *MurphyInterface::mMurphyInterface = NULL;
+
+
+/* static */
+void MurphyInterface::setSocketHandler(am::CAmSocketHandler *socketHandler)
+{
+  assert(mSocketHandler == NULL);
+  assert(socketHandler != NULL);
+
+  MurphyInterface::mSocketHandler = socketHandler;
+}
+
+
+/* static */
+MurphyInterface *MurphyInterface::getMurphyInterface()
+{
+  if (mMurphyInterface == NULL)
+    mMurphyInterface = new MurphyInterface();
+
+  return mMurphyInterface;
+}
+
+
+void MurphyInterface::setControlReceiver(am::IAmControlReceive *receiver)
+{
+  mControlReceiver = receiver;
+}
+
+
+void MurphyInterface::setControlSender(am::CAmControlSenderMurphy *sender)
+{
+  mControlSender = sender;
+}
+
+
+MurphyInterface::MurphyInterface()
+  : mControlReceiver(NULL),
+    mControlSender(NULL),
+    mMainloop(NULL),
+    mDomCtl(NULL),
+    mSsuTimer(NULL),
+    mSsuExpectMore(false)
+{
+  assert(mSocketHandler != NULL);
+  CreateMainloop();
+  assert(mMainloop != NULL);
+  CreateDomainController();
+  RegisterDomainFunctions();
+}
+
+
+MurphyInterface::~MurphyInterface()
+{
+  CancelSinkAndSourceUpdate();
+  DestroyDomainController();
+  DestroyMainloop();
+}
+
+
+void MurphyInterface::CreateMainloop()
+{
+  assert(mSocketHandler != NULL);
+
+  mMainloop = MurphyMainloop::getMurphyMainloop(mSocketHandler);
+}
+
+
+void MurphyInterface::DestroyMainloop()
+{
+  MurphyMainloop::getMurphyMainloop(NULL);
+  mMainloop = NULL;
+}
+
+
+void MurphyInterface::CreateDomainController()
+{
+  mrp_domctl_table_t tables[] = {
+    MRP_DOMCTL_TABLE(AM_SINK_TABLE, AM_SINK_COLUMNS, AM_SINK_INDEX),
+    MRP_DOMCTL_TABLE(AM_SOURCE_TABLE, AM_SOURCE_COLUMNS, AM_SOURCE_INDEX)
+  };
+  int ntable = MRP_ARRAY_SIZE(tables);
+  mrp_domctl_watch_t watches[] = {
+    MRP_DOMCTL_WATCH(PLAYBACK_TABLE , PLAYBACK_COLUMNS , PLAYBACK_SELECT , 0),
+    MRP_DOMCTL_WATCH(RECORDING_TABLE, RECORDING_COLUMNS, RECORDING_SELECT, 0),
+  };
+  int nwatch = MRP_ARRAY_SIZE(watches);
+
+  mDomCtl = mrp_domctl_create("audio-manager", mMainloop,
+                              tables, ntable, watches, nwatch,
+                              &MurphyInterface::DomainConnectionCB,
+                              &MurphyInterface::DataImportCB,
+                              (void *)this);
+
+  assert(mDomCtl != NULL);
+  assert(mrp_domctl_connect(mDomCtl, MRP_DEFAULT_DOMCTL_ADDRESS, 0));
+
+  ExpectSinkAndSourceChanges(true);
+}
+
+
+void MurphyInterface::DestroyDomainController()
+{
+  mrp_domctl_disconnect(mDomCtl);
+  mrp_domctl_destroy(mDomCtl);
+  mDomCtl = NULL;
+}
+
+
+static int connect_request_cb(mrp_domctl_t *ctl,
+                              int narg, mrp_domctl_arg_t *args,
+                              int *nout, mrp_domctl_arg_t *outs,
+                              void *user_data)
+{
+  MurphyInterface           *self = static_cast<MurphyInterface *>(user_data);
+  const char                *error;
+  am::am_sinkID_t            sinkID;
+  am::am_sourceID_t          sourceID;
+  am::am_mainConnectionID_t  connID;
+  uint32_t                   rsetID;
+
+  MRP_UNUSED(ctl);
+
+  if (narg != 3) {
+    error = "called with invalid number of arguments (source and sink expected)";
+    goto error;
+  }
+
+  if (args[0].type != MRP_DOMCTL_UINT16 ||
+      args[1].type != MRP_DOMCTL_UINT16 ||
+      args[2].type != MRP_DOMCTL_UINT32) {
+    error = "called with invalid types of arguments";
+    goto error;
+  }
+
+  *nout    = 0;
+  sourceID = args[0].u16;
+  sinkID   = args[1].u16;
+  rsetID   = args[2].u32;
+
+  mrp_log_info("Got connect request %u -> %u (rset: #%u).", sourceID, sinkID,
+               rsetID);
+
+  if (self->ConnectSourceToSink(sourceID, sinkID, rsetID, connID))
+    mrp_log_info("Connected %u -> %u as %u.", sourceID, sinkID, connID);
+  else {
+    mrp_log_error("Failed to connect %u -> %u.", sourceID, sinkID);
+    connID = 0;
+  }
+
+  return connID;
+
+ error:
+  mrp_log_error("Connect request failed (error: %s).",
+                error ? "error" : "<unknown>");
+
+  *nout        = 1;
+  outs[0].type = MRP_DOMCTL_STRING;
+  outs[0].str  = mrp_strdup(error);
+
+  return 0;
+}
+
+
+bool MurphyInterface::RegisterDomainFunctions()
+{
+  mrp_domctl_method_def_t methods[] = {
+    { "connect", 1, connect_request_cb, this },
+  };
+
+  if (mrp_domctl_register_methods(mDomCtl, methods, MRP_ARRAY_SIZE(methods)))
+    return true;
+  else
+    return false;
+}
+
+
+bool MurphyInterface::ConnectSourceToSink(am::am_sourceID_t source,
+                                          am::am_sinkID_t sink,
+                                          uint32_t rset,
+                                          am::am_mainConnectionID_t & conn)
+{
+  if (mControlSender->CreateConnection(source, sink, rset, conn) != am::E_OK)
+    return false;
+  else
+    return true;
+#if 0
+  if (mControlSender->hookUserConnectionRequest(source, sink, conn) != am::E_OK)
+    return false;
+  else
+    return true;
+#endif
+}
+
+
+static void ssu_update_cb(mrp_timer_t *t, void *user_data)
+{
+  MRP_UNUSED(t);
+
+  MurphyInterface *self = static_cast<MurphyInterface *>(user_data);
+
+  self->ExportSinksAndSources();
+}
+
+
+void MurphyInterface::ExpectSinkAndSourceChanges(bool more)
+{
+  mSsuExpectMore = more;
+}
+
+
+void MurphyInterface::ScheduleSinkAndSourceUpdate()
+{
+  unsigned int delay;
+
+  if (mSsuExpectMore)
+    delay = 100;
+  else
+    delay = 0;
+
+  if (mSsuTimer != NULL) {
+    mrp_debug("rescheduling update of sinks and sources");
+    mrp_mod_timer(mSsuTimer, delay);
+  }
+  else {
+    mrp_debug("scheduling update of sinks and sources");
+    mSsuTimer = mrp_add_timer(mMainloop, delay, ssu_update_cb, (void *)this);
+  }
+}
+
+
+void MurphyInterface::CancelSinkAndSourceUpdate()
+{
+  mrp_del_timer(mSsuTimer);
+  mSsuTimer = NULL;
+}
+
+
+void MurphyInterface::ExportSinksAndSources()
+{
+  std::vector<am::am_Sink_s> sinks;
+  std::vector<am::am_Source_s> sources;
+  mrp_domctl_data_t  *tables, *tbl;
+  mrp_domctl_value_t *values, *v;
+  int nsink, nsource, ntable, nvalue, row;
+
+  mrp_del_timer(mSsuTimer);
+  mSsuTimer = NULL;
+  ExpectSinkAndSourceChanges(false);
+
+  mrp_log_info("Exporting sinks and sources to Murphy.");
+
+  if (mControlReceiver->getListSources(sources) != am::E_OK ||
+      mControlReceiver->getListSinks(sinks) != am::E_OK) {
+    mrp_log_error("Failed to get list of sources and/or sinks.");
+    return;
+  }
+
+  nsink   = sinks.size();
+  nsource = sources.size();
+  ntable  = 2;
+  nvalue  = nsink * AM_SINK_NCOLUMN + nsource * AM_SOURCE_NCOLUMN;
+
+  tables  = (mrp_domctl_data_t  *)alloca(sizeof(*tables) * ntable);
+  values  = (mrp_domctl_value_t *)alloca(sizeof(*values) * nvalue);
+  v       = values;
+
+  tbl = tables;
+
+  tbl->id      = tbl - tables;
+  tbl->ncolumn = AM_SINK_NCOLUMN;
+  tbl->nrow    = nsink;
+  tbl->rows    = (mrp_domctl_value_t **)alloca(tbl->nrow * sizeof(tbl->rows[0]));
+
+  std::vector<am::am_Sink_s>::iterator sink(sinks.begin());
+  row = 0;
+  while (sink != sinks.end()) {
+    tbl->rows[row] = v;
+
+    v[0].type = MRP_DOMCTL_INTEGER;
+    v[0].s32 = sink->sinkID;
+    v[1].type = MRP_DOMCTL_STRING;
+    v[1].str = sink->name.c_str();
+    v[2].type = MRP_DOMCTL_INTEGER;
+    v[2].s32 = sink->available.availability == am::A_AVAILABLE;
+    v[3].type = MRP_DOMCTL_INTEGER;
+    v[3].s32 = sink->visible ? 1 : 0;
+
+    v += AM_SINK_NCOLUMN;
+    sink++;
+    row++;
+  }
+
+  tbl++;
+  tbl->id      = tbl - tables;
+  tbl->ncolumn = AM_SOURCE_NCOLUMN;
+  tbl->nrow    = nsource;
+  tbl->rows    = (mrp_domctl_value_t **)alloca(tbl->nrow * sizeof(tbl->rows[0]));
+
+  std::vector<am::am_Source_s>::iterator source(sources.begin());
+  row = 0;
+  while (source != sources.end()) {
+    tbl->rows[row] = v;
+
+    v[0].type = MRP_DOMCTL_INTEGER;
+    v[0].s32 = source->sourceID;
+    v[1].type = MRP_DOMCTL_STRING;
+    v[1].str = source->name.c_str();
+    v[2].type = MRP_DOMCTL_INTEGER;
+    v[2].s32 = source->available.availability == am::A_AVAILABLE;
+    v[3].type = MRP_DOMCTL_INTEGER;
+    v[3].s32 = source->visible ? 1 : 0;
+
+    v += AM_SOURCE_NCOLUMN;
+    source++;
+    row++;
+  }
+
+  if (!mrp_domctl_set_data(mDomCtl, tables, ntable, &MurphyInterface::DataExportCB, this))
+    mrp_log_error("Failed to export of sinks and sources.");
+}
+
+
+static void request_route_reply_cb(mrp_domctl_t *dc, int error, int retval,
+                                   int narg, mrp_domctl_arg_t *args,
+                                   void *user_data)
+{
+  MurphyInterface      *self = mctl::MurphyInterface::getMurphyInterface();
+  mctl::MainConnection *conn = static_cast<mctl::MainConnection *>(user_data);
+  uint16_t             *route;
+  size_t                nhop;
+
+  MRP_UNUSED(dc);
+
+  if (error != 0 || retval != 0) {
+    mrp_log_error("Route request failed with error %d.", error);
+    return;
+  }
+
+  if (narg != 1) {
+    mrp_log_error("Received invalid route reply (%d args).", narg);
+    return;
+  }
+
+  if (args[0].type != MRP_DOMCTL_ARRAY(UINT16)) {
+    mrp_log_error("Received invalid route reply (wrong type of argument).");
+    return;
+  }
+
+  route = (uint16_t *)args[0].arr;
+  nhop  = args[0].size;
+
+  if (nhop < 2) {
+    mrp_log_error("Received invalid route reply (fewer than 2 hops).");
+    return;
+  }
+
+  self->ProcessRouteRequestReply(conn, route, nhop);
+}
+
+
+bool MurphyInterface::RequestRoute(MainConnection *conn,
+                                   std::vector<am::am_Route_s> routes)
+{
+  am::am_sourceID_t  source = conn->mainSourceID();
+  am::am_sinkID_t    sink   = conn->mainSinkID();
+  mrp_domctl_arg_t  *args;
+  int                narg, i;
+  uint16_t           ends[2], *path;
+  size_t             j, len;
+
+  mrp_log_info("Requesting route for %u -> %u", source, sink);
+
+  narg = 3 + routes.size();
+  args = (mrp_domctl_arg_t *)alloca(narg * sizeof(args[0]));
+
+  ends[0] = source;
+  ends[1] = sink;
+  args[0].type = (mrp_domctl_type_t)MRP_DOMCTL_ARRAY(UINT16);
+  args[0].arr  = ends;
+  args[0].size = 2;
+
+  args[1].type = (mrp_domctl_type_t)MRP_DOMCTL_UINT16;
+  args[1].u32  = conn->getID();
+
+  args[2].type = (mrp_domctl_type_t)MRP_DOMCTL_UINT32;
+  args[2].u32  = conn->rsetID();
+
+  std::vector<am::am_Route_s>::iterator route(routes.begin());
+
+  i = 3;
+  while (route != routes.end()) {
+    std::vector<am::am_RoutingElement_s>::iterator re(route->route.begin());
+    len  = route->route.size();
+    path = (uint16_t *)alloca(len * sizeof(path[0]));
+
+    args[i].type = (mrp_domctl_type_t)MRP_DOMCTL_ARRAY(UINT16);
+    args[i].size = len * 2;
+    args[i].arr  = path;
+
+    j = 0;
+    while (re != route->route.end()) {
+      path[2 * j + 0] = re->sourceID;
+      path[2 * j + 1] = re->sinkID;
+      j++;
+      re++;
+    }
+
+    i++;
+    route++;
+  }
+
+  if (mrp_domctl_invoke(mDomCtl, "request_route", narg, args,
+                        request_route_reply_cb, (void *)conn))
+    return true;
+  else
+    return false;
+}
+
+
+void MurphyInterface::ProcessRouteRequestReply(mctl::MainConnection *conn,
+                                               uint16_t *path, size_t nhop)
+{
+  std::vector<am::am_Route_s> routes;
+  am::am_sourceID_t           source;
+  am::am_sinkID_t             sink;
+  size_t                      len, i;
+  bool                        found;
+
+  source = conn->mainSourceID();
+  sink   = conn->mainSinkID();
+
+  mrp_log_info("Got route of %zd hops for %u -> %u.", nhop, source, sink);
+
+  mControlReceiver->getRoute(false, source, sink, routes);
+
+  found = false;
+  std::vector<am::am_Route_s>::iterator route(routes.begin());
+
+  while (route != routes.end()) {
+    std::vector<am::am_RoutingElement_s>::iterator re(route->route.begin());
+
+    len = route->route.size();
+
+    if (nhop != 2 * len)
+      goto next_route;
+
+    i = 0;
+    while (re != route->route.end()) {
+      if (path[2 * i + 0] != re->sourceID || path[2 * i + 1] != re->sinkID)
+        break;
+      i++;
+      re++;
+    }
+
+    if (re == route->route.end()) {
+      found = true;
+      break;
+    }
+
+  next_route:
+    route++;
+  }
+
+  if (!found) {
+    mrp_log_error("Chosen routing path does not exist.");
+    return;
+  }
+
+  conn->setRoute(*route);
+
+#if 0
+  std::vector<am::am_Route_s> chosen;
+  chosen.push_back(*route);
+
+  mctl::ConnectEvent connev(chosen);
+  conn->queueEvent(connev);
+
+  if (conn->getStateID() == mctl::STATE_END)
+    delete conn;
+#endif
+}
+
+
+bool MurphyInterface::NotifyDisconnect(MainConnection *conn)
+{
+  mrp_domctl_arg_t args[1];
+  int              narg;
+  uint16_t         connid;
+
+
+  connid = conn->getID();
+  mrp_log_info("Notifying disconnection of connection %u.", connid);
+
+  narg = 1;
+  args[0].type = MRP_DOMCTL_UINT16;
+  args[0].u16  = connid;
+
+  mrp_domctl_invoke(mDomCtl, "notify_disconnect", narg, args, NULL, 0);
+
+  return true;
+}
+
+
+void MurphyInterface::SetDecisions(mrp_domctl_data_t *tables, int ntable)
+{
+  mTables = tables;
+  mNtable = ntable;
+}
+
+
+void MurphyInterface::ClearDecisions(void)
+{
+  SetDecisions(NULL, 0);
+}
+
+
+MurphyInterface::Decision MurphyInterface::Verdict(MainConnection *conn)
+{
+  mrp_domctl_data_t  *playback = mTables;
+  mrp_domctl_value_t *row;
+  int                 i;
+  uint16_t            cid;
+  uint32_t            rsid;
+  const char         *verdict;
+
+  cid  = (uint16_t)conn->getID();
+  rsid = conn->rsetID();
+
+  mrp_log_info("Checking verdict for connection %u (rsetid %u)", cid, rsid);
+
+  for (i = 0; i < playback->nrow; i++) {
+    row = playback->rows[i];
+
+    if (row[PLAYBACK_CONNID].u32 != cid && row[PLAYBACK_RSETID].u32 != rsid)
+        continue;
+
+    verdict = row[PLAYBACK_VERDICT].str;
+
+    mrp_log_info("Got verdict '%s' for connection %u", verdict, cid);
+
+    if (!strcmp(verdict, "disconnected")) // no route, stop
+      return DECISION_DISCONNECT;
+    if (!strcmp(verdict, "connected"))    // route and play
+      return DECISION_CONNECT;
+    if (!strcmp(verdict, "suspended"))    // route but stop
+      return DECISION_SUSPEND;
+    if (!strcmp(verdict, "<not yet>"))    // well...
+        return DECISION_NOOP;
+
+    return DECISION_TEARDOWN;
+  }
+
+  mrp_log_info("No explicit verdict for connection %u => TEARDOWN", cid);
+
+  return DECISION_TEARDOWN;
+}
+
+
+/* static */
+void MurphyInterface::DomainConnectionCB(mrp_domctl_t *ctl, int connected, int errcode,
+                                         const char *errmsg, void *user_data)
+{
+  MurphyInterface *self = static_cast<MurphyInterface *>(user_data);
+
+  MRP_UNUSED(ctl);
+
+  if (connected) {
+    mrp_log_info("Domain-controller connection established.");
+    self->ScheduleSinkAndSourceUpdate();
+  }
+  else
+    mrp_log_error("Domain-controller connection down (%d: %s).",
+                  errcode, errmsg);
+}
+
+
+static void dump_data(mrp_domctl_data_t *table)
+{
+    mrp_domctl_value_t *row;
+    int                 i, j;
+    char                buf[1024], *p;
+    const char         *t;
+    int                 n, l;
+
+    mrp_log_info("Table #%d: %d rows x %d columns", table->id,
+                 table->nrow, table->ncolumn);
+
+    for (i = 0; i < table->nrow; i++) {
+        row = table->rows[i];
+        p   = buf;
+        n   = sizeof(buf);
+
+        for (j = 0, t = ""; j < table->ncolumn; j++, t = ", ") {
+            switch (row[j].type) {
+            case MRP_DOMCTL_STRING:
+                l  = snprintf(p, n, "%s'%s'", t, row[j].str);
+                p += l;
+                n -= l;
+                break;
+            case MRP_DOMCTL_INTEGER:
+                l  = snprintf(p, n, "%s%d", t, row[j].s32);
+                p += l;
+                n -= l;
+                break;
+            case MRP_DOMCTL_UNSIGNED:
+                l  = snprintf(p, n, "%s%u", t, row[j].u32);
+                p += l;
+                n -= l;
+                break;
+            case MRP_DOMCTL_DOUBLE:
+                l  = snprintf(p, n, "%s%f", t, row[j].dbl);
+                p += l;
+                n -= l;
+                break;
+            default:
+                l  = snprintf(p, n, "%s<invalid column 0x%x>",
+                              t, row[j].type);
+                p += l;
+                n -= l;
+            }
+        }
+
+        mrp_log_info("row #%d: { %s }", i, buf);
+    }
+}
+
+
+/* static */
+void MurphyInterface::DataImportCB(mrp_domctl_t *ctl, mrp_domctl_data_t *tables,
+                                   int ntable, void *user_data)
+{
+  MurphyInterface *self = static_cast<MurphyInterface *>(user_data);
+  int              i;
+
+  MRP_UNUSED(ctl);
+
+  mrp_log_info("Data import notification (%d tables) from Murphy.", ntable);
+
+  for (i = 0; i < ntable; i++) {
+    dump_data(tables + i);
+  }
+
+
+  self->SetDecisions(tables, ntable);
+  self->mControlSender->ExecuteActions();
+  self->ClearDecisions();
+
+}
+
+
+/* static */
+void MurphyInterface::DataExportCB(mrp_domctl_t *ctl, int errcode, const char *errmsg,
+                                   void *user_data)
+{
+  MurphyInterface *self = static_cast<MurphyInterface *>(user_data);
+
+  MRP_UNUSED(ctl);
+  MRP_UNUSED(self);
+
+    if (errcode == 0)
+      mrp_log_info("Domain-controller data export ok.");
+    else
+      mrp_log_error("Domain-controller data export failed (%d: %s).",
+                    errcode, errmsg);
+}
diff --git a/PluginControlInterfaceMurphy/src/MurphyMainloop.cpp b/PluginControlInterfaceMurphy/src/MurphyMainloop.cpp
new file mode 100644 (file)
index 0000000..19ac839
--- /dev/null
@@ -0,0 +1,773 @@
+/**
+ * XXX TODO: sdd suitable license and copyright
+ */
+
+#include <config.h>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <cstdlib>
+#include <stdexcept>
+#include "shared/CAmDltWrapper.h"
+#include "shared/CAmSocketHandler.h"
+#include "MurphyMainloop.h"
+
+#include <stdlib.h>
+#include <murphy/common/debug.h>
+#include <murphy/common/log.h>
+#include <murphy/common/mm.h>
+#include <murphy/domain-control/client.h>
+
+
+/*
+ * DLT Murphy context
+ */
+
+DLT_DECLARE_CONTEXT(MURPHY)
+
+
+/*
+ * You can use the following environment variable to configure
+ * the Murphy debugging infra. Unsetting, or explicitly setting
+ * this variable to 'off' will disable debugging. Setting this
+ * to a comma-separated list of values will treat those values
+ * as Murphy debug sites and enable all of them. For instance:
+ *
+ *     export GAM_MURPHY_DEBUG="@foo.c,@bar.c,@foobar.cpp,foo_func"
+ *
+ * will enable the given debug sites.
+ */
+
+#define ENVVAR_DBG "GAM_MURPHY_DEBUG"
+#define ENVVAR_LOG "GAM_MURPHY_LOG"
+
+
+/*
+ * Murphy superloop (mainloop integration)
+ */
+
+extern "C" {
+
+  /*
+   * Murphy mainloop AudioManager glue
+   */
+
+  typedef struct {
+    void *am_ml;
+  } am_glue_t;
+
+
+  /*
+   * superloop I/O watch, timer, and deferred callback abstractions
+   */
+
+  typedef struct {
+    void  *am_h;
+    void (*cb)(void *glue_data,
+               void *id, int fd, mrp_io_event_t events,
+               void *user_data);
+    void  *user_data;
+    void  *glue_data;
+    int    fd;
+    short  pending;
+  } io_t;
+
+  typedef struct {
+    void  *am_h;
+    void (*cb)(void *glue_data, void *id, void *user_data);
+    void  *user_data;
+    void  *glue_data;
+  } tmr_t;
+
+  typedef struct {
+    void  *am_h;
+    void (*cb)(void *glue_data, void *id, void *user_data);
+    void  *user_data;
+    void  *glue_data;
+  } dfr_t;
+
+
+  /*
+   * superloop API operations
+   */
+
+  static void *add_io(void *glue_data, int fd, mrp_io_event_t events,
+                      void (*cb)(void *glue_data, void *id, int fd,
+                                 mrp_io_event_t events, void *user_data),
+                      void *user_data);
+  static void  del_io(void *glue_data, void *id);
+  static void  io_cb(int fd, short mask, void *user_data);
+
+  static void *add_timer(void *glue_data, unsigned int msecs,
+                         void (*cb)(void *glue_data, void *id, void *user_data),
+                         void *user_data);
+  static void  del_timer(void *glue_data, void *id);
+  static void  mod_timer(void *glue_data, void *id, unsigned int msecs);
+  static void  timer_cb(void *user_data);
+
+  static void *add_defer(void *glue_data,
+                         void (*cb)(void *glue_data, void *id, void *user_data),
+                         void *user_data);
+  static void  del_defer(void *glue_data, void *id);
+  static void  mod_defer(void *glue_data, void *id, int enabled);
+  static void  defer_cb(void *user_data);
+
+  static void unregister(void *data);
+
+
+  /*
+   * Murphy DLT logging backend
+   */
+
+  static void  gamlogger(void *data, mrp_log_level_t level, const char *file,
+                         int line, const char *func,
+                         const char *format, va_list ap);
+} // extern "C"
+
+
+/*
+ * AudioManager mainloop API bridging
+ */
+
+static bool am_add_io(am_glue_t *glue, int fd, int mask, io_t *io);
+static void am_del_io(am_glue_t *glue, io_t *io);
+
+static bool am_add_timer(am_glue_t *glue, unsigned int msecs, tmr_t *t);
+static void am_del_timer(am_glue_t *glue, tmr_t *t);
+static void am_mod_timer(am_glue_t *glue, unsigned int msecs, tmr_t *t);
+
+static bool am_add_defer(am_glue_t *glue, dfr_t *d);
+static void am_del_defer(am_glue_t *glue, dfr_t *d);
+static void am_mod_defer(am_glue_t *glue, dfr_t *d, bool enabled);
+
+
+/*
+ * Murphy superloop operation table
+ */
+
+static mrp_superloop_ops_t am_ops = {
+  add_io, del_io,
+  add_timer, del_timer, mod_timer,
+  add_defer, del_defer, mod_defer,
+  unregister
+};
+
+
+static void io_cb(int fd, short mask, void *user_data)
+{
+  io_t *io     = (io_t *)user_data;
+  int   events = MRP_IO_EVENT_NONE;
+
+  if (mask & POLLIN)    events |= (int)MRP_IO_EVENT_IN;
+  if (mask & POLLOUT)   events |= (int)MRP_IO_EVENT_OUT;
+  if (mask & POLLRDHUP) events |= (int)MRP_IO_EVENT_HUP;
+  if (mask & POLLHUP)   events |= (int)MRP_IO_EVENT_HUP;
+  if (mask & POLLERR)   events |= (int)MRP_IO_EVENT_ERR;
+
+  mrp_debug("I/O CB (0x%x) for %p", events, user_data);
+
+  io->cb(io->glue_data, io, fd, (mrp_io_event_t)events, io->user_data);
+}
+
+
+static void *add_io(void *glue_data, int fd, mrp_io_event_t events,
+                    void (*cb)(void *glue_data, void *id, int fd,
+                               mrp_io_event_t events, void *user_data),
+                    void *user_data)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  int        mask = 0;
+  io_t      *io;
+
+  io = (io_t *)calloc(1, sizeof(*io));
+
+  if (io != NULL) {
+    if (events & MRP_IO_EVENT_IN)  mask |= POLLIN;
+    if (events & MRP_IO_EVENT_OUT) mask |= POLLOUT;
+    if (events & MRP_IO_EVENT_HUP) mask |= POLLHUP;
+    if (events & MRP_IO_EVENT_ERR) mask |= POLLERR;
+
+    io->fd        = fd;
+    io->cb        = cb;
+    io->user_data = user_data;
+    io->glue_data = glue_data;
+
+    mrp_debug("adding I/O for fd %d, events 0x%x", fd, (int)events);
+
+    if (am_add_io(glue, fd, mask, io))
+      return io;
+
+    free(io);
+  }
+
+  return NULL;
+}
+
+
+static void del_io(void *glue_data, void *id)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  io_t      *io   = (io_t *)id;
+
+  mrp_debug("deleting I/O %p", id);
+
+  am_del_io(glue, io);
+
+  free(io);
+}
+
+
+static void timer_cb(void *user_data)
+{
+    tmr_t *t = (tmr_t *)user_data;
+
+    mrp_debug("timer CB for %p", user_data);
+
+    t->cb(t->glue_data, t, t->user_data);
+}
+
+
+static void *add_timer(void *glue_data, unsigned int msecs,
+                       void (*cb)(void *glue_data, void *id, void *user_data),
+                       void *user_data)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  tmr_t     *t;
+
+  t = (tmr_t *)calloc(1, sizeof(*t));
+
+  if (t != NULL) {
+    t->cb        = cb;
+    t->user_data = user_data;
+    t->glue_data = glue_data;
+
+    mrp_debug("adding timer for %.2f secs", msecs / 1000.0);
+
+    if (am_add_timer(glue, msecs, t))
+      return t;
+
+    free(t);
+  }
+
+  return NULL;
+}
+
+
+static void del_timer(void *glue_data, void *id)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  tmr_t     *t    = (tmr_t *)id;
+
+  mrp_debug("deleting timer %p", id);
+
+  am_del_timer(glue, t);
+
+  free(t);
+}
+
+
+static void mod_timer(void *glue_data, void *id, unsigned int msecs)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  tmr_t     *t    = (tmr_t *)id;
+
+  if (t != NULL)
+    am_mod_timer(glue, msecs, t);
+}
+
+
+static void defer_cb(void *user_data)
+{
+  dfr_t *d = (dfr_t *)user_data;
+
+  mrp_debug("deferred CB for %p", user_data);
+
+  d->cb(d->glue_data, d, d->user_data);
+}
+
+
+static void *add_defer(void *glue_data,
+                       void (*cb)(void *glue_data, void *id, void *user_data),
+                       void *user_data)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  dfr_t     *d;
+
+  d = (dfr_t *)calloc(1, sizeof(*d));
+
+  if (d != NULL) {
+    d->cb        = cb;
+    d->user_data = user_data;
+    d->glue_data = glue_data;
+
+    mrp_debug("%s", "adding deferred");
+
+    if (am_add_defer(glue, d))
+      return d;
+
+    free(d);
+  }
+
+  return NULL;
+}
+
+
+static void del_defer(void *glue_data, void *id)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  dfr_t     *d    = (dfr_t *)id;
+
+  mrp_debug("%s", "deleting deferred");
+
+  am_del_defer(glue, d);
+
+  mrp_free(d);
+}
+
+
+static void mod_defer(void *glue_data, void *id, int enabled)
+{
+  am_glue_t *glue = (am_glue_t *)glue_data;
+  dfr_t     *d    = (dfr_t *)id;
+
+  mrp_debug("%sabling deferred %p", enabled ? "en" : "dis", id);
+
+  am_mod_defer(glue, d, !!enabled);
+}
+
+
+static void unregister(void *data)
+{
+  free(data);
+}
+
+
+/*
+ * AudioManager mainloop API bridging
+ */
+
+static bool am_add_io(am_glue_t *glue, int fd, int mask, io_t *io)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  if ((io->am_h = am_ml->addIO(fd, (int16_t)mask, (void *)io)) != NULL)
+    return true;
+  else
+    return false;
+}
+
+
+static void am_del_io(am_glue_t *glue, io_t *io)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  am_ml->delIO(io->am_h);
+}
+
+
+static bool am_add_timer(am_glue_t *glue, unsigned int msecs, tmr_t *t)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  if ((t->am_h = am_ml->addTimer(msecs, (void *)t)) != NULL)
+    return true;
+  else
+    return false;
+}
+
+
+static void am_del_timer(am_glue_t *glue, tmr_t *t)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  am_ml->delTimer(t->am_h);
+}
+
+
+static void am_mod_timer(am_glue_t *glue, unsigned int msecs, tmr_t *t)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  am_ml->modTimer(msecs, t->am_h);
+}
+
+
+static bool am_add_defer(am_glue_t *glue, dfr_t *d)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  if ((d->am_h = am_ml->addDefer((void *)d)) != NULL)
+    return true;
+  else
+    return false;
+}
+
+
+static void am_del_defer(am_glue_t *glue, dfr_t *d)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  am_ml->delDefer(d->am_h);
+}
+
+
+static void am_mod_defer(am_glue_t *glue, dfr_t *d, bool enabled)
+{
+  mctl::MurphyMainloop *am_ml = (mctl::MurphyMainloop *)glue->am_ml;
+
+  if (enabled && !d->am_h)
+    d->am_h = am_ml->addDefer((void *)d);
+  else if (!enabled && d->am_h) {
+    am_ml->delDefer(d->am_h);
+    d->am_h = NULL;
+  }
+}
+
+
+namespace mctl {
+
+  /*
+   * singleton getter, constructor, destructor
+   */
+
+  mrp_mainloop_t *MurphyMainloop::getMurphyMainloop(am::CAmSocketHandler *sh)
+  {
+    static MurphyMainloop *mainLoop = NULL;
+
+    if (sh == NULL) {
+      if (mainLoop != NULL) {
+        delete mainLoop;
+        mainLoop = NULL;
+      }
+
+      return NULL;
+    }
+
+    if (mainLoop == NULL)
+      mainLoop = new MurphyMainloop(sh);
+
+    if (mainLoop != NULL)
+      return mainLoop->get_mainloop();
+    else
+      return NULL;
+  }
+
+
+  MurphyMainloop::MurphyMainloop(am::CAmSocketHandler *sh) :
+    m_sh(sh),
+    m_ml(mrp_mainloop_create()),
+    m_io_prepare_cb(this, &MurphyMainloop::ioPrepareCB),
+    m_io_check_cb(this, &MurphyMainloop::ioCheckCB),
+    m_io_fire_cb(this, &MurphyMainloop::ioFireCB),
+    m_io_dispatch_cb(this, &MurphyMainloop::ioDispatchCB),
+    m_timer_cb(this, &MurphyMainloop::timerCB),
+    m_defer_cb(this, &MurphyMainloop::deferCB)
+  {
+    assert(m_sh != 0);
+    assert(m_ml != NULL);
+
+    registerLogger();
+    assert(registerMainloop());
+  }
+
+
+  MurphyMainloop::~MurphyMainloop()
+  {
+    unregisterMainloop();
+    mrp_mainloop_destroy(m_ml);
+    m_sh = NULL;
+    m_ml = NULL;
+  }
+
+
+  /*
+   * AudioManager mainloop callback bridging
+   */
+
+  void MurphyMainloop::ioPrepareCB(const sh_pollHandle_t h, void* userData)
+  {
+    MRP_UNUSED(userData);
+
+    mrp_debug("ioPrepareCB for %d", h);
+  }
+
+
+  bool MurphyMainloop::ioCheckCB(const sh_pollHandle_t h, void *userData)
+  {
+    MRP_UNUSED(userData);
+
+    mrp_debug("ioCheckCB for %d", h);
+
+    return true;
+  }
+
+
+  bool MurphyMainloop::ioDispatchCB(const sh_pollHandle_t h, void *userData)
+  {
+    io_t *io = (io_t *)userData;
+
+    mrp_debug("ioDispatchCB for %p (%d)", userData, h);
+
+    io_cb(io->fd, io->pending, io);
+    io->pending = 0;
+
+    return false;
+  }
+
+
+  void MurphyMainloop::ioFireCB(const pollfd pfd, const sh_pollHandle_t h,
+                                   void *userData)
+  {
+    io_t *io = (io_t *)userData;
+
+    mrp_debug("ioFireCB for %d", h);
+
+    io->pending = pfd.revents;
+  }
+
+
+  void MurphyMainloop::timerCB(sh_timerHandle_t h, void *userData)
+  {
+    mrp_debug("timerCB for %p (%d)", userData, h);
+
+    m_sh->restartTimer(h);
+
+    timer_cb(userData);
+  }
+
+
+  void MurphyMainloop::deferCB(sh_timerHandle_t h, void *userData)
+  {
+    mrp_debug("deferCB for %p (%d)", userData, h);
+
+    m_sh->restartTimer(h);
+
+    defer_cb(userData);
+  }
+
+
+  /*
+   * AudioManager mainloop API bridging
+   */
+
+  void *MurphyMainloop::addIO(int fd, int16_t events, void *iop)
+  {
+    sh_pollHandle_t *handle = new sh_pollHandle_t;
+
+    if (m_sh->addFDPoll(fd, events, &m_io_prepare_cb, &m_io_fire_cb,
+                        &m_io_check_cb, &m_io_dispatch_cb,
+                        iop, *handle) == E_OK)
+      return (void *)handle;
+    else {
+      mrp_log_error("failed to add native AudioManager I/O watch");
+
+      delete handle;
+      return NULL;
+    }
+  }
+
+
+  void MurphyMainloop::delIO(void *handlep)
+  {
+    sh_pollHandle_t *handle = (sh_pollHandle_t *)handlep;
+
+    if (handle)
+      m_sh->removeFDPoll(*handle);
+  }
+
+
+  void *MurphyMainloop::addTimer(unsigned int msecs, void *tp)
+  {
+    sh_timerHandle_t *handle = new sh_timerHandle_t;
+    timespec          ts;
+
+    ts.tv_sec  = msecs / 1000;
+    ts.tv_nsec = 1000000 * (msecs % 1000);
+
+    if (ts.tv_sec == 0 && ts.tv_nsec == 0)
+      ts.tv_nsec = 1;
+
+    if (m_sh->addTimer(ts, &m_timer_cb, *handle, tp) == E_OK)
+      return (void *)handle;
+    else {
+      mrp_log_error("failed to add native AudioManager timer");
+
+      delete handle;
+      return NULL;
+    }
+  }
+
+
+  void MurphyMainloop::delTimer(void *handlep)
+  {
+    sh_timerHandle_t *handle = (sh_timerHandle_t *)handlep;
+
+    if (handle)
+      m_sh->removeTimer(*handle);
+  }
+
+
+  void MurphyMainloop::modTimer(unsigned int msecs, void *handlep)
+  {
+    sh_timerHandle_t *handle = (sh_timerHandle_t *)handlep;
+    timespec          ts;
+
+    if (handle) {
+      ts.tv_sec  = msecs / 1000;
+      ts.tv_nsec = 1000000 * (msecs % 1000);
+
+      if (ts.tv_sec == 0 && ts.tv_nsec == 0)
+        ts.tv_nsec = 1;
+
+      if (m_sh->restartTimer(*handle) != E_OK ||
+          m_sh->updateTimer(*handle, ts) != E_OK)
+        mrp_log_error("failed to update native AudioManager timer");
+    }
+  }
+
+
+  void *MurphyMainloop::addDefer(void *dp)
+  {
+    sh_timerHandle_t *handle = new sh_timerHandle_t;
+    timespec          ts     = { 0, 1 };
+
+    if (m_sh->addTimer(ts, &m_defer_cb, *handle, dp) == E_OK)
+      return (void *)handle;
+    else {
+      delete handle;
+      return NULL;
+    }
+  }
+
+
+  void MurphyMainloop::delDefer(void *handlep)
+  {
+    sh_timerHandle_t *handle = (sh_timerHandle_t *)handlep;
+
+    if (handle)
+      m_sh->removeTimer(*handle);
+  }
+
+
+  /*
+   * Murphy mainloop registration
+   */
+
+  bool MurphyMainloop::registerMainloop()
+  {
+    am_glue_t *glue;
+
+    glue = (am_glue_t *)calloc(1, sizeof(*glue));
+
+    if (glue != NULL) {
+      glue->am_ml = (void *)this;
+
+      if (mrp_set_superloop(m_ml, &am_ops, glue))
+        return true;
+      else
+        free(glue);
+    }
+
+    return false;
+  }
+
+
+  void MurphyMainloop::unregisterMainloop()
+  {
+    mrp_mainloop_unregister(m_ml);
+    m_ml = NULL;
+  }
+
+
+  /*
+   * Murphy logging/debugging setup and DLT backend registration
+   */
+
+  void MurphyMainloop::registerLogger()
+  {
+    am::CAmDltWrapper *dlt = am::getWrapper();
+    const char        *dbg, *log, *p, *n;
+    char               site[1024];
+    size_t             l;
+
+    dlt->registerContext(MURPHY, "MRP", "Murphy Infrastructure");
+
+    if (mrp_log_register_target("AudioManager", gamlogger, NULL))
+        mrp_log_set_target("AudioManager");
+
+    if ((log = getenv(ENVVAR_LOG)) == NULL)
+      log = "info,error,warning";
+
+    mrp_log_enable(mrp_log_parse_levels(log));
+
+    if ((dbg = getenv(ENVVAR_DBG)) == NULL)
+      dbg = "off";
+
+    if (strcmp(dbg, "off")) {
+      mrp_log_info("Enabling Murphy debugging (%s).", dbg);
+      mrp_debug_enable(true);
+
+      p = dbg;
+      while (p != NULL) {
+        n = strchr(p, ';');
+        l = n ? n - p : strlen(p);
+
+        if (l < sizeof(site) - 1) {
+          strncpy(site, p, l);
+          site[l] = '\0';
+          mrp_log_info("Enabling Murphy debug site '%s'.", site);
+          mrp_debug_set_config(site);
+        }
+
+        p = n ? n + 1 : NULL;
+      }
+    }
+  }
+}
+
+
+/*
+ * Murphy DLT logger backend
+ */
+
+static void dltlog(DltLogLevelType type, const char *prefix, const char *msg)
+{
+  am::CAmDltWrapper *dlt = am::getWrapper();
+
+  dlt->init(type, &MURPHY);
+  if (prefix)
+    dlt->append(prefix);
+  dlt->append(msg);
+  dlt->send();
+}
+
+
+static void gamlogger(void *data, mrp_log_level_t level, const char *file,
+                      int line, const char *func,
+                      const char *format, va_list ap)
+{
+    va_list         cp;
+    DltLogLevelType type;
+    char            msg[1024], locbuf[1024], *loc;
+
+    MRP_UNUSED(data);
+    MRP_UNUSED(file);
+    MRP_UNUSED(line);
+
+    va_copy(cp, ap);
+    switch (level) {
+    case MRP_LOG_ERROR:   type = DLT_LOG_ERROR; loc = NULL; break;
+    case MRP_LOG_WARNING: type = DLT_LOG_WARN;  loc = NULL; break;
+    case MRP_LOG_INFO:    type = DLT_LOG_INFO;  loc = NULL; break;
+    default:              type = DLT_LOG_INFO;  loc = NULL; break;
+    case MRP_LOG_DEBUG:   type = DLT_LOG_DEBUG;
+      snprintf(locbuf, sizeof(locbuf), "[%s] ", func ? func : "<unknown>");
+      loc = locbuf;
+    }
+
+    if (vsnprintf(msg, sizeof(msg), format, cp) < (ssize_t)sizeof(msg))
+      dltlog(type, loc, msg);
+
+    va_end(cp);
+}
diff --git a/PluginControlInterfaceMurphy/src/StateMachine.cpp b/PluginControlInterfaceMurphy/src/StateMachine.cpp
new file mode 100644 (file)
index 0000000..f46c006
--- /dev/null
@@ -0,0 +1,352 @@
+#include <iostream>
+#include <list>
+
+#include "StateMachine.h"
+#include "TransitionRoutines.h"
+
+using namespace mctl;
+
+#define TRANSITION      static_cast<Transition *>
+
+#define IGNORE          TRANSITION(new NoTransition())
+#define GOTO(_s)        TRANSITION(new DirectTransition(STATE_ ## _s))
+#define TRANSIT(_s,_f)  TRANSITION(new BasicTransition(STATE_ ## _s, _f, # _f))
+#define CONDITIONAL(_a) TRANSITION(new ConditionalTransition(_a))
+
+#if 0
+#define ALTERNATIVE_LIST(_n, ... )                                                \
+    static AlternativeTransition ListOf ## _n[] = {                               \
+        __VA_ARGS__                                                               \
+    };                                                                            \
+    static std::list<AlternativeTransition> _n(ListOf ## _n, ListOf ## _n +       \
+                                 (sizeof(ListOf ## _n) / sizeof(ListOf ## _n [0])))
+
+#define ALTERNATIVE(_c, _s, _f) AlternativeTransition(_c, STATE_ ## _s, _f, # _f)
+#endif
+
+#define ALTERNATIVE_LIST(_n, ... )                                                \
+    static AlternativeTransition *ListOf ## _n[] = {                              \
+        __VA_ARGS__                                                               \
+    };                                                                            \
+    static std::list<AlternativeTransition *> *_n =                               \
+        new std::list<AlternativeTransition *> (ListOf ## _n, ListOf ## _n +      \
+                                 (sizeof(ListOf ## _n) / sizeof(ListOf ## _n [0])))
+
+#define ALTERNATIVE(_c, _s, _f) new AlternativeTransition(_c, STATE_ ## _s, _f, # _f)
+
+
+//--------------------------- Statemachine definition -----------------------------
+
+ALTERNATIVE_LIST (RouteReadyAlternatives,
+    ALTERNATIVE (CanPlay   , CONNECTED, FinishAndConnectMainConnection),
+    ALTERNATIVE (CannotPlay, SUSPENDED, FinishAndSuspendMainConnection)
+);
+
+
+Transition *StateMachine::mTransitions [int(STATE_MAX)] [int(EVENT_TYPE_MAX)] = {
+    //-------------------------
+    // State START
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ TRANSIT      (INITIAL_CONNECT, RouteAndPlaybackRequest)       ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State INITIAL_CONNECT
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ TRANSIT      (END, RouteAndPlaybackRelease)                   ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ TRANSIT      (CONNECTING, SetupDomainConnections)             ,
+        /* NO_ROUTE         */ GOTO         (DISCONNECTED)                                   ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State CONNECTING
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ TRANSIT      (REMOVE, TearDownDomainConnections)              ,
+        /* DOMAIN_CONN_UP   */ TRANSIT      (CONNECTING, DomainConnectionIsUp)               ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ TRANSIT      (CONNECTING, MarkPlay)                           ,
+        /* STOP             */ TRANSIT      (CONNECTING, MarkPlay)                           ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ TRANSIT      (DISCONNECTED, FinishAndDisconnectMainConnection),
+        /* ROUTE_READY      */ CONDITIONAL  (RouteReadyAlternatives)                         ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State CONNECTED
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ TRANSIT      (REMOVE, TearDownDomainConnections)              ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ TRANSIT      (SUSPENDED, SuspendMainConnection)               ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State SUSPENDED
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ TRANSIT      (REMOVE, TearDownDomainConnections)              ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ TRANSIT      (CONNECTED, ResumeMainConnection)                ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ TRANSIT      (REROUTE, TearDownDomainConnections)             ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State DISCONNECTING
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State DISCONNECTED
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State REROUTE
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ TRANSIT     (REROUTE, DomainConnectionIsDown)                 ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ TRANSIT      (CONNECTING, SetupDomainConnections)             ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State REMOVE
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ TRANSIT     (REMOVE, DomainConnectionIsDown)                  ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ TRANSIT     (END, RouteAndPlaybackRelease)                    ,
+        /* DONE             */ IGNORE                                                        ,
+    },
+
+    //-------------------------
+    // State END
+    //-------------------------
+    {   /* Events:          */
+        /* CONNECT          */ IGNORE                                                        ,
+        /* REMOVE           */ IGNORE                                                        ,
+        /* DOMAIN_CONN_UP   */ IGNORE                                                        ,
+        /* DOMAIN_CONN_DOWN */ IGNORE                                                        ,
+        /* PLAY             */ IGNORE                                                        ,
+        /* STOP             */ IGNORE                                                        ,
+        /* NEW_ROUTE        */ IGNORE                                                        ,
+        /* NO_ROUTE         */ IGNORE                                                        ,
+        /* ROUTE_READY      */ IGNORE                                                        ,
+        /* ROUTE_DELETED    */ IGNORE                                                        ,
+        /* DONE             */ IGNORE                                                        ,
+    }
+};
+
+//---------------------------------------------------------------------------------
+
+#undef ALTERNATIVE
+#undef ALTERNATIVE_LIST
+
+#undef CONDITIONAL
+#undef TRANSIT
+#undef GOTO
+#undef IGNORE
+
+#undef TRANSITION
+
+
+
+StateMachine::StateMachine(const char *name):
+    mName(name),
+    mBusy(false),
+    mStateID(STATE_START),
+    mCanPlay(false)
+{
+}
+
+
+StateMachine::~StateMachine()
+{
+}
+
+
+void StateMachine::queueEvent(Event& ev)
+{
+    Event *dup;
+
+    std::cout << mName << ": queue event " << ev << std::endl;
+
+#define DUP(_t,_e) static_cast<Event *>(new _t ## Event(* static_cast<_t ## Event *>(&_e)))
+
+    switch (ev.getType()) {
+    case EVENT_TYPE_CONNECT:          dup = DUP (Connect       , ev);  break;
+    case EVENT_TYPE_REMOVE:           dup = DUP (Remove        , ev);  break;
+    case EVENT_TYPE_DOMAIN_CONN_UP:   dup = DUP (DomainConnUp  , ev);  break;
+    case EVENT_TYPE_DOMAIN_CONN_DOWN: dup = DUP (DomainConnDown, ev);  break;
+    case EVENT_TYPE_PLAY:             dup = DUP (Play          , ev);  break;
+    case EVENT_TYPE_STOP:             dup = DUP (Stop          , ev);  break;
+    case EVENT_TYPE_NEW_ROUTE:        dup = DUP (NewRoute      , ev);  break;
+    case EVENT_TYPE_NO_ROUTE:         dup = DUP (NoRoute       , ev);  break;
+    case EVENT_TYPE_ROUTE_READY:      dup = DUP (RouteReady    , ev);  break;
+    case EVENT_TYPE_ROUTE_DELETED:    dup = DUP (RouteDeleted  , ev);  break;
+    case EVENT_TYPE_DONE:             dup = DUP (Done          , ev);  break;
+    default:
+        std::cout << mName << ": refuse to queue unsupported event type "
+                  << ev.getType() << std::endl;
+        return;
+    }
+
+#undef DUP
+
+    mQueue.push_back(dup);
+    processEvents();
+}
+
+void StateMachine::processEvents()
+{
+    Transition *transition;
+
+    if (!mBusy) {
+        while (!mQueue.empty()) {
+            StateId oldStateID = mStateID;
+
+            Event *ev = mQueue.front();
+            mQueue.pop_front();
+
+            transition = mTransitions [int(mStateID)] [int(ev->getType())];
+
+            std::cout << mName << ": handling event '" << *ev
+                      << " in '" << *this << "' state. "
+                      << *transition << std::endl;
+
+            mBusy = true;
+            mStateID = transition->function(*this, *ev);
+            mBusy = false;
+
+            if (oldStateID == mStateID) {
+                std::cout << mName << ": stayed in '" << *this << "' state"
+                          << std::endl;
+            }
+            else {
+                std::cout << mName << ": transited to new state '"
+                          << *this << "'" << std::endl;
+            }
+
+            delete ev;
+        }
+    }
+}
+
+const char *StateMachine::getName()
+{
+    return mName.c_str();
+}
+
+StateId StateMachine::getStateID()
+{
+    return mStateID;
+}
+
+
+StateMachine::operator const char * ()
+{
+    switch (mStateID) {
+    case STATE_START:               return "Start";
+    case STATE_INITIAL_CONNECT:     return "InitialConnect";
+    case STATE_CONNECTING:          return "Connecting";
+    case STATE_CONNECTED:           return "Connected";
+    case STATE_SUSPENDED:           return "Suspended";
+    case STATE_DISCONNECTING:       return "Disconnecting";
+    case STATE_DISCONNECTED:        return "Disconnected";
+    case STATE_REROUTE:             return "Reroute";
+    case STATE_REMOVE:              return "Remove";
+    case STATE_END:                 return "End";
+    default:                        return "<unknown>";
+    }
+}
+
+void StateMachine::freeTransitions()
+{
+    int i,j;
+
+    std::cout << "Freeing state machine" << std::endl;
+
+    for (i = 0;  i < int(STATE_MAX);  i++) {
+        for (j = 0;  j < int(EVENT_TYPE_MAX); j++) {
+            delete mTransitions[i][j];
+        }
+    }
+}
diff --git a/PluginControlInterfaceMurphy/src/Transition.cpp b/PluginControlInterfaceMurphy/src/Transition.cpp
new file mode 100644 (file)
index 0000000..c01c620
--- /dev/null
@@ -0,0 +1,158 @@
+#include <stdlib.h>
+
+#include <iostream>
+
+#include "Transition.h"
+
+
+using namespace mctl;
+
+
+Transition::Transition()
+{
+}
+
+Transition::~Transition()
+{
+}
+
+
+Transition::operator const char * ()
+{
+    return mString.c_str();
+}
+
+
+StateId Transition::function(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+    return sm.getStateID();
+}
+
+
+NoTransition::NoTransition()
+{
+    mString = "Ignoring the event (no transition).";
+}
+
+StateId NoTransition::function(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+    return sm.getStateID();
+}
+
+DirectTransition::DirectTransition(StateId nextState):
+    mNextState(nextState)
+{
+    mString = "Direct transition.";
+}
+
+StateId DirectTransition::function(StateMachine &sm, Event &ev)
+{
+    (void)(sm);
+    (void)(ev);
+
+    return mNextState;
+}
+
+
+BasicTransition::BasicTransition(StateId nextState,
+                                 TransitionFunction function,
+                                 const char *functionName):
+    mNextState(nextState),
+    mFunction(function)
+{
+    mString  = "Transiting via ";
+    mString += functionName;
+    mString += "() function.";
+}
+
+StateId BasicTransition::function(StateMachine& sm, Event &ev)
+{
+    bool success;
+
+    success = mFunction(sm, ev);
+
+    return success ? mNextState : sm.getStateID();
+}
+
+AlternativeTransition::AlternativeTransition(ConditionFunction condition,
+                                             StateId nextState):
+    mCondition(condition)
+{
+    DirectTransition *directTransition = new DirectTransition(nextState);
+
+    mTransition = static_cast<Transition *>(directTransition);
+}
+
+
+AlternativeTransition::AlternativeTransition(ConditionFunction condition,
+                                             StateId nextState,
+                                             TransitionFunction function,
+                                             const char *functionName):
+    mCondition(condition)
+{
+    BasicTransition *basicTransition = new BasicTransition(nextState,
+                                                           function,
+                                                           functionName);
+    mTransition = static_cast<Transition *>(basicTransition);
+}
+
+
+AlternativeTransition::~AlternativeTransition()
+{
+    delete mTransition;
+}
+
+AlternativeTransition::operator const char * ()
+{
+    return *mTransition;
+}
+
+
+bool AlternativeTransition::function(StateMachine& sm,
+                                     Event& ev,
+                                     StateId& nextState)
+{
+    if (!mCondition(sm, ev))
+        return false;
+
+    std::cout << sm.getName() << ": " << *mTransition << std::endl;
+
+    nextState = mTransition->function(sm, ev);
+
+    return true;
+}
+
+ConditionalTransition::ConditionalTransition(std::list<AlternativeTransition *> *alternatives):
+    mAlternatives(alternatives)
+{
+    mString = "Conditional transition";
+}
+
+ConditionalTransition::~ConditionalTransition()
+{
+    std::list<AlternativeTransition *>::iterator it = mAlternatives->begin();
+    for (;   it != mAlternatives->end();   it++)
+        delete (*it);
+
+    delete mAlternatives;
+}
+
+
+StateId ConditionalTransition::function(StateMachine& sm, Event& ev)
+{
+    StateId nextState;
+
+    std::list<AlternativeTransition *>::iterator it = mAlternatives->begin();
+    for (;   it != mAlternatives->end();   it++) {
+        if ((*it)->function(sm, ev, nextState))
+            return nextState;
+    }
+
+    std::cout << sm.getName() << ": Ignoring event (no transition)" << std::endl;
+
+    return sm.getStateID();
+}
diff --git a/PluginControlInterfaceMurphy/src/TransitionRoutines.cpp b/PluginControlInterfaceMurphy/src/TransitionRoutines.cpp
new file mode 100644 (file)
index 0000000..7487453
--- /dev/null
@@ -0,0 +1,266 @@
+#include <iostream>
+
+
+#include "TransitionRoutines.h"
+#include "Connection.h"
+
+#define ENTER \
+    std::cout << sm.getName() << ": " << __FUNCTION__ << "() enter" << std::endl;
+
+#define LEAVE(_v) \
+    do { \
+        std::cout << sm.getName() << ": " << __FUNCTION__ << "() leave (" \
+        << (_v ? "true" : "false") << ")" << std::endl; \
+        return _v; \
+    } while (0)
+
+
+using namespace mctl;
+
+/***************************************************************************************
+ *                                                                                     *
+ *                                  condition functions                                *
+ *                                                                                     *
+ ***************************************************************************************/
+bool mctl::CanPlay(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+#if 0
+    ENTER;
+
+    LEAVE(false);
+#else
+    ENTER;
+
+    LEAVE(sm.getCanPlay());
+#endif
+}
+
+bool mctl::CannotPlay(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+#if 0
+    ENTER;
+
+    LEAVE(true);
+#else
+    ENTER;
+
+    LEAVE(!sm.getCanPlay());
+#endif
+}
+
+/***************************************************************************************
+ *                                                                                     *
+ *                                  transition routines                                *
+ *                                                                                     *
+ ***************************************************************************************/
+bool mctl::RouteAndPlaybackRequest(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    ConnectEvent *cev = static_cast<ConnectEvent *>(&ev);
+
+    ENTER;
+
+    NewRouteEvent newrt(cev->route(0));
+
+    conn->queueEvent(newrt);
+
+
+    LEAVE(true);
+}
+
+
+bool mctl::RouteAndPlaybackRelease(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+    ENTER;
+
+    LEAVE(true);
+}
+
+
+bool mctl::SavePlaybackGrant(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+    ENTER;
+
+    LEAVE(true);
+}
+
+
+bool mctl::SetupDomainConnections(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+
+    ENTER;
+
+    conn->setupDomainConnections(static_cast<NewRouteEvent&>(ev));
+
+    LEAVE(true);
+}
+
+
+bool mctl::TearDownDomainConnections(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+
+    (void)(ev);
+
+    ENTER;
+
+    conn->tearDownDomainConnections();
+
+    LEAVE(true);
+}
+
+
+bool mctl::DomainConnectionIsUp(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    DomainConnUpEvent *upev = static_cast<DomainConnUpEvent *>(&ev);
+
+    ENTER;
+
+    conn->domainConnectionIsUp(*upev);
+
+    bool ready = true;
+    for (size_t i = 0;   i < conn->size();   i++) {
+        if (conn->domainConnection(i)->getState() != am::CS_CONNECTED) {
+            ready = false;
+            break;
+        }
+    }
+
+    if (ready) {
+        RouteReadyEvent readyev;
+        sm.queueEvent(readyev);
+    }
+
+    LEAVE(true);
+}
+
+
+bool mctl::DomainConnectionIsDown(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    DomainConnDownEvent *downev = static_cast<DomainConnDownEvent *>(&ev);
+
+    (void)(ev);
+
+    ENTER;
+
+    conn->domainConnectionIsDown(*downev);
+
+    bool done = true;
+    for (size_t i = 0;   i < conn->size();   i++) {
+        if (conn->domainConnection(i)->getState() != am::CS_DISCONNECTED) {
+            done = false;
+            break;
+        }
+    }
+
+    if (done) {
+        RouteDeletedEvent doneev;
+        conn->queueEvent(doneev);
+    }
+
+    LEAVE(true);
+}
+
+bool mctl::MarkPlay(StateMachine& sm, Event& ev)
+{
+    ENTER;
+
+    sm.setCanPlay(ev.getType() == EVENT_TYPE_PLAY);
+
+    LEAVE(true);
+}
+
+bool mctl::FinishMainConnection(StateMachine& sm, Event& ev)
+{
+    (void)(ev);
+
+    ENTER;
+
+    LEAVE(true);
+}
+
+
+bool mctl::ConnectMainConnection(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    bool success;
+
+    (void)(ev);
+
+    ENTER;
+
+    success = conn->setState(am::CS_CONNECTED);
+
+    LEAVE(success);
+}
+
+
+bool mctl::SuspendMainConnection(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    bool success;
+
+    (void)(ev);
+
+    ENTER;
+
+    success = conn->setState(am::CS_SUSPENDED);
+
+    LEAVE(success);
+}
+
+
+bool mctl::ResumeMainConnection(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    bool success;
+
+    (void)(ev);
+
+    ENTER;
+
+    success = conn->setState(am::CS_CONNECTED);
+
+    LEAVE(success);
+}
+
+
+bool mctl::DisconnectMainConnection(StateMachine& sm, Event& ev)
+{
+    MainConnection *conn = static_cast<MainConnection *>(&sm);
+    bool success;
+
+    (void)(ev);
+
+    ENTER;
+
+    success = conn->setState(am::CS_DISCONNECTED);
+
+    LEAVE(success);
+}
+
+bool mctl::FinishAndConnectMainConnection(StateMachine& sm, Event& ev)
+{
+    return FinishMainConnection(sm, ev) && ConnectMainConnection(sm, ev);
+}
+
+bool mctl::FinishAndSuspendMainConnection(StateMachine& sm, Event& ev)
+{
+    return FinishMainConnection(sm, ev) && SuspendMainConnection(sm, ev);
+}
+
+
+bool mctl::FinishAndDisconnectMainConnection(StateMachine& sm, Event& ev)
+{
+    return FinishMainConnection(sm, ev) && DisconnectMainConnection(sm, ev);
+}
diff --git a/cmake/FindMURPHY.cmake b/cmake/FindMURPHY.cmake
new file mode 100644 (file)
index 0000000..03bf644
--- /dev/null
@@ -0,0 +1,55 @@
+############################################################################
+#
+# Copyright 2014 Intel
+#
+#
+# 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.
+#
+############################################################################
+
+FIND_PATH(MURPHY_INCLUDE_DIR murphy/common.h
+/usr/include
+)
+
+FIND_LIBRARY(MURPHY_LIBRARY
+NAMES murphy-common
+PATHS /lib
+)
+
+FIND_LIBRARY(DOMCTL_LIBRARY
+NAMES murphy-domain-controller
+PATHS /lib
+)
+
+FIND_LIBRARY(MURPHY_DBUS_LIBRARY
+NAMES murphy-dbus-libdbus
+PATHS /lib
+)
+
+SET( MURPHY_FOUND "NO" )
+
+IF(MURPHY_LIBRARY)
+    IF(DOMCTL_LIBRARY)
+        IF(MURPHY_DBUS_LIBRARY)
+          SET( MURPHY_FOUND "YES" )
+          SET( MURPHY_LIBRARY "${DOMCTL_LIBRARY}" "${MURPHY_LIBRARY}" "${MURPHY_DBUS_LIBRARY}")
+          message(STATUS "Found MURPHY libs: ${MURPHY_LIBRARY}")
+          message(STATUS "Found MURPHY include: ${MURPHY_INCLUDE_DIR}")
+      ENDIF(MURPHY_DBUS_LIBRARY)
+  ENDIF(DOMCTL_LIBRARY)
+ENDIF(MURPHY_LIBRARY)
+
+MARK_AS_ADVANCED(
+  MURPHY_INCLUDE_DIR
+  MURPHY_LIBRARY
+)
index b98f174..23b120a 100644 (file)
@@ -14,6 +14,7 @@ BuildRequires:          pkgconfig(automotive-dlt)
 BuildRequires:   pkgconfig(zlib)
 BuildRequires:    pkgconfig(CommonAPI)
 BuildRequires:    pkgconfig(CommonAPI-DBus)
+BuildRequires:   pkgconfig(murphy-common)
 Requires(post):   /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
 
@@ -54,6 +55,7 @@ rm $RPM_BUILD_ROOT%{_libdir}/audioManager/routing/libPluginRoutingInterfaceAsync
 %{_libdir}/audioManager/routing/libPluginRoutingInterfaceDbus.so*
 %{_libdir}/audioManager/control/libPluginControlInterface.so*
 %{_libdir}/audioManager/control/libPluginControlInterfaceDbus.so*
+%{_libdir}/audioManager/control/libPluginControlInterfaceMurphy.so*
 %{_datadir}/audiomanager/*xml
 
 %files devel