mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2156 lines
81 KiB
C
2156 lines
81 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File voipcommon.c
|
|
|
|
\Description
|
|
Cross-platform voip data types and functions.
|
|
|
|
\Copyright
|
|
Copyright (c) 2009 Electronic Arts Inc.
|
|
|
|
\Version 12/02/2009 (jbrookes) First Version
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#ifdef _XBOX
|
|
#include <xtl.h>
|
|
#include <xonline.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/platform.h"
|
|
#include "DirtySDK/dirtysock.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
#include "DirtySDK/dirtysock/netconn.h"
|
|
|
|
#include "DirtySDK/voip/voipdef.h"
|
|
#include "voippriv.h"
|
|
#include "voipcommon.h"
|
|
|
|
#include "DirtySDK/voip/voip.h"
|
|
#include "DirtySDK/voip/voipblocklist.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
#define VOIPCOMMON_CODEDCHAN_ALL (0) //! Special handling for codeded channel {(0,none),(0,none),(0,none),(0,none)} = talk/listen to everyone
|
|
#define VOIPCOMMON_CODEDCHAN_NONE (0x01010101) //! Special handling for codeded channel {(1,none),(1,none),(1,none),(1,none)} = can't talk or listen to anyone
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
//! pointer to module state
|
|
static VoipRefT *_Voip_pRef = NULL;
|
|
|
|
//! voip memgroup
|
|
static int32_t _Voip_iMemGroup='dflt';
|
|
|
|
//! voip memgroup userdata
|
|
static void *_Voip_pMemGroupUserData=NULL;
|
|
|
|
/*** Private Functions ************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonTextDataCb
|
|
|
|
\Description
|
|
Callback to handle locally generated transcribed text.
|
|
|
|
\Input *pStrUtf8 - pointer to text data
|
|
\Input uLocalUserIndex - local user index
|
|
\Input *pUserData - pointer to callback user data
|
|
|
|
\Version 10/29/2018 (tcho)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonTextDataCb(const char *pStrUtf8, uint32_t uLocalUserIndex, void *pUserData)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
|
|
VoipConnectionReliableTranscribedTextMessage(&pVoipCommon->Connectionlist, uLocalUserIndex, pStrUtf8);
|
|
/* We also want locally generated transcribed text shown to its originator if that local user has
|
|
also requested transcribed text from remote users. Motivation: a hearing-impaired person requesting
|
|
transcribed text from other players also wants to see transcribed text for his own speech
|
|
(request from EA's accessibility team).
|
|
|
|
Note on XBoxOne this data will come through _VoipCommonReceiveTextDataCb as it would for remote generated text.
|
|
*/
|
|
if (pVoipCommon->Connectionlist.bTranscribedTextRequested[uLocalUserIndex] == TRUE)
|
|
{
|
|
if (pVoipCommon->pDisplayTranscribedTextCb != NULL)
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb(-1, uLocalUserIndex, pStrUtf8, pVoipCommon->pDisplayTranscribedTextUserData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonMicDataCb
|
|
|
|
\Description
|
|
Callback to handle locally acquired mic data.
|
|
|
|
\Input *pVoiceData - pointer to mic data
|
|
\Input iDataSize - size of mic data
|
|
\Input *pMetaData - pointer to platform-specific metadata (can be NULL)
|
|
\Input iMetaDataSize - size of platform-specifici metadata
|
|
\Input uLocalUserIndex - local user index
|
|
\Input uSendSeqn - send sequence
|
|
\Input *pUserData - pointer to callback user data
|
|
|
|
\Version 10/29/2018 (tcho)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonMicDataCb(const void *pVoiceData, int32_t iDataSize, const void *pMetaData, int32_t iMetaDataSize, uint32_t uLocalUserIndex, uint8_t uSendSeqn, void *pUserData)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
|
|
if (pVoipCommon != NULL)
|
|
{
|
|
VoipConnectionSend(&pVoipCommon->Connectionlist, 0xFFFFFFFF, (uint8_t *)pVoiceData, iDataSize, (uint8_t *)pMetaData, iMetaDataSize, uLocalUserIndex, uSendSeqn);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonOpaqueDataCb
|
|
|
|
\Description
|
|
Callback to handle locally generated opaque data to be sent reliably to other voip peers.
|
|
|
|
\Input pOpaqueData - data buffer
|
|
\Input iOpaqueDataSize - opaque data size in bytes
|
|
\Input uSendMask - mask identifying which connections to send the data to
|
|
\Input bReliable - TRUE if reliable transmission needed, FALSE otherwise
|
|
\Input uSendSeqn - send sequence
|
|
\Input *pUserData - user data
|
|
|
|
\Version 11/22/2018 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonOpaqueDataCb(const uint8_t *pOpaqueData, int32_t iOpaqueDataSize, uint32_t uSendMask, uint8_t bReliable, uint8_t uSendSeqn, void *pUserData)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
|
|
int32_t iConnID;
|
|
|
|
if (bReliable)
|
|
{
|
|
for (iConnID = 0; iConnID < pVoipCommon->Connectionlist.iMaxConnections; iConnID++)
|
|
{
|
|
if (uSendMask & (1 << iConnID))
|
|
{
|
|
VoipConnectionReliableSendOpaque(&pVoipCommon->Connectionlist, iConnID, pOpaqueData, iOpaqueDataSize);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The xboxone unreliable date frames are opaque to us. Consequently, we do not know if they contain encode voice from a specific
|
|
local user or from multiple local users. Therfore, we always invoke VoipConnectionSend() with the local user index being
|
|
VOIP_SHARED_USER_INDEX. By doing so, we guarantee that VOIP_REMOTE_USER_RECVVOICE and VOIP_LOCAL_USER_SENDVOICE gets updated
|
|
consistently for all participating users on a given console. We loose the per-user granularity for that flag, but it's
|
|
the best we can do. */
|
|
VoipConnectionSend(&pVoipCommon->Connectionlist, uSendMask, pOpaqueData, iOpaqueDataSize, NULL, 0, VOIP_SHARED_USER_INDEX, uSendSeqn);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonEncode
|
|
|
|
\Description
|
|
Packs the channel selection for sending to a remote machine
|
|
|
|
\Input iChannels[] - the array of channels to encode
|
|
\Input uModes[] - the array of modes to encode
|
|
|
|
\Output
|
|
uint32_t - the coded channels
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static uint32_t _VoipCommonEncode(int32_t iChannels[], uint32_t uModes[])
|
|
{
|
|
uint32_t codedChannel = 0;
|
|
int32_t iIndex;
|
|
|
|
for(iIndex = 0; iIndex < VOIP_MAX_CONCURRENT_CHANNEL; iIndex++)
|
|
{
|
|
codedChannel |= (iChannels[iIndex] & 0x3f) << (8 * iIndex);
|
|
codedChannel |= ((uModes[iIndex] & 0x3) << 6) << (8 * iIndex);
|
|
}
|
|
|
|
return(codedChannel);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonDecode
|
|
|
|
\Description
|
|
Unpacks the channel selection received by a remote machine
|
|
|
|
\Input uCodedChannel - the coded channels
|
|
\Input iChannels[] - the array of channels to fill up
|
|
\Input uModes[] - the array of modes to fill up
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonDecode(uint32_t uCodedChannel, int32_t iChannels[], uint32_t uModes[])
|
|
{
|
|
int32_t iIndex;
|
|
for(iIndex = 0; iIndex < VOIP_MAX_CONCURRENT_CHANNEL; iIndex++)
|
|
{
|
|
iChannels[iIndex] = (uCodedChannel >> (8 * iIndex)) & 0x3f;
|
|
uModes[iIndex] = ((uCodedChannel >> (8 * iIndex)) >> 6) & 0x3;
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonProcessChannelChange
|
|
|
|
\Description
|
|
Unpacks the channel selection received by a remote machine
|
|
|
|
\Input pVoipCommon - voip common state
|
|
\Input iConnId - connection id
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonProcessChannelChange(VoipCommonRefT *pVoipCommon, int32_t iConnId)
|
|
{
|
|
int32_t iUserIndex;
|
|
|
|
for (iUserIndex = 0; iUserIndex < VOIP_MAXLOCALUSERS_EXTENDED; iUserIndex++)
|
|
{
|
|
uint32_t uInputOuputVar;
|
|
#if DIRTYCODE_LOGGING
|
|
uint32_t uNewChannelConfig, uOldChannelConfig;
|
|
#endif
|
|
|
|
uInputOuputVar = (uint32_t)iUserIndex;
|
|
VoipStatus(VoipGetRef(), 'rchn', iConnId, &uInputOuputVar, sizeof(uInputOuputVar));
|
|
|
|
#if DIRTYCODE_LOGGING
|
|
uNewChannelConfig = uInputOuputVar;
|
|
uOldChannelConfig = pVoipCommon->uRemoteChannelSelection[iConnId][iUserIndex];
|
|
|
|
NetPrintf(("voipcommon: got remote channels 0x%08x (old config: 0x%08x)for user index %d on low-level conn id %d\n",
|
|
uNewChannelConfig, uOldChannelConfig, iUserIndex, iConnId));
|
|
#endif
|
|
|
|
pVoipCommon->uRemoteChannelSelection[iConnId][iUserIndex] = uInputOuputVar;
|
|
}
|
|
|
|
VoipCommonApplyChannelConfig(pVoipCommon);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function _VoipIdle
|
|
|
|
\Description
|
|
NetConn idle function to update the Voip module.
|
|
|
|
This function is designed to handle issuing user callbacks based on events such as
|
|
headset insertion and removal. It is implemented as a NetConn idle function instead
|
|
of as a part of the Voip thread so that callbacks will be generated from the same
|
|
thread that DirtySock operates in.
|
|
|
|
\Input *pData - pointer to module state
|
|
\Input uTick - current tick count
|
|
|
|
\Notes
|
|
This function is installed as a NetConn Idle function. NetConnIdle()
|
|
must be regularly polled for this function to be called.
|
|
|
|
\Version 02/10/2006 (jbrookes)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
static void _VoipIdle(void *pData, uint32_t uTick)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pData;
|
|
int32_t iIndex;
|
|
|
|
// check for state changes and trigger callback
|
|
if (pVoipCommon->uLastHsetStatus != pVoipCommon->uPortHeadsetStatus)
|
|
{
|
|
pVoipCommon->pCallback((VoipRefT *)pData, VOIP_CBTYPE_HSETEVENT, pVoipCommon->uPortHeadsetStatus, pVoipCommon->pUserData);
|
|
pVoipCommon->uLastHsetStatus = pVoipCommon->uPortHeadsetStatus;
|
|
}
|
|
|
|
if (pVoipCommon->uLastFrom != pVoipCommon->Connectionlist.uRecvVoice)
|
|
{
|
|
pVoipCommon->pCallback((VoipRefT *)pData, VOIP_CBTYPE_FROMEVENT, pVoipCommon->Connectionlist.uRecvVoice, pVoipCommon->pUserData);
|
|
pVoipCommon->uLastFrom = pVoipCommon->Connectionlist.uRecvVoice;
|
|
}
|
|
|
|
if (pVoipCommon->uLastTtsStatus != pVoipCommon->uTtsStatus)
|
|
{
|
|
pVoipCommon->pCallback((VoipRefT *)pData, VOIP_CBTYPE_TTOSEVENT, pVoipCommon->uTtsStatus, pVoipCommon->pUserData);
|
|
pVoipCommon->uLastTtsStatus = pVoipCommon->uTtsStatus;
|
|
}
|
|
|
|
for (iIndex = 0; iIndex < VOIP_MAXLOCALUSERS; ++iIndex)
|
|
{
|
|
if (pVoipCommon->uLastLocalStatus[iIndex] != pVoipCommon->Connectionlist.uLocalUserStatus[iIndex])
|
|
{
|
|
if ((pVoipCommon->uLastLocalStatus[iIndex] ^ pVoipCommon->Connectionlist.uLocalUserStatus[iIndex]) & VOIP_LOCAL_USER_SENDVOICE)
|
|
{
|
|
pVoipCommon->pCallback((VoipRefT *)pData, VOIP_CBTYPE_SENDEVENT, pVoipCommon->Connectionlist.uLocalUserStatus[iIndex] & VOIP_LOCAL_USER_SENDVOICE, pVoipCommon->pUserData);
|
|
}
|
|
pVoipCommon->uLastLocalStatus[iIndex] = pVoipCommon->Connectionlist.uLocalUserStatus[iIndex];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonChannelMatch
|
|
|
|
\Description
|
|
Returns whether a given channel selection is to be received and/or sent to
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iUserIndex - local user index
|
|
\Input uCodedChannel - coded channels of remote user
|
|
|
|
\Output
|
|
uint32_t - the coded channels
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static VoipChanModeE _VoipCommonChannelMatch(VoipCommonRefT *pVoipCommon, int32_t iUserIndex, uint32_t uCodedChannel)
|
|
{
|
|
int32_t iIndexRemote;
|
|
int32_t iIndexLocal;
|
|
VoipChanModeE eMode = 0;
|
|
int32_t iChannels[VOIP_MAX_CONCURRENT_CHANNEL];
|
|
uint32_t uModes[VOIP_MAX_CONCURRENT_CHANNEL];
|
|
|
|
// Voip traffic sent on channels {(0,none),(0,none),(0,none),(0,none)} = talk/listen to everyone = VOIPCOMMON_CODEDCHAN_ALL
|
|
// Voip traffic blocked on channels {(1,none),(1,none),(1,none),(1,none)} = can't talk or listen = VOIPCOMMON_CODEDCHAN_NONE
|
|
// is assumed to be meant for everybody.
|
|
// enables default behaviour for teams not using channels.
|
|
if ((uCodedChannel == VOIPCOMMON_CODEDCHAN_ALL) || (pVoipCommon->uLocalChannelSelection[iUserIndex] == VOIPCOMMON_CODEDCHAN_ALL))
|
|
{
|
|
return(VOIP_CHANSEND|VOIP_CHANRECV);
|
|
}
|
|
else if ((uCodedChannel == VOIPCOMMON_CODEDCHAN_NONE) || (pVoipCommon->uLocalChannelSelection[iUserIndex] == VOIPCOMMON_CODEDCHAN_NONE))
|
|
{
|
|
return(VOIP_CHANNONE);
|
|
}
|
|
|
|
_VoipCommonDecode(uCodedChannel, iChannels, uModes);
|
|
|
|
// for all our channels, and all the channels of the remote party
|
|
for(iIndexRemote = 0; iIndexRemote < VOIP_MAX_CONCURRENT_CHANNEL; iIndexRemote++)
|
|
{
|
|
for(iIndexLocal = 0; iIndexLocal < VOIP_MAX_CONCURRENT_CHANNEL; iIndexLocal++)
|
|
{
|
|
// if their channel numbers match
|
|
if (pVoipCommon->iLocalChannels[iUserIndex][iIndexLocal] == iChannels[iIndexRemote])
|
|
{
|
|
// if we're sending on it and they're receiving on it
|
|
if ((pVoipCommon->uLocalModes[iUserIndex][iIndexLocal] & VOIP_CHANSEND) && (uModes[iIndexRemote] & VOIP_CHANRECV))
|
|
{
|
|
// let's send
|
|
eMode |= VOIP_CHANSEND;
|
|
}
|
|
// if we're receiving on it and they're send on it
|
|
if ((pVoipCommon->uLocalModes[iUserIndex][iIndexLocal] & VOIP_CHANRECV) && (uModes[iIndexRemote] & VOIP_CHANSEND))
|
|
{
|
|
// let's receive
|
|
eMode |= VOIP_CHANRECV;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(eMode);
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonComputeEffectiveUserSendMask
|
|
|
|
\Description
|
|
Compute effective user send mask from two other masks: user-selected
|
|
send mask and mask obtained from voip channel config
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonComputeEffectiveUserSendMask(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
VoipCommonSetMask(&pVoipCommon->Connectionlist.uUserSendMask, pVoipCommon->uUserMicrValue & pVoipCommon->uChanSendMask, "usendmask");
|
|
#if defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
|
|
pVoipCommon->Connectionlist.bApplyRelFromMuting = TRUE; // to reflect these changes in the communication relationship
|
|
#endif
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonComputeDefaultSharedChannelConfig
|
|
|
|
\Description
|
|
Computes the default shared channel config. This is the logical "and" of all
|
|
local user's channel modes
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
|
|
\Notes
|
|
Loops through all the channels and "and" the channel mode of all the valid users on the
|
|
that particular channel together. Only if everyone is subcribed to the channel do we set
|
|
the mode for the shared user.
|
|
|
|
\Version 12/11/2014 (tcho)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonComputeDefaultSharedChannelConfig(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
// only bother to do any of this if we are in fact using the "default shared channel config", which is more of a behavior than a static thing
|
|
if (pVoipCommon->bUseDefaultSharedChannelConfig)
|
|
{
|
|
int32_t iLocalUserIndex;
|
|
int32_t iChannel;
|
|
int32_t iChannelSlot;
|
|
int32_t iEmptySlot = 0;
|
|
|
|
_VoipCommonDecode(VOIPCOMMON_CODEDCHAN_NONE, pVoipCommon->iDefaultSharedChannels, pVoipCommon->uDefaultSharedModes);
|
|
|
|
// loop through all the channel from 1 to 63
|
|
for (iChannel = 1; iChannel < VOIP_MAXLOCALCHANNEL; ++iChannel)
|
|
{
|
|
int32_t iValidUser = 0;
|
|
int32_t iChannelSubscriber = 0;
|
|
int32_t iChannelAllUser = 0;
|
|
uint32_t uSharedChannelMode = VOIP_CHANSENDRECV;
|
|
|
|
// only compute the shared channel config if we still have a free slot
|
|
if (iEmptySlot != VOIP_MAX_CONCURRENT_CHANNEL)
|
|
{
|
|
// loop through all the local users excluding the shared user
|
|
for (iLocalUserIndex = 0; iLocalUserIndex < VOIP_MAXLOCALUSERS; ++iLocalUserIndex)
|
|
{
|
|
if (!VOIP_NullUser((VoipUserT *)&pVoipCommon->Connectionlist.LocalUsers[iLocalUserIndex]))
|
|
{
|
|
++iValidUser;
|
|
|
|
// the user is valid loop through his subscribed channels
|
|
for (iChannelSlot = 0; iChannelSlot < VOIP_MAX_CONCURRENT_CHANNEL; ++iChannelSlot)
|
|
{
|
|
// check to see if we are in an VOIPCOMMON_CODEDCHAN_ALL state, in which case consider treating the shared user as a VOIPCOMMON_CODEDCHAN_ALL
|
|
if (_VoipCommonEncode(pVoipCommon->iLocalChannels[iLocalUserIndex], pVoipCommon->uLocalModes[iLocalUserIndex]) == VOIPCOMMON_CODEDCHAN_ALL)
|
|
{
|
|
++iChannelAllUser;
|
|
break;
|
|
}
|
|
// check to see if the user is actually a member of the channel, in which case consider using this channel for the shared user too
|
|
else if (pVoipCommon->iLocalChannels[iLocalUserIndex][iChannelSlot] == iChannel)
|
|
{
|
|
++iChannelSubscriber;
|
|
uSharedChannelMode &= pVoipCommon->uLocalModes[iLocalUserIndex][iChannelSlot];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if everyone is all open, then the shared channel is all open too
|
|
if ((iValidUser == iChannelAllUser) && (iChannelAllUser != 0))
|
|
{
|
|
_VoipCommonDecode(VOIPCOMMON_CODEDCHAN_ALL, pVoipCommon->iDefaultSharedChannels, pVoipCommon->uDefaultSharedModes);
|
|
}
|
|
// if everyone is subscribed to the channel (or all open) then the uSharedChannelMode is valid
|
|
else if ((iValidUser == (iChannelSubscriber + iChannelAllUser)) && (iChannelSubscriber != 0))
|
|
{
|
|
// if we were set to VOIPCOMMON_CODEDCHAN_NONE but now we are going to make changes, clear out to VOIPCOMMON_CODEDCHAN_ALL first
|
|
if (_VoipCommonEncode(pVoipCommon->iDefaultSharedChannels, pVoipCommon->uDefaultSharedModes) == VOIPCOMMON_CODEDCHAN_NONE)
|
|
{
|
|
_VoipCommonDecode(VOIPCOMMON_CODEDCHAN_ALL, pVoipCommon->iDefaultSharedChannels, pVoipCommon->uDefaultSharedModes);
|
|
}
|
|
pVoipCommon->iDefaultSharedChannels[iEmptySlot] = iChannel;
|
|
pVoipCommon->uDefaultSharedModes[iEmptySlot] = uSharedChannelMode;
|
|
++iEmptySlot;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonComputeEffectiveUserRecvMask
|
|
|
|
\Description
|
|
Compute effective user recv mask from two other masks: user-selected
|
|
recv mask and mask obtained from voip channel config
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonComputeEffectiveUserRecvMask(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
VoipCommonSetMask(&pVoipCommon->Connectionlist.uUserRecvMask, pVoipCommon->uUserSpkrValue & pVoipCommon->uChanRecvMask, "urecvmask");
|
|
#if defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
|
|
pVoipCommon->Connectionlist.bApplyRelFromMuting = TRUE; // to reflect these changes in the communication relationship
|
|
#endif
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonSetChannels
|
|
|
|
\Description
|
|
Set the active voip channel (coded value of channels and modes)
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input uChannels - channels value we are setting for the user
|
|
\Input iUserIndex - index of user we are performing the operation on
|
|
|
|
\Output
|
|
int32_t - zero=success, negative=failure
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _VoipCommonSetChannels(VoipCommonRefT *pVoipCommon, uint32_t uChannels, int32_t iUserIndex)
|
|
{
|
|
if ((iUserIndex >= 0) && (iUserIndex < VOIP_MAXLOCALUSERS))
|
|
{
|
|
NetPrintf(("voipcommon: setting voip channels (0x%08x) for local user index %d\n", uChannels, iUserIndex));
|
|
pVoipCommon->Connectionlist.aChannels[iUserIndex] = uChannels;
|
|
return(0);
|
|
}
|
|
else if (iUserIndex == VOIP_SHARED_USER_INDEX)
|
|
{
|
|
NetPrintf(("voipcommon: setting voip channels (0x%08x) for local shared user\n", uChannels));
|
|
pVoipCommon->Connectionlist.aChannels[iUserIndex] = uChannels;
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: warning - setting voip channels for invalid local user index %d\n", iUserIndex));
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonSetSharedUserChannelConfig
|
|
|
|
\Description
|
|
Set the shared user channel config to custom or default based on the
|
|
bUseDefaultSharedChannelConfig flag.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
|
|
\Version 12/16/2014 (tcho)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonSetSharedUserChannelConfig(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
int32_t iMaxConcurrentChannel;
|
|
int32_t iSharedUserIndex = VOIP_SHARED_USER_INDEX;
|
|
|
|
for (iMaxConcurrentChannel = 0; iMaxConcurrentChannel < VOIP_MAX_CONCURRENT_CHANNEL; ++iMaxConcurrentChannel)
|
|
{
|
|
if (pVoipCommon->bUseDefaultSharedChannelConfig)
|
|
{
|
|
pVoipCommon->iLocalChannels[iSharedUserIndex][iMaxConcurrentChannel] = pVoipCommon->iDefaultSharedChannels[iMaxConcurrentChannel];
|
|
pVoipCommon->uLocalModes[iSharedUserIndex][iMaxConcurrentChannel] = pVoipCommon->uDefaultSharedModes[iMaxConcurrentChannel];
|
|
}
|
|
else
|
|
{
|
|
pVoipCommon->iLocalChannels[iSharedUserIndex][iMaxConcurrentChannel] = pVoipCommon->iCustomSharedChannels[iMaxConcurrentChannel];
|
|
pVoipCommon->uLocalModes[iSharedUserIndex][iMaxConcurrentChannel] = pVoipCommon->uCustomSharedModes[iMaxConcurrentChannel];
|
|
}
|
|
}
|
|
|
|
// encdoe the channel selection and set the active voip channels
|
|
pVoipCommon->uLocalChannelSelection[iSharedUserIndex] = _VoipCommonEncode(pVoipCommon->iLocalChannels[iSharedUserIndex], pVoipCommon->uLocalModes[iSharedUserIndex]);
|
|
_VoipCommonSetChannels(pVoipCommon, pVoipCommon->uLocalChannelSelection[iSharedUserIndex], iSharedUserIndex);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonCallback
|
|
|
|
\Description
|
|
Default (empty) user callback function.
|
|
|
|
\Input *pVoip - voip module state
|
|
\Input eCbType - type of event
|
|
\Input iValue - event-specific information
|
|
\Input *pUserData - callback user data
|
|
|
|
\Output
|
|
None.
|
|
|
|
\Version 02/10/2006 (jbrookes)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
static void _VoipCommonCallback(VoipRefT *pVoip, VoipCbTypeE eCbType, int32_t iValue, void *pUserData)
|
|
{
|
|
}
|
|
|
|
#if defined(DIRTYCODE_PS4)
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonDisplayRemoteTextDataCb
|
|
|
|
\Description
|
|
Callback to handle receiving a transcribed text packet from a remote peer.
|
|
(once permission check has been validated in voipheadset)
|
|
|
|
\Input *pRemoteUser - transcribed text's originator
|
|
\Input *pStrUtf - transcribed text
|
|
\Input *pUserData - user data
|
|
|
|
\Version 04/04/2019 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonDisplayRemoteTextDataCb(const VoipUserT *pRemoteUser, const char *pStrUtf8, void *pUserData)
|
|
{
|
|
int32_t iConnectionIndex, iRemoteUserIndex = 0;
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
uint32_t bFound = FALSE;
|
|
|
|
for (iConnectionIndex = 0; iConnectionIndex < pVoipCommon->Connectionlist.iMaxConnections; iConnectionIndex++)
|
|
{
|
|
VoipConnectionT *pConnection = &pVoipCommon->Connectionlist.pConnections[iConnectionIndex];
|
|
|
|
for (iRemoteUserIndex = 0; iRemoteUserIndex < VOIP_MAXLOCALUSERS_EXTENDED; iRemoteUserIndex++)
|
|
{
|
|
if (VOIP_SameUser(pRemoteUser, (VoipUserT *)&pConnection->RemoteUsers[iRemoteUserIndex]))
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound == TRUE)
|
|
{
|
|
if (pVoipCommon->pDisplayTranscribedTextCb != NULL)
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb(iConnectionIndex, iRemoteUserIndex, pStrUtf8, pVoipCommon->pDisplayTranscribedTextUserData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: failed to find matching remote user for originator of transcribed text\n"));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonReceiveTextDataCb
|
|
|
|
\Description
|
|
Callback to handle receiving a transcribed text packet from a remote peer.
|
|
|
|
\Input *pSourceUser - transcribed text's originator
|
|
\Input *pStrUtf - transcribed text
|
|
\Input *pUserData - user data
|
|
|
|
\Version 05/02/2017 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonReceiveTextDataNativeCb(const VoipUserT *pSourceUser, const char *pStrUtf8, void *pUserData)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
|
|
if (pVoipCommon->pDisplayTranscribedTextCb != NULL)
|
|
{
|
|
int32_t iConnectionIndex, iUserIndex;
|
|
|
|
// see if a local user sent this text (seeing what they said)
|
|
for (iUserIndex = 0; iUserIndex < VOIP_MAXLOCALUSERS; iUserIndex++)
|
|
{
|
|
int64_t iLocalPersonaId;
|
|
if (NetConnStatus('peid', iUserIndex, &iLocalPersonaId, sizeof(iLocalPersonaId)) == 0)
|
|
{
|
|
if (iLocalPersonaId == pSourceUser->AccountInfo.iPersonaId)
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb(-1, iUserIndex, pStrUtf8, pVoipCommon->pDisplayTranscribedTextUserData);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// search for a remote user who sent this text
|
|
for (iConnectionIndex = 0; iConnectionIndex < pVoipCommon->Connectionlist.iMaxConnections; iConnectionIndex++)
|
|
{
|
|
VoipConnectionT *pConnection = &pVoipCommon->Connectionlist.pConnections[iConnectionIndex];
|
|
|
|
for (iUserIndex = 0; iUserIndex < VOIP_MAXLOCALUSERS_EXTENDED; iUserIndex++)
|
|
{
|
|
if (VOIP_SameUser(pSourceUser, &pConnection->RemoteUsers[iUserIndex]))
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb(iConnectionIndex, iUserIndex, pStrUtf8, pVoipCommon->pDisplayTranscribedTextUserData);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// we didn't find a local or remote user who sent this text, just drop it but complain
|
|
NetPrintf(("voipcommon: failed to find matching originator of transcribed text; user: %lld, text: %s\n", pSourceUser->AccountInfo.iPersonaId, pStrUtf8));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _VoipCommonReceiveTextDataCb
|
|
|
|
\Description
|
|
Callback to handle receiving a transcribed text packet from a remote peer.
|
|
|
|
\Input iConnId - connection index
|
|
\Input iRemoteUserIndex - index of remote user
|
|
\Input *pStrUtf8 - pointer to beginning of text
|
|
\Input *pUserData - user data
|
|
|
|
\Version 05/02/2017 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _VoipCommonReceiveTextDataCb(int32_t iConnId, int32_t iRemoteUserIndex, const char *pStrUtf8, void *pUserData)
|
|
{
|
|
VoipCommonRefT *pVoipCommon = (VoipCommonRefT *)pUserData;
|
|
|
|
if (pVoipCommon->pDisplayTranscribedTextCb != NULL)
|
|
{
|
|
#if defined(DIRTYCODE_PS4)
|
|
VoipUserT VoipUser;
|
|
uint32_t uConnUserPair;
|
|
|
|
// initialize variable used with VoipStatus('rcvu'). most-significant 16 bits = remote user index, least-significant 16 bits = conn index
|
|
uConnUserPair = iConnId;
|
|
uConnUserPair |= (iRemoteUserIndex << 16);
|
|
|
|
// find out if there is a valid remote user for that connId/userId pair
|
|
if (VoipStatus(VoipGetRef(), 'rcvu', (int32_t)uConnUserPair, &VoipUser, sizeof(VoipUser)) == 0)
|
|
{
|
|
VoipHeadsetTranscribedTextPermissionCheck(pVoipCommon->pHeadset, &VoipUser, pStrUtf8);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: 'transcribed text received' event dropped because voipheadset can't find remote user index %d on connection %d\n", iRemoteUserIndex, iConnId));
|
|
}
|
|
#else
|
|
pVoipCommon->pDisplayTranscribedTextCb(iConnId, iRemoteUserIndex, pStrUtf8, pVoipCommon->pDisplayTranscribedTextUserData);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*** Public functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonGetRef
|
|
|
|
\Description
|
|
Return current module reference.
|
|
|
|
\Output
|
|
VoipRefT * - reference pointer, or NULL if the module is not active
|
|
|
|
\Version 03/08/2004 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
VoipRefT *VoipCommonGetRef(void)
|
|
{
|
|
// return pointer to module state
|
|
return(_Voip_pRef);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonStartup
|
|
|
|
\Description
|
|
Start up common functionality
|
|
|
|
\Input iMaxPeers - maximum number of peers supported (up to VOIP_MAXCONNECT)
|
|
\Input iVoipRefSize - size of voip ref to allocate
|
|
\Input *pStatusCb - headset status callback
|
|
\Input iData - platform-specific
|
|
|
|
\Output
|
|
VoipRefT * - voip ref if successful; else NULL
|
|
|
|
\Version 12/02/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
VoipRefT *VoipCommonStartup(int32_t iMaxPeers, int32_t iVoipRefSize, VoipHeadsetStatusCbT *pStatusCb, int32_t iData)
|
|
{
|
|
int32_t iMemGroup;
|
|
void *pMemGroupUserData;
|
|
VoipCommonRefT *pVoipCommon;
|
|
int32_t i;
|
|
|
|
// make sure we're not already started
|
|
if (_Voip_pRef != NULL)
|
|
{
|
|
NetPrintf(("voipcommon: module startup called when not in a shutdown state\n"));
|
|
return(NULL);
|
|
}
|
|
|
|
// Query current mem group data
|
|
DirtyMemGroupQuery(&iMemGroup, &pMemGroupUserData);
|
|
|
|
// create and initialize module state
|
|
if ((pVoipCommon = (VoipCommonRefT *)DirtyMemAlloc(iVoipRefSize, VOIP_MEMID, iMemGroup, pMemGroupUserData)) == NULL)
|
|
{
|
|
NetPrintf(("voipcommon: unable to allocate module state\n"));
|
|
return(NULL);
|
|
}
|
|
ds_memclr(pVoipCommon, iVoipRefSize);
|
|
|
|
// set voip memgroup
|
|
VoipCommonMemGroupSet(iMemGroup, pMemGroupUserData);
|
|
|
|
// by default, user-selected micr and spkr flag always default to ON
|
|
pVoipCommon->uUserMicrValue = 0xFFFFFFFF;
|
|
pVoipCommon->uUserSpkrValue = 0xFFFFFFFF;
|
|
|
|
// create thread critical section
|
|
NetCritInit(&pVoipCommon->ThreadCrit, "voip");
|
|
|
|
// create block list
|
|
if ((pVoipCommon->pBlockList = VoipBlockListCreate()) == NULL)
|
|
{
|
|
NetPrintf(("voipcommon: unable to allocate block list\n"));
|
|
VoipCommonShutdown(pVoipCommon);
|
|
return(NULL);
|
|
}
|
|
|
|
// create connection list
|
|
if (VoipConnectionStartup(&pVoipCommon->Connectionlist, iMaxPeers) < 0)
|
|
{
|
|
NetPrintf(("voipcommon: unable to allocate connectionlist\n"));
|
|
VoipCommonShutdown(pVoipCommon);
|
|
return(NULL);
|
|
}
|
|
|
|
// create headset module
|
|
if ((pVoipCommon->pHeadset = VoipHeadsetCreate(iMaxPeers, &_VoipCommonMicDataCb, &_VoipCommonTextDataCb, &_VoipCommonOpaqueDataCb, pStatusCb, pVoipCommon, iData)) == NULL)
|
|
{
|
|
NetPrintf(("voipcommon: unable to create VoipHeadset layer\n"));
|
|
VoipCommonShutdown(pVoipCommon);
|
|
return(NULL);
|
|
}
|
|
|
|
// turn on default shared channel config by default
|
|
pVoipCommon->bUseDefaultSharedChannelConfig = TRUE;
|
|
|
|
// set up connectionlist callback interface
|
|
#if defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
|
|
VoipConnectionSetCallbacks(&pVoipCommon->Connectionlist, &VoipHeadsetReceiveVoiceDataCb, (void *)pVoipCommon->pHeadset,
|
|
NULL, NULL,
|
|
&VoipHeadsetRegisterUserCb, (void *)pVoipCommon->pHeadset,
|
|
&VoipHeadsetReceiveOpaqueDataCb, (void *)pVoipCommon->pHeadset);
|
|
|
|
VoipHeadsetSetTranscribedTextReceivedCallback(pVoipCommon->pHeadset, &_VoipCommonReceiveTextDataNativeCb, (void *)pVoipCommon);
|
|
#else
|
|
#if defined(DIRTYCODE_PS4)
|
|
VoipHeadsetSetTranscribedTextReceivedCallback(pVoipCommon->pHeadset, &_VoipCommonDisplayRemoteTextDataCb, (void *)pVoipCommon);
|
|
#endif
|
|
|
|
VoipConnectionSetCallbacks(&pVoipCommon->Connectionlist, &VoipHeadsetReceiveVoiceDataCb, (void *)pVoipCommon->pHeadset,
|
|
&_VoipCommonReceiveTextDataCb, (void *)pVoipCommon,
|
|
&VoipHeadsetRegisterUserCb, (void *)pVoipCommon->pHeadset,
|
|
NULL, (void *)pVoipCommon->pHeadset);
|
|
#endif
|
|
|
|
// add callback idle function
|
|
VoipCommonSetEventCallback(pVoipCommon, NULL, NULL);
|
|
pVoipCommon->uLastFrom = pVoipCommon->Connectionlist.uRecvVoice;
|
|
for (i = 0; i < VOIP_MAXLOCALUSERS; ++i)
|
|
{
|
|
pVoipCommon->uLastLocalStatus[i] = pVoipCommon->Connectionlist.uLocalUserStatus[i];
|
|
}
|
|
NetConnIdleAdd(_VoipIdle, pVoipCommon);
|
|
|
|
// save ref
|
|
_Voip_pRef = (VoipRefT *)pVoipCommon;
|
|
return(_Voip_pRef);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonShutdown
|
|
|
|
\Description
|
|
Shutdown common functionality
|
|
|
|
\Input *pVoipCommon - common module state
|
|
|
|
\Version 12/02/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonShutdown(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
void *pMemGroupUserData;
|
|
int32_t iMemGroup;
|
|
|
|
// del callback idle function
|
|
if (_Voip_pRef)
|
|
{
|
|
NetConnIdleDel(_VoipIdle, pVoipCommon);
|
|
}
|
|
|
|
// destroy headset module
|
|
if (pVoipCommon->pHeadset)
|
|
{
|
|
VoipHeadsetDestroy(pVoipCommon->pHeadset);
|
|
}
|
|
|
|
// shut down connectionlist
|
|
if (pVoipCommon->Connectionlist.pConnections)
|
|
{
|
|
VoipConnectionShutdown(&pVoipCommon->Connectionlist);
|
|
}
|
|
|
|
// destroy the block list
|
|
if (pVoipCommon->pBlockList)
|
|
{
|
|
VoipBlockListDestroy((VoipRefT *)pVoipCommon);
|
|
}
|
|
|
|
// destroy critical section
|
|
NetCritKill(&pVoipCommon->ThreadCrit);
|
|
|
|
// free module memory
|
|
VoipCommonMemGroupQuery(&iMemGroup, &pMemGroupUserData);
|
|
DirtyMemFree(pVoipCommon, VOIP_MEMID, iMemGroup, pMemGroupUserData);
|
|
|
|
// clear pointer to module state
|
|
_Voip_pRef = NULL;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonMemGroupQuery
|
|
|
|
\Description
|
|
Get VoIP mem group data.
|
|
|
|
\Input *pMemGroup - [OUT param] pointer to variable to be filled with mem group id
|
|
\Input **ppMemGroupUserData - [OUT param] pointer to variable to be filled with pointer to user data
|
|
|
|
\Version 1.0 11/11/2005 (jbrookes) First Version
|
|
\Version 1.1 11/18/2008 (mclouatre) returned values now passed in [OUT] parameters
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonMemGroupQuery(int32_t *pMemGroup, void **ppMemGroupUserData)
|
|
{
|
|
*pMemGroup = _Voip_iMemGroup;
|
|
*ppMemGroupUserData = _Voip_pMemGroupUserData;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonMemGroupSet
|
|
|
|
\Description
|
|
Set VoIP mem group data.
|
|
|
|
\Input iMemGroup - mem group to set
|
|
\Input *pMemGroupUserData - user data associated with mem group
|
|
|
|
\Version 1.0 11/11/2005 (jbrookes) First Version
|
|
\Version 1.1 11/18/2008 (mclouatre) Adding second parameter (user data)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonMemGroupSet(int32_t iMemGroup, void *pMemGroupUserData)
|
|
{
|
|
_Voip_iMemGroup = iMemGroup;
|
|
_Voip_pMemGroupUserData = pMemGroupUserData;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonUpdateRemoteStatus
|
|
|
|
\Description
|
|
Process mute list, and set appropriate flags/priority for each remote user.
|
|
|
|
\Input *pVoipCommon - pointer to module state
|
|
|
|
\Version 08/23/2005 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonUpdateRemoteStatus(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
uint32_t uSendMask, uRecvMask, uChannelMask, bEnabled;
|
|
int32_t iConnection;
|
|
int32_t bTextTranscriptionEnabled = FALSE;
|
|
int32_t iLocalUserIndex;
|
|
|
|
// process all active channels
|
|
for (iConnection = 0; iConnection < pVoipCommon->Connectionlist.iMaxConnections; iConnection++)
|
|
{
|
|
VoipConnectionT *pConnection = &pVoipCommon->Connectionlist.pConnections[iConnection];
|
|
|
|
// if not active, don't process
|
|
if (pConnection->eState != ST_ACTV)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// calculate channel mask
|
|
uChannelMask = 1 << iConnection;
|
|
|
|
// decide whether this channel should be enabled or not
|
|
bEnabled = pVoipCommon->bPrivileged;
|
|
|
|
// set send/recv masks based on enable + user send override
|
|
if (bEnabled && ((pVoipCommon->Connectionlist.uUserSendMask & uChannelMask) != 0))
|
|
{
|
|
uSendMask = pVoipCommon->Connectionlist.uSendMask | uChannelMask;
|
|
}
|
|
else
|
|
{
|
|
uSendMask = pVoipCommon->Connectionlist.uSendMask & ~uChannelMask;
|
|
}
|
|
|
|
// set send/recv masks based on enable + user recv override
|
|
if (bEnabled && ((pVoipCommon->Connectionlist.uUserRecvMask & uChannelMask) != 0))
|
|
{
|
|
uRecvMask = pVoipCommon->Connectionlist.uRecvMask | uChannelMask;
|
|
}
|
|
else
|
|
{
|
|
uRecvMask = pVoipCommon->Connectionlist.uRecvMask & ~uChannelMask;
|
|
}
|
|
|
|
// set send/recv masks and priority
|
|
VoipConnectionSetSendMask(&pVoipCommon->Connectionlist, uSendMask);
|
|
VoipConnectionSetRecvMask(&pVoipCommon->Connectionlist, uRecvMask);
|
|
|
|
if ((pConnection->bTranscribedTextRequested) && (pVoipCommon->Connectionlist.uSendMask & (1 << iConnection)))
|
|
{
|
|
// enable local text transcription because at least one remote user requested transcribed text
|
|
bTextTranscriptionEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
/* We also want text transcription locally enabled if any local user is requesting text transcription
|
|
from remote users. Motivation: a hearing-impaired person requesting transcribed text from other
|
|
players also wants to see transcribed text for his own speech (request from EA's accessibility team). */
|
|
for (iLocalUserIndex = 0; iLocalUserIndex < VOIP_MAXLOCALUSERS; iLocalUserIndex++)
|
|
{
|
|
if (pVoipCommon->Connectionlist.bTranscribedTextRequested[iLocalUserIndex] == TRUE)
|
|
{
|
|
bTextTranscriptionEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bTextTranscriptionEnabled != pVoipCommon->bTextTranscriptionEnabled)
|
|
{
|
|
NetPrintf(("voipcommon: %s text transcription locally\n", bTextTranscriptionEnabled?"enabling":"disabling"));
|
|
pVoipCommon->bTextTranscriptionEnabled = bTextTranscriptionEnabled;
|
|
VoipHeadsetControl(pVoipCommon->pHeadset, 'tran', bTextTranscriptionEnabled, 0, NULL);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonStatus
|
|
|
|
\Description
|
|
Return status.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iSelect - status selector
|
|
\Input iValue - selector-specific
|
|
\Input *pBuf - [out] storage for selector-specific output
|
|
\Input iBufSize - size of output buffer
|
|
|
|
\Output
|
|
int32_t - selector-specific data
|
|
|
|
\Notes
|
|
Allowed selectors:
|
|
|
|
\verbatim
|
|
'avlb' - whether a given ConnID is available
|
|
'chan' - retrieve the active voip channel (coded value of channels and modes)
|
|
'chnc' - return the count of channel slots used by the voip group manager
|
|
'chnl' - return the channel id and channel mode associated with specified channel slot
|
|
'from' - bitfield indicating which peers are talking
|
|
'hset' - bitfield indicating which ports have headsets
|
|
'lprt' - return local socket port
|
|
'luvu' - return voipuser of specified local user
|
|
'maxc' - return max connections
|
|
'mgrp' - voip memgroup user id
|
|
'mgud' - voip memgroup user data
|
|
'micr' - who we're sending voice to
|
|
'rchn' - retrieve the active voip channel of a remote peer (coded value of channels and modes)
|
|
'rcvu' - return voipuser of specified remote user (connection and user index)
|
|
'shch' - return bUseDefaultSharedChannelConfig which indicates if the default shared channel config is used
|
|
'sock' - voip socket ref
|
|
'spkr' - who we're accepting voice from
|
|
'umic' - user-specified microphone send list
|
|
'uspk' - user-specified microphone recv list
|
|
\endverbatim
|
|
|
|
\Version 12/02/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonStatus(VoipCommonRefT *pVoipCommon, int32_t iSelect, int32_t iValue, void *pBuf, int32_t iBufSize)
|
|
{
|
|
if (iSelect == 'avlb')
|
|
{
|
|
return(VoipConnectionCanAllocate(&pVoipCommon->Connectionlist, iValue));
|
|
}
|
|
if (iSelect == 'chan')
|
|
{
|
|
return(pVoipCommon->Connectionlist.aChannels[iValue]);
|
|
}
|
|
if (iSelect == 'chnc')
|
|
{
|
|
return(VOIP_MAX_CONCURRENT_CHANNEL);
|
|
}
|
|
if (iSelect == 'chnl')
|
|
{
|
|
int32_t iUserIndex = iValue & 0xFFFF;
|
|
int32_t iChannelSlot = iValue >> 16;
|
|
|
|
if (!pBuf)
|
|
{
|
|
NetPrintf(("voipcommon: pBuf must be valid with the 'chnl' selector\n"));
|
|
return(-1);
|
|
}
|
|
|
|
if ((unsigned)iBufSize < sizeof(VoipChanModeE))
|
|
{
|
|
NetPrintf(("voipcommon: user buffer used with the 'chnl' selector is too small (expected size = %d; current size =%d)\n",
|
|
sizeof(VoipChanModeE), iBufSize));
|
|
return(-2);
|
|
}
|
|
|
|
if ((iChannelSlot < 0) || (iChannelSlot >= VOIP_MAX_CONCURRENT_CHANNEL))
|
|
{
|
|
NetPrintf(("voipcommon: invalid slot id (%d) used with 'chnl' selector; valid range is [0,%d]\n", iChannelSlot, VOIP_MAX_CONCURRENT_CHANNEL-1));
|
|
return(-3);
|
|
}
|
|
|
|
*(VoipChanModeE *)pBuf = pVoipCommon->uLocalModes[iUserIndex][iChannelSlot];
|
|
return(pVoipCommon->iLocalChannels[iUserIndex][iChannelSlot]);
|
|
}
|
|
if (iSelect == 'from')
|
|
{
|
|
return(pVoipCommon->Connectionlist.uRecvVoice);
|
|
}
|
|
if (iSelect == 'hset')
|
|
{
|
|
uint32_t uPortHeadsetStatus = pVoipCommon->uPortHeadsetStatus;
|
|
return(uPortHeadsetStatus);
|
|
}
|
|
if (iSelect == 'lprt')
|
|
{
|
|
return(pVoipCommon->Connectionlist.uBindPort);
|
|
}
|
|
if (iSelect == 'luvu')
|
|
{
|
|
if (pBuf)
|
|
{
|
|
if (iBufSize >= (signed)sizeof(VoipUserT))
|
|
{
|
|
if ((iValue < VOIP_MAXLOCALUSERS_EXTENDED) && (!VOIP_NullUser((VoipUserT *)(&pVoipCommon->Connectionlist.LocalUsers[iValue]))))
|
|
{
|
|
// copy user id in caller-provided buffer
|
|
ds_memcpy(pBuf, &pVoipCommon->Connectionlist.LocalUsers[iValue], sizeof(VoipUserT));
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('luvu') error --> iBufSize (%d) not big enough (needs to be at least %d bytes)\n",
|
|
iBufSize, sizeof(VoipUserT)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('luvu') error --> pBuf cannot be NULL\n"));
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
if (iSelect == 'maxc')
|
|
{
|
|
return(pVoipCommon->Connectionlist.iMaxConnections);
|
|
}
|
|
if (iSelect == 'mgrp')
|
|
{
|
|
int32_t iMemGroup;
|
|
void *pMemGroupUserData;
|
|
|
|
// Query mem group data
|
|
VoipCommonMemGroupQuery(&iMemGroup, &pMemGroupUserData);
|
|
|
|
// return mem group id
|
|
return(iMemGroup);
|
|
}
|
|
if (iSelect == 'mgud')
|
|
{
|
|
// make sure user-provided buffer is large enough to receive a pointer
|
|
if ((pBuf != NULL) && (iBufSize >= (signed)sizeof(void *)))
|
|
{
|
|
int32_t iMemGroup;
|
|
void *pMemGroupUserData;
|
|
|
|
// Query mem group data
|
|
VoipCommonMemGroupQuery(&iMemGroup, &pMemGroupUserData);
|
|
|
|
// fill [out] parameter with pointer to mem group user data
|
|
*((void **)pBuf) = pMemGroupUserData;
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
// unhandled
|
|
return(-1);
|
|
}
|
|
}
|
|
if (iSelect == 'micr')
|
|
{
|
|
return(pVoipCommon->Connectionlist.uSendMask);
|
|
}
|
|
if (iSelect == 'rchn')
|
|
{
|
|
if (pBuf)
|
|
{
|
|
if (iBufSize == sizeof(uint32_t))
|
|
{
|
|
// pBut is used as an input and an output parameter
|
|
// input -> user index
|
|
// output -> returned channels
|
|
int32_t iUserIndex = *(uint32_t *)pBuf;
|
|
*(uint32_t *)pBuf = pVoipCommon->Connectionlist.pConnections[iValue].aRecvChannels[iUserIndex];
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('rchn') error for conn id %d --> iBufSize (%d) does not match expected size (%d)\n",
|
|
iValue, iBufSize, sizeof(int32_t)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('rchn') error for conn id %d --> pBuf cannot be NULL\n", iValue));
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
if (iSelect == 'rcvu')
|
|
{
|
|
int32_t iConnIndex = iValue & 0xFFFF;
|
|
int32_t iRemoteUserIndex = iValue >> 16;
|
|
|
|
if (pBuf)
|
|
{
|
|
if (iBufSize >= (signed)sizeof(VoipUserT))
|
|
{
|
|
if (pVoipCommon->Connectionlist.pConnections[iConnIndex].eState != ST_DISC)
|
|
{
|
|
if ((iRemoteUserIndex < VOIP_MAXLOCALUSERS_EXTENDED) && (!VOIP_NullUser((VoipUserT *)(&pVoipCommon->Connectionlist.pConnections[iConnIndex].RemoteUsers[iRemoteUserIndex]))))
|
|
{
|
|
// copy user id in caller-provided buffer
|
|
ds_memcpy(pBuf, &pVoipCommon->Connectionlist.pConnections[iConnIndex].RemoteUsers[iRemoteUserIndex], sizeof(VoipUserT));
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('rcvu') error for conn id %d and remote user index %d --> connection is not active\n",
|
|
iConnIndex, iRemoteUserIndex));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('rcvu') error for conn id %d and remote user index %d --> iBufSize (%d) not big enough (needs to be at least %d bytes)\n",
|
|
iConnIndex, iRemoteUserIndex, iBufSize, sizeof(VoipUserT)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: VoipCommonStatus('rcvu') error for conn id %d and remote user index %d --> pBuf cannot be NULL\n", iConnIndex, iRemoteUserIndex));
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
if (iSelect == 'shch')
|
|
{
|
|
return(pVoipCommon->bUseDefaultSharedChannelConfig);
|
|
}
|
|
if (iSelect == 'sock')
|
|
{
|
|
if (pBuf != NULL)
|
|
{
|
|
if (iBufSize >= (signed)sizeof(pVoipCommon->Connectionlist.pSocket))
|
|
{
|
|
ds_memcpy(pBuf, &pVoipCommon->Connectionlist.pSocket, sizeof(pVoipCommon->Connectionlist.pSocket));
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: socket reference cannot be copied because user buffer is not large enough\n"));
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: socket reference cannot be copied because user buffer pointer is NULL\n"));
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
if (iSelect == 'spkr')
|
|
{
|
|
return(pVoipCommon->Connectionlist.uRecvMask);
|
|
}
|
|
if (iSelect == 'umic')
|
|
{
|
|
return(pVoipCommon->uUserMicrValue);
|
|
}
|
|
if (iSelect == 'uspk')
|
|
{
|
|
return(pVoipCommon->uUserSpkrValue);
|
|
}
|
|
// unrecognized selector, so pass through to voipheadset
|
|
return(VoipHeadsetStatus(pVoipCommon->pHeadset, iSelect, iValue, pBuf, iBufSize));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonControl
|
|
|
|
\Description
|
|
Set control options.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iControl - control selector
|
|
\Input iValue - selector-specific input
|
|
\Input *pValue - selector-specific input
|
|
|
|
\Output
|
|
int32_t - selector-specific output
|
|
|
|
\Notes
|
|
iControl can be one of the following:
|
|
|
|
\verbatim
|
|
'clid' - set local client id
|
|
'flsh' - send currently queued voice data immediately (iValue=connection id)
|
|
'shch' - turn on or the of the default shared channel config. iValue = TRUE to turn, FALSE to turn off
|
|
'stot' - turn on/off (*pValue) STT for local user specified with iValue
|
|
'time' - set data timeout in milliseconds
|
|
'xply' - toggle cross play
|
|
\endverbatim
|
|
|
|
Unhandled selectors are passed through to VoipHeadsetControl()
|
|
|
|
\Version 03/02/2004 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonControl(VoipCommonRefT *pVoipCommon, int32_t iControl, int32_t iValue, void *pValue)
|
|
{
|
|
if (iControl == 'clid')
|
|
{
|
|
if ((pVoipCommon->Connectionlist.uClientId != 0) && (pVoipCommon->Connectionlist.uClientId != (unsigned)iValue))
|
|
{
|
|
NetPrintf(("voipcommon: warning - local client id is being changed from %d to %d\n", pVoipCommon->Connectionlist.uClientId, iValue));
|
|
}
|
|
pVoipCommon->Connectionlist.uClientId = (unsigned)iValue;
|
|
return(0);
|
|
}
|
|
if (iControl == 'flsh')
|
|
{
|
|
return(VoipConnectionFlush(&pVoipCommon->Connectionlist, iValue));
|
|
}
|
|
if (iControl == 'shch')
|
|
{
|
|
pVoipCommon->bUseDefaultSharedChannelConfig = iValue;
|
|
pVoipCommon->bApplyChannelConfig = TRUE;
|
|
NetPrintf(("voipcommon: VoipCommonControl('shch') default shared channel config is %s\n", pVoipCommon->bUseDefaultSharedChannelConfig ? "on" : "off"));
|
|
return(0);
|
|
}
|
|
if (iControl == 'stot')
|
|
{
|
|
uint32_t bEnabled = TRUE; // default to 'enabled'
|
|
int32_t iUserLocalIndex = iValue;
|
|
|
|
if (pValue != NULL)
|
|
{
|
|
bEnabled = *(uint32_t *)pValue;
|
|
}
|
|
|
|
if ((iUserLocalIndex >= 0) && (iUserLocalIndex < VOIP_MAXLOCALUSERS))
|
|
{
|
|
NetPrintf(("voipcommon: %s STT for local user index %d\n", (bEnabled ?"enabling":"disabling"), iUserLocalIndex));
|
|
pVoipCommon->Connectionlist.bTranscribedTextRequested[iUserLocalIndex] = bEnabled;
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: warning invalid local user index %d used with VoipControl('stot')\n", iUserLocalIndex));
|
|
return(-1);
|
|
}
|
|
}
|
|
if (iControl == 'time')
|
|
{
|
|
pVoipCommon->Connectionlist.iDataTimeout = iValue;
|
|
return(0);
|
|
}
|
|
if (iControl == 'xply')
|
|
{
|
|
int32_t iRet;
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
#if defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
|
|
if (iValue == TRUE)
|
|
{
|
|
VoipConnectionSetTextCallback(&pVoipCommon->Connectionlist, &_VoipCommonReceiveTextDataCb, (void *)pVoipCommon);
|
|
}
|
|
else
|
|
{
|
|
VoipConnectionSetTextCallback(&pVoipCommon->Connectionlist, NULL, NULL);
|
|
}
|
|
#endif
|
|
iRet = VoipHeadsetControl(pVoipCommon->pHeadset, 'xply', iValue, 0, pValue);
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
// unhandled selectors are passed through to voipheadset
|
|
if (pVoipCommon)
|
|
{
|
|
return(VoipHeadsetControl(pVoipCommon->pHeadset, iControl, iValue, 0, pValue));
|
|
}
|
|
else
|
|
{
|
|
// some voipheadset control selectors can be used before a call to VoipStartup()
|
|
return(VoipHeadsetControl(NULL, iControl, iValue, 0, pValue));
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonAddMask
|
|
|
|
\Description
|
|
Add (OR) uAddMask into *pMask
|
|
|
|
\Input *pMask - mask to add into
|
|
\Input uAddMask - mask to add (OR)
|
|
\Input *pMaskName - name of mask (for debug logging)
|
|
|
|
\Version 12/03/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonAddMask(uint32_t *pMask, uint32_t uAddMask, const char *pMaskName)
|
|
{
|
|
VoipCommonSetMask(pMask, *pMask | uAddMask, pMaskName);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonDelMask
|
|
|
|
\Description
|
|
Del (&~) uDelMask from *pMask
|
|
|
|
\Input *pMask - mask to del from
|
|
\Input uDelMask - mask to del (&~)
|
|
\Input *pMaskName - name of mask (for debug logging)
|
|
|
|
\Version 12/03/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonDelMask(uint32_t *pMask, uint32_t uDelMask, const char *pMaskName)
|
|
{
|
|
VoipCommonSetMask(pMask, *pMask & ~uDelMask, pMaskName);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSetMask
|
|
|
|
\Description
|
|
Set value of mask (with logging).
|
|
|
|
\Input *pMask - mask to write to
|
|
\Input uNewMask - new mask value
|
|
\Input *pMaskName - name of mask (for debug logging)
|
|
|
|
\Version 12/03/2009 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonSetMask(uint32_t *pMask, uint32_t uNewMask, const char *pMaskName)
|
|
{
|
|
NetPrintf(("voipcommon: %s update: 0x%08x->0x%08x\n", pMaskName, *pMask, uNewMask));
|
|
*pMask = uNewMask;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSelectChannel
|
|
|
|
\Description
|
|
Select the mode(send/recv) of a given channel.
|
|
|
|
\Input *pVoipCommon - common module state
|
|
\Input iUserIndex - local user index
|
|
\Input iChannel - Channel ID (valid range: [0,63])
|
|
\Input eMode - The mode, combination of VOIP_CHANSEND, VOIP_CHANRECV
|
|
|
|
\Output
|
|
int32_t - number of channels remaining that this console could join
|
|
|
|
\Version 01/31/2007 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonSelectChannel(VoipCommonRefT *pVoipCommon, int32_t iUserIndex, int32_t iChannel, VoipChanModeE eMode)
|
|
{
|
|
int32_t iIndex;
|
|
int32_t iSlot = VOIP_MAX_CONCURRENT_CHANNEL;
|
|
int32_t iCount = 0;
|
|
|
|
// if the shared user index is 0xff, the current platform does not support shared channel config feature
|
|
if (iUserIndex != VOIP_SHARED_USER_INDEX)
|
|
{
|
|
if ((iUserIndex < 0) || (iUserIndex >= VOIP_MAXLOCALUSERS))
|
|
{
|
|
NetPrintf(("voipcommon: [channel] warning - attempt to set invalid local channels index %d\n", iUserIndex));
|
|
return(-3);
|
|
}
|
|
}
|
|
|
|
// enforcing the valid ranges
|
|
eMode &= VOIP_CHANSENDRECV;
|
|
iChannel &= 0x3f;
|
|
|
|
// find the slot to store the specified channel and count the slots remaining.
|
|
for(iIndex = 0; iIndex < VOIP_MAX_CONCURRENT_CHANNEL; iIndex++)
|
|
{
|
|
// remember either the slot with the channel we want to set, or if we have found nothing, an empty slot
|
|
if ( ((pVoipCommon->uLocalModes[iUserIndex][iIndex] != VOIP_CHANNONE) && (pVoipCommon->iLocalChannels[iUserIndex][iIndex] == iChannel)) ||
|
|
((pVoipCommon->uLocalModes[iUserIndex][iIndex] == VOIP_CHANNONE) && (iSlot == VOIP_MAX_CONCURRENT_CHANNEL)) )
|
|
{
|
|
iSlot = iIndex;
|
|
}
|
|
// and take the opportunity to count the free slots
|
|
if (pVoipCommon->uLocalModes[iUserIndex][iIndex] == VOIP_CHANNONE)
|
|
{
|
|
iCount++;
|
|
}
|
|
}
|
|
|
|
// no more slots to store the channel selection or
|
|
// the given channel doesn't exist
|
|
if (iSlot == VOIP_MAX_CONCURRENT_CHANNEL)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
//count if we're taking a spot.
|
|
if ((pVoipCommon->uLocalModes[iUserIndex][iSlot] == VOIP_CHANNONE) && (eMode != VOIP_CHANNONE))
|
|
{
|
|
iCount--;
|
|
}
|
|
//count if we're freeing a spot.
|
|
if ((pVoipCommon->uLocalModes[iUserIndex][iSlot] != VOIP_CHANNONE) && (eMode == VOIP_CHANNONE))
|
|
{
|
|
iCount++;
|
|
iChannel = 0; // when freeing a channel reset it back to the 0 to bring us towards the default state
|
|
}
|
|
|
|
// if we are trying to set the shared channel
|
|
if (iUserIndex == VOIP_SHARED_USER_INDEX)
|
|
{
|
|
pVoipCommon->iCustomSharedChannels[iSlot] = iChannel;
|
|
pVoipCommon->uCustomSharedModes[iSlot] = eMode;
|
|
}
|
|
// set the channel and mode in selected slot
|
|
else
|
|
{
|
|
pVoipCommon->iLocalChannels[iUserIndex][iSlot] = iChannel;
|
|
pVoipCommon->uLocalModes[iUserIndex][iSlot] = eMode;
|
|
|
|
NetPrintf(("voipcommon: [channel] set local channel at slot %d: channelId=%d, channelMode=%u for local user index %d\n",
|
|
iSlot, pVoipCommon->iLocalChannels[iUserIndex][iSlot], pVoipCommon->uLocalModes[iUserIndex][iSlot], iUserIndex));
|
|
pVoipCommon->uLocalChannelSelection[iUserIndex] = _VoipCommonEncode(pVoipCommon->iLocalChannels[iUserIndex], pVoipCommon->uLocalModes[iUserIndex]);
|
|
NetPrintf(("voipcommon: [channel] set local channels 0x%08x for local user index %d\n", pVoipCommon->uLocalChannelSelection[iUserIndex], iUserIndex));
|
|
}
|
|
|
|
_VoipCommonSetChannels(pVoipCommon, pVoipCommon->uLocalChannelSelection[iUserIndex], iUserIndex);
|
|
pVoipCommon->bApplyChannelConfig = TRUE;
|
|
|
|
return(iCount);
|
|
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonApplyChannelConfig
|
|
|
|
\Description
|
|
Setup user muting flags based on channel config
|
|
|
|
\Input *pVoipCommon - voip module state
|
|
|
|
\Todo
|
|
Rename this function to indicate that we are applying the peer to peer
|
|
mutes instead of just applying channel configurations. The name we have
|
|
now no longer makes sense.
|
|
|
|
\Version 12/02/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonApplyChannelConfig(VoipCommonRefT *pVoipCommon)
|
|
{
|
|
static uint32_t uLastChanSendMask = 0;
|
|
static uint32_t uLastChanRecvMask = 0;
|
|
int32_t iConnIndex, iLocalUserIndex, iRemoteUserIndex;
|
|
uint32_t uConnUserPair;
|
|
uint8_t bSocialBlocked = FALSE;
|
|
VoipChanModeE eMatch;
|
|
VoipUserT LocalUser;
|
|
|
|
pVoipCommon->uChanRecvMask = pVoipCommon->uChanSendMask = 0;
|
|
pVoipCommon->uUserSendMask = 0;
|
|
|
|
// setup the shared channel, to reflect the channel changes that may have occurred of the local users
|
|
_VoipCommonComputeDefaultSharedChannelConfig(pVoipCommon);
|
|
_VoipCommonSetSharedUserChannelConfig(pVoipCommon);
|
|
|
|
for (iLocalUserIndex = 0; iLocalUserIndex < VOIP_MAXLOCALUSERS_EXTENDED; iLocalUserIndex++)
|
|
{
|
|
// find out if there is a local user for that local user index
|
|
if (VoipStatus(VoipGetRef(), 'luvu', iLocalUserIndex, &LocalUser, sizeof(LocalUser)) == 0)
|
|
{
|
|
for(iConnIndex = 0; iConnIndex < VoipStatus(VoipGetRef(), 'maxc', 0, NULL, 0); iConnIndex++)
|
|
{
|
|
if (pVoipCommon->Connectionlist.pConnections[iConnIndex].eState != ST_DISC)
|
|
{
|
|
for (iRemoteUserIndex = 0; iRemoteUserIndex < VOIP_MAXLOCALUSERS_EXTENDED; iRemoteUserIndex++)
|
|
{
|
|
// initialize variable used with VoipStatus('rcvu'). most-significant 16 bits = remote user index, least-significant 16 bits = conn index
|
|
VoipUserT RemoteUser;
|
|
uConnUserPair = iConnIndex;
|
|
uConnUserPair |= (iRemoteUserIndex << 16);
|
|
|
|
// find out if there is a valid remote user for that connId/userId pair
|
|
if (VoipStatus(VoipGetRef(), 'rcvu', (int32_t)uConnUserPair, &RemoteUser, sizeof(RemoteUser)) == 0)
|
|
{
|
|
uint8_t bFirstPartyBlocked = FALSE;
|
|
eMatch = _VoipCommonChannelMatch(pVoipCommon, iLocalUserIndex, pVoipCommon->uRemoteChannelSelection[iConnIndex][iRemoteUserIndex]);
|
|
|
|
// does the local user have that remote user blocked, if so do not alow voip between them?
|
|
bSocialBlocked = VoipBlockListIsBlocked((VoipRefT *)pVoipCommon, iLocalUserIndex, RemoteUser.AccountInfo.iAccountId);
|
|
|
|
// apply first party mute list block
|
|
if (VoipHeadsetStatus(pVoipCommon->pHeadset, 'fpml', iLocalUserIndex, &RemoteUser, sizeof(RemoteUser)) > 0)
|
|
{
|
|
bFirstPartyBlocked = TRUE;
|
|
}
|
|
|
|
// update send mask
|
|
if (!bFirstPartyBlocked && !bSocialBlocked && (eMatch & VOIP_CHANSEND))
|
|
{
|
|
pVoipCommon->uChanSendMask |= (1 << iConnIndex);
|
|
pVoipCommon->uUserSendMask |= (1 << iLocalUserIndex);
|
|
}
|
|
|
|
// update receive mask and user-specific playback config
|
|
if (!bFirstPartyBlocked && !bSocialBlocked && (eMatch & VOIP_CHANRECV))
|
|
{
|
|
pVoipCommon->uChanRecvMask |= (1 << iConnIndex);
|
|
|
|
// remote users exist in the connection list before they are registered with voipheadset later in the voip thread
|
|
// therefore we must make sure the remote user is registered with voip headset before applying voice playback
|
|
if (VoipHeadsetStatus(pVoipCommon->pHeadset, 'ruvu', 0, &RemoteUser, sizeof(RemoteUser)))
|
|
{
|
|
// enable playback of the remote user's voice for the specified local user
|
|
VoipControl(VoipGetRef(), '+pbk', iLocalUserIndex, &RemoteUser);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// remote users exist in the connection list before they are registered with voipheadset later in the voip thread
|
|
// therefore we must make sure the remote user is registered with voip headset before applying voice playback
|
|
if (VoipHeadsetStatus(pVoipCommon->pHeadset, 'ruvu', 0, &RemoteUser, sizeof(RemoteUser)))
|
|
{
|
|
// disable playback of the remote user's voice for the specified local user
|
|
VoipControl(VoipGetRef(), '-pbk', iLocalUserIndex, &RemoteUser);
|
|
}
|
|
}
|
|
} // if
|
|
} // for
|
|
} // if
|
|
} // for
|
|
} // if
|
|
} // for
|
|
|
|
if (uLastChanSendMask != pVoipCommon->uChanSendMask)
|
|
{
|
|
NetPrintf(("voipcommon: uChanSendMask is now 0x%08x\n", pVoipCommon->uChanSendMask));
|
|
uLastChanSendMask = pVoipCommon->uChanSendMask;
|
|
}
|
|
|
|
if (uLastChanRecvMask != pVoipCommon->uChanRecvMask)
|
|
{
|
|
NetPrintf(("voipcommon: uChanRecvMask is now 0x%08x\n", pVoipCommon->uChanRecvMask));
|
|
uLastChanRecvMask = pVoipCommon->uChanRecvMask;
|
|
}
|
|
|
|
_VoipCommonComputeEffectiveUserSendMask(pVoipCommon);
|
|
_VoipCommonComputeEffectiveUserRecvMask(pVoipCommon);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonResetChannels
|
|
|
|
\Description
|
|
Resets the channels selection to defaults. Sends and receives to all
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iUserIndex - local user index
|
|
|
|
\Version 12/07/2009 (jrainy)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonResetChannels(VoipCommonRefT *pVoipCommon, int32_t iUserIndex)
|
|
{
|
|
// if the default config is on ignore the channel reset on the shared user
|
|
if ((pVoipCommon->bUseDefaultSharedChannelConfig) && (iUserIndex == VOIP_SHARED_USER_INDEX))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((iUserIndex < 0 || iUserIndex >= VOIP_MAXLOCALUSERS) && iUserIndex != VOIP_SHARED_USER_INDEX)
|
|
{
|
|
NetPrintf(("voipcommon: [channel] warning - attempt to reset invalid local channels index %d\n", iUserIndex));
|
|
return;
|
|
}
|
|
|
|
_VoipCommonDecode(VOIPCOMMON_CODEDCHAN_ALL, pVoipCommon->iLocalChannels[iUserIndex], pVoipCommon->uLocalModes[iUserIndex]);
|
|
|
|
pVoipCommon->uLocalChannelSelection[iUserIndex] = _VoipCommonEncode(pVoipCommon->iLocalChannels[iUserIndex], pVoipCommon->uLocalModes[iUserIndex]);
|
|
NetPrintf(("voipcommon: [channel] set local channels 0x%08x\n", pVoipCommon->uLocalChannelSelection[iUserIndex]));
|
|
|
|
if (VoipGetRef() != NULL)
|
|
{
|
|
_VoipCommonSetChannels(pVoipCommon, pVoipCommon->uLocalChannelSelection[iUserIndex], iUserIndex);
|
|
pVoipCommon->bApplyChannelConfig = TRUE;
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonMicrophone
|
|
|
|
\Description
|
|
Select which peers to send voice to
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input uUserMicrValue - microphone bit values
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonMicrophone(VoipCommonRefT *pVoipCommon, uint32_t uUserMicrValue)
|
|
{
|
|
NetPrintf(("voipcommon: uUserMicrValue changed from 0x%08x to 0x%08x\n", pVoipCommon->uUserMicrValue, uUserMicrValue));
|
|
pVoipCommon->uUserMicrValue = uUserMicrValue;
|
|
_VoipCommonComputeEffectiveUserSendMask(pVoipCommon);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSpeaker
|
|
|
|
\Description
|
|
Select which peers to accept voice from
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input uUserSpkrValue - speaker bit values
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonSpeaker(VoipCommonRefT *pVoipCommon, uint32_t uUserSpkrValue)
|
|
{
|
|
NetPrintf(("voipcommon: uUserSpkrValue changed from 0x%08x to 0x%08x\n", pVoipCommon->uUserSpkrValue, uUserSpkrValue));
|
|
pVoipCommon->uUserSpkrValue = uUserSpkrValue;
|
|
_VoipCommonComputeEffectiveUserRecvMask(pVoipCommon);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonConnectionSharingAddSession
|
|
|
|
\Description
|
|
Add session id to share a specified voip connection
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnId - connection id
|
|
\Input uSessionId - session id we are adding
|
|
|
|
\Output
|
|
int32_t - zero=success, negative=failure
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonConnectionSharingAddSession(VoipCommonRefT *pVoipCommon, int32_t iConnId, uint32_t uSessionId)
|
|
{
|
|
int32_t iRetCode;
|
|
|
|
// acquire critical section to modify ConnectionList
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
iRetCode = VoipConnectionAddSessionId(&pVoipCommon->Connectionlist, iConnId, uSessionId);
|
|
|
|
// release critical section to modify ConnectionList
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
|
|
return(iRetCode);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonConnectionSharingDelSession
|
|
|
|
\Description
|
|
Remove session id from sharing a specified voip connection
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnId - connection id
|
|
\Input uSessionId - session id we are removing
|
|
|
|
\Output
|
|
int32_t - zero=success, negative=failure
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonConnectionSharingDelSession(VoipCommonRefT* pVoipCommon, int32_t iConnId, uint32_t uSessionId)
|
|
{
|
|
int32_t iRetCode;
|
|
|
|
// acquire critical section to modify ConnectionList
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
iRetCode = VoipConnectionDeleteSessionId(&pVoipCommon->Connectionlist, iConnId, uSessionId);
|
|
|
|
// release critical section to modify ConnectionList
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
|
|
return(iRetCode);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonMapVoipServerId
|
|
|
|
\Description
|
|
For server-based voip, maps a local conn id to a voipserver conn id
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iLocalConnId - local connection id
|
|
\Input iVoipServerConnId - voipserver connection id
|
|
|
|
\Output
|
|
int32_t - zero=success, negative=failure
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonMapVoipServerId(VoipCommonRefT *pVoipCommon, int32_t iLocalConnId, int32_t iVoipServerConnId)
|
|
{
|
|
if (pVoipCommon->Connectionlist.pConnections[iLocalConnId].eState != ST_DISC)
|
|
{
|
|
NetPrintf(("voipcommon: mapping local conn id %d to voipserver conn id %d\n", iLocalConnId, iVoipServerConnId));
|
|
pVoipCommon->Connectionlist.pConnections[iLocalConnId].iVoipServerConnId = iVoipServerConnId;
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: warning - mapping local conn id to voipserver conn id ignored because connection state is ST_DISC\n"));
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSetLocalClientId
|
|
|
|
\Description
|
|
Set local client id for connection
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnId - connection id
|
|
\Input uLocalClientId - local client id
|
|
|
|
\Version 01/30/2019 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonSetLocalClientId(VoipCommonRefT *pVoipCommon, int32_t iConnId, uint32_t uLocalClientId)
|
|
{
|
|
if (pVoipCommon->Connectionlist.pConnections[iConnId].bIsLocalClientIdValid)
|
|
{
|
|
NetPrintf(("voipcommon: warning - local client id 0x%08x is being replaced with 0x%08x for conn id %d\n",
|
|
pVoipCommon->Connectionlist.pConnections[iConnId].uLocalClientId, uLocalClientId, iConnId));
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("voipcommon: assigning local client id 0x%08x to conn id %d\n", uLocalClientId, iConnId));
|
|
}
|
|
pVoipCommon->Connectionlist.pConnections[iConnId].uLocalClientId = uLocalClientId;
|
|
pVoipCommon->Connectionlist.pConnections[iConnId].bIsLocalClientIdValid = TRUE;
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSetDisplayTranscribedTextCallback
|
|
|
|
\Description
|
|
Set callback to be invoked when transcribed text (from local user or remote user)
|
|
is ready to be displayed locally.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input *pCallback - notification handler
|
|
\Input *pUserData - user data for handler
|
|
|
|
\Version 05/03/2017 (mclouatre)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
void VoipCommonSetDisplayTranscribedTextCallback(VoipCommonRefT *pVoipCommon, VoipDisplayTranscribedTextCallbackT *pCallback, void *pUserData)
|
|
{
|
|
// acquire critical section
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
if (pCallback == NULL)
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb = NULL;
|
|
pVoipCommon->pDisplayTranscribedTextUserData = NULL;
|
|
}
|
|
else
|
|
{
|
|
pVoipCommon->pDisplayTranscribedTextCb = pCallback;
|
|
pVoipCommon->pDisplayTranscribedTextUserData = pUserData;
|
|
}
|
|
|
|
// release critical section
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function VoipCommonSetEventCallback
|
|
|
|
\Description
|
|
Set voip event notification handler.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input *pCallback - event notification handler
|
|
\Input *pUserData - user data for handler
|
|
|
|
\Version 02/10/2006 (jbrookes)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
void VoipCommonSetEventCallback(VoipCommonRefT *pVoipCommon, VoipCallbackT *pCallback, void *pUserData)
|
|
{
|
|
// acquire critical section
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
if (pCallback == NULL)
|
|
{
|
|
pVoipCommon->pCallback = _VoipCommonCallback;
|
|
pVoipCommon->pUserData = NULL;
|
|
}
|
|
else
|
|
{
|
|
pVoipCommon->pCallback = pCallback;
|
|
pVoipCommon->pUserData = pUserData;
|
|
}
|
|
|
|
// release critical section
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonConnect
|
|
|
|
\Description
|
|
Connect to a peer.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnID - [zero, iMaxPeers-1] for an explicit slot or VOIP_CONNID_NONE to auto-allocate
|
|
\Input uAddress - remote peer address
|
|
\Input uManglePort - port from demangler
|
|
\Input uGamePort - port to connect on
|
|
\Input uClientId - remote clientId to connect to (cannot be 0)
|
|
\Input uSessionId - session identifier (optional)
|
|
|
|
\Output
|
|
int32_t - connection identifier (negative=error)
|
|
|
|
\Version 1.0 03/02/2004 (jbrookes) first version
|
|
\Version 1.1 10/26/2009 (mclouatre) uClientId is no longer optional
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonConnect(VoipCommonRefT *pVoipCommon, int32_t iConnID, uint32_t uAddress, uint32_t uManglePort, uint32_t uGamePort, uint32_t uClientId, uint32_t uSessionId)
|
|
{
|
|
// acquire critical section to modify ConnectionList
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
// initiate connection
|
|
iConnID = VoipConnectionStart(&pVoipCommon->Connectionlist, iConnID, uAddress, uManglePort, uGamePort, uClientId, uSessionId);
|
|
|
|
// release critical section
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
|
|
// return connection ID to caller
|
|
return(iConnID);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonDisconnect
|
|
|
|
\Description
|
|
Disconnect from peer.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnID - which connection to disconnect (VOIP_CONNID_ALL for all)
|
|
\Input bSendDiscMsg - TRUE if a voip disc pkt needs to be sent, FALSE otherwise
|
|
|
|
\Todo
|
|
Multiple connection support.
|
|
|
|
\Version 15/01/2014 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void VoipCommonDisconnect(VoipCommonRefT *pVoipCommon, int32_t iConnID, int32_t bSendDiscMsg)
|
|
{
|
|
// acquire critical section to modify ConnectionList
|
|
NetCritEnter(&pVoipCommon->ThreadCrit);
|
|
|
|
// shut down connection
|
|
VoipConnectionStop(&pVoipCommon->Connectionlist, iConnID, bSendDiscMsg);
|
|
|
|
// release critical section
|
|
NetCritLeave(&pVoipCommon->ThreadCrit);
|
|
}
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonRemoteUserStatus
|
|
|
|
\Description
|
|
Return information about remote peer.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnID - which connection to get remote info for, or VOIP_CONNID_ALL
|
|
\Input iRemoteUserIndex - user index at the connection iConnID
|
|
|
|
\Output
|
|
int32_t - VOIP_REMOTE* flags, or VOIP_FLAG_INVALID if iConnID is invalid
|
|
|
|
\Version 05/06/2014 (amakoukji)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonRemoteUserStatus(VoipCommonRefT *pVoipCommon, int32_t iConnID, int32_t iRemoteUserIndex)
|
|
{
|
|
int32_t iRemoteStatus = VOIP_FLAG_INVALID;
|
|
|
|
if (pVoipCommon != NULL && pVoipCommon->Connectionlist.pConnections != NULL)
|
|
{
|
|
if (iConnID == VOIP_CONNID_ALL)
|
|
{
|
|
for (iConnID = 0, iRemoteStatus = 0; iConnID < pVoipCommon->Connectionlist.iMaxConnections; iConnID++)
|
|
{
|
|
iRemoteStatus |= (int32_t)pVoipCommon->Connectionlist.pConnections[iConnID].uRemoteUserStatus[iRemoteUserIndex];
|
|
}
|
|
}
|
|
else if ((iConnID >= 0) && (iConnID < pVoipCommon->Connectionlist.iMaxConnections))
|
|
{
|
|
iRemoteStatus = pVoipCommon->Connectionlist.pConnections[iConnID].uRemoteUserStatus[iRemoteUserIndex];
|
|
}
|
|
}
|
|
|
|
return(iRemoteStatus);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function VoipCommonConnStatus
|
|
|
|
\Description
|
|
Return information about peer connection.
|
|
|
|
\Input *pVoipCommon - voip common state
|
|
\Input iConnID - which connection to get remote info for, or VOIP_CONNID_ALL
|
|
|
|
\Output
|
|
int32_t - VOIP_CONN* flags, or VOIP_FLAG_INVALID if iConnID is invalid
|
|
|
|
\Version 05/06/2014 (amakoukji)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t VoipCommonConnStatus(VoipCommonRefT *pVoipCommon, int32_t iConnID)
|
|
{
|
|
int32_t iRemoteStatus = VOIP_FLAG_INVALID;
|
|
|
|
if (pVoipCommon != NULL && pVoipCommon->Connectionlist.pConnections != NULL)
|
|
{
|
|
if (iConnID == VOIP_CONNID_ALL)
|
|
{
|
|
for (iConnID = 0, iRemoteStatus = 0; iConnID < pVoipCommon->Connectionlist.iMaxConnections; iConnID++)
|
|
{
|
|
iRemoteStatus |= (int32_t)pVoipCommon->Connectionlist.pConnections[iConnID].uRemoteConnStatus;
|
|
}
|
|
}
|
|
else if ((iConnID >= 0) && (iConnID < pVoipCommon->Connectionlist.iMaxConnections))
|
|
{
|
|
iRemoteStatus = pVoipCommon->Connectionlist.pConnections[iConnID].uRemoteConnStatus;
|
|
}
|
|
}
|
|
|
|
return(iRemoteStatus);
|
|
}
|