summaryrefslogtreecommitdiff
path: root/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c')
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
new file mode 100644
index 00000000..326b64b7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
@@ -0,0 +1,470 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ * MODULE SUMMARY :
+ *
+ * Stream clients (talkers or listeners) must connect to the central
+ * "avdecc_msg" process to create a reservation for their traffic.
+ *
+ * This code implements the server side of the IPC.
+ *
+ * It provides proxy functions for the avdecc_msg to call. The arguments
+ * for those calls are packed into messages, which are unpacked in the
+ * process and then used to call the real functions.
+ *
+ * Current IPC uses unix sockets. Can change this by creating a new
+ * implementations in openavb_avdecc_msg_client.c and openavb_avdecc_msg_server.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#define AVB_LOG_COMPONENT "AVDECC Msg"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_adp.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+
+#include "openavb_avdecc_msg_server.h"
+#include "openavb_trace.h"
+
+// forward declarations
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg);
+
+// OSAL specific functions
+#include "openavb_avdecc_msg_server_osal.c"
+
+// AvdeccMsgStateListGet() support.
+#include "openavb_avdecc_msg.c"
+
+// the following are from openavb_avdecc.c
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_tl_data_cfg_t * streamList;
+
+
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg) {
+ AVB_LOG_ERROR("Receiving message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ bool ret = FALSE;
+ switch (msg->type) {
+ case OPENAVB_AVDECC_MSG_VERSION_REQUEST:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_REQUEST");
+ ret = openavbAvdeccMsgSrvrHndlVerRqstFromClient(avdeccMsgHandle);
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY");
+ ret = openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(avdeccMsgHandle,
+ msg->params.clientInitIdentify.friendly_name,
+ msg->params.clientInitIdentify.talker);
+ break;
+ case OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID");
+ ret = openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(avdeccMsgHandle,
+ msg->params.c2sTalkerStreamID.sr_class,
+ msg->params.c2sTalkerStreamID.stream_src_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_uid),
+ msg->params.c2sTalkerStreamID.stream_dest_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION");
+ ret = openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeNotification.current_state);
+ break;
+ default:
+ AVB_LOG_ERROR("Unexpected message received at server");
+ break;
+ }
+
+ AVB_LOGF_VERBOSE("Message handled, ret=%d", ret);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+void openavbAvdeccMsgSrvrSendServerVersionToClient(int avdeccMsgHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_VERSION_CALLBACK;
+ msgBuf.params.versionCallback.AVBVersion = htonl(AVBVersion);
+ openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+/* Client version request
+ */
+bool openavbAvdeccMsgSrvrHndlVerRqstFromClient(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMsgSrvrSendServerVersionToClient(avdeccMsgHandle, AVB_CORE_VER_FULL);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavb_tl_data_cfg_t * currentStream;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ // The handle was already specified. Something has gone terribly wrong!
+ AVB_LOGF_ERROR("avdeccMsgHandle %d already used", avdeccMsgHandle);
+ AvdeccMsgStateListRemove(pState);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Make sure the supplied string is nil-terminated.
+ friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+
+ // Create a structure to hold the client information.
+ pState = (avdecc_msg_state_t *) calloc(1, sizeof(avdecc_msg_state_t));
+ if (!pState) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+ pState->avdeccMsgHandle = avdeccMsgHandle;
+ pState->bTalker = (talker != 0);
+ pState->lastRequestedState = pState->lastReportedState = OPENAVB_AVDECC_MSG_UNKNOWN;
+
+ // Find the state information matching this item.
+ for (currentStream = streamList; currentStream != NULL; currentStream = currentStream->next) {
+ if (strncmp(currentStream->friendly_name, friendly_name, FRIENDLY_NAME_SIZE) == 0)
+ {
+ break;
+ }
+ }
+ if (!currentStream) {
+ AVB_LOGF_WARNING("Ignoring unexpected client %d, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Keep track of this new state item.
+ if (!AvdeccMsgStateListAdd(pState)) {
+ AVB_LOGF_ERROR("Error saving client identity information %d", avdeccMsgHandle);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Associate this Listener instance with the stream information.
+ pState->stream = currentStream;
+ currentStream->client = pState;
+
+ AVB_LOGF_INFO("Client %d Detected, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+
+ // Enable ADP support, now that we have at least one Talker/Listener.
+ openavbAdpHaveTL(true);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (!pCfg) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d stream not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Update the stream information supplied by the client.
+ pCfg->sr_class = sr_class;
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->vlan_id = stream_vlan_id;
+ AVB_LOGF_DEBUG("Talker-supplied sr_class: %u", pCfg->sr_class);
+ AVB_LOGF_DEBUG("Talker-supplied stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ AVB_LOGF_DEBUG("Talker-supplied dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ AVB_LOGF_DEBUG("Talker-supplied vlan_id: %u", pCfg->vlan_id);
+
+ // Notify the state machine that we received this information.
+ openavbAcmpSMTalker_updateStreamInfo(pCfg);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrListenerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID;
+ openavbAvdeccMsgParams_ListenerStreamID_t * pParams =
+ &(msgBuf.params.listenerStreamID);
+ pParams->sr_class = sr_class;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrTalkerStreamID(int avdeccMsgHandle,
+ U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Send the stream information to the client.
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID;
+ openavbAvdeccMsgParams_S2C_TalkerStreamID_t * pParams =
+ &(msgBuf.params.s2cTalkerStreamID);
+ pParams->sr_class = sr_class;
+ pParams->stream_id_valid = stream_id_valid;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ pParams->stream_dest_valid = stream_dest_valid;
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id_valid = stream_vlan_id_valid;
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST;
+ openavbAvdeccMsgParams_ClientChangeRequest_t * pParams =
+ &(msgBuf.params.clientChangeRequest);
+ pParams->desired_state = (U8) desiredState;
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+ if (ret) {
+ // Save the requested state for future reference.
+ pState->lastRequestedState = desiredState;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+static const char * GetStateString(openavbAvdeccMsgStateType_t state)
+{
+ switch (state) {
+ case OPENAVB_AVDECC_MSG_UNKNOWN:
+ return "Unknown";
+ case OPENAVB_AVDECC_MSG_STOPPED:
+ return "Stopped";
+ case OPENAVB_AVDECC_MSG_RUNNING:
+ return "Running";
+ case OPENAVB_AVDECC_MSG_PAUSED:
+ return "Paused";
+ case OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY:
+ return "Stopped_Unexpectedly";
+ default:
+ return "ERROR";
+ }
+}
+
+bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Save the updated state.
+ if (currentState != pState->lastReportedState) {
+ openavbAvdeccMsgStateType_t previousState = pState->lastReportedState;
+ pState->lastReportedState = currentState;
+ AVB_LOGF_INFO("Notified of client %d state change from %s to %s (Last requested: %s)",
+ avdeccMsgHandle, GetStateString(previousState), GetStateString(currentState), GetStateString(pState->lastRequestedState));
+
+ // If AVDECC did not yet set the client state, set the client state to the desired state.
+ if (pState->lastRequestedState == OPENAVB_AVDECC_MSG_UNKNOWN) {
+ if (pState->stream->initial_state == TL_INIT_STATE_RUNNING && pState->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client be running if the user explicitly requested it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
+ }
+ else if (pState->stream->initial_state != TL_INIT_STATE_RUNNING && pState->lastReportedState == OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client not be running if the user didn't explicitly request it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+ else if (gAvdeccCfg.bFastConnectSupported &&
+ !(pState->bTalker) &&
+ pState->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ // Listener started as not running, and is not configured to start in the running state.
+ // See if we should do a fast connect using the saved state.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ openavbAcmpSMListenerSet_doFastConnect(pCfg, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+ }
+ }
+ }
+ }
+ else if (currentState == OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY) {
+ if (previousState != OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY &&
+ pState->lastRequestedState == OPENAVB_AVDECC_MSG_RUNNING &&
+ gAvdeccCfg.bFastConnectSupported) {
+ // The Talker disappeared. Use fast connect to assist with reconnecting if it reappears.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ // Set the timed-out status for the Listener's descriptor.
+ // The next time the Talker advertises itself, openavbAcmpSMListenerSet_talkerTestFastConnect() should try to reconnect.
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (pDescriptor && pDescriptor->stream &&
+ strcmp(pDescriptor->stream->friendly_name, pCfg->friendly_name) == 0) {
+ // We found a match.
+ AVB_LOGF_INFO("Listener %s waiting to fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pCfg->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
+ memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
+ pDescriptor->fast_connect_start_time.tv_sec += 5; // Give the Talker some time to shutdown or stabilize
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Now that we have handled this, treat this state as a normal stop.
+ pState->lastReportedState = OPENAVB_AVDECC_MSG_STOPPED;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+
+/* Called if a client closes their end of the IPC
+ */
+void openavbAvdeccMsgSrvrCloseClientConnection(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ // Free the state for this handle.
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ AvdeccMsgStateListRemove(pState);
+ if (streamList && pState->stream) {
+ // Clear the stream pointer to this object.
+ pState->stream = NULL;
+ }
+ free(pState);
+
+ // If there are no more Talkers or Listeners, stop ADP.
+ if (AvdeccMsgStateListGetIndex(0) == NULL) {
+ openavbAdpHaveTL(false);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}