first commit

This commit is contained in:
murdle
2026-03-01 02:38:58 +02:00
commit 19250b9db4
19111 changed files with 4358159 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
#pragma once
#include <np.h>
#ifdef __PS3__
#include <netex\libnetctl.h>
#include <netex\net.h>
#else
#include <libnetctl.h>
#include <net.h>
#endif
#include <queue>
#include "..\..\Common\Network\Sony\SQRNetworkManager.h"
class SQRNetworkPlayer;
class ISQRNetworkManagerListener;
class SonyVoiceChat;
class C4JThread;
// This is the lowest level manager for providing network functionality on Sony platforms. This manages various network activities including the players within a gaming session.
// The game shouldn't directly use this class, it is here to provide functionality required by PlatformNetworkManagerSony.
class SQRNetworkManager_PS3 : public SQRNetworkManager
{
friend class SonyVoiceChat;
friend class SQRNetworkPlayer;
static const eSQRNetworkManagerState m_INTtoEXTStateMappings[SNM_INT_STATE_COUNT];
public:
SQRNetworkManager_PS3(ISQRNetworkManagerListener *listener);
// General
void Tick();
void Initialise();
void Terminate();
eSQRNetworkManagerState GetState();
bool IsHost();
bool IsReadyToPlayOrIdle();
bool IsInSession();
// Session management
void CreateAndJoinRoom(int hostIndex, int localPlayerMask, void *extData, int extDataSize, bool offline);
void UpdateExternalRoomData();
bool FriendRoomManagerIsBusy();
bool FriendRoomManagerSearch();
bool FriendRoomManagerSearch2();
int FriendRoomManagerGetCount();
void FriendRoomManagerGetRoomInfo(int idx, SessionSearchResult *searchResult);
bool JoinRoom(SessionSearchResult *searchResult, int localPlayerMask);
bool JoinRoom(SceNpMatching2RoomId roomId, SceNpMatching2ServerId serverId, int localPlayerMask, const SQRNetworkManager_PS3::PresenceSyncInfo *presence);
void StartGame();
void LeaveRoom(bool bActuallyLeaveRoom);
void EndGame();
bool SessionHasSpace(int spaceRequired);
bool AddLocalPlayerByUserIndex(int idx);
bool RemoveLocalPlayerByUserIndex(int idx);
void SendInviteGUI();
void GetInviteDataAndProcess(SceNpBasicAttachmentDataId id);
static bool UpdateInviteData(SQRNetworkManager_PS3::PresenceSyncInfo *invite);
void GetExtDataForRoom( SceNpMatching2RoomId roomId, void *extData, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam );
// Player retrieval
int GetPlayerCount();
int GetOnlinePlayerCount();
SQRNetworkPlayer *GetPlayerByIndex(int idx);
SQRNetworkPlayer *GetPlayerBySmallId(int idx);
SQRNetworkPlayer *GetPlayerByXuid(PlayerUID xuid);
SQRNetworkPlayer *GetLocalPlayerByUserIndex(int idx);
SQRNetworkPlayer *GetHostPlayer();
// Communication parameter storage
static const SceNpCommunicationId* GetSceNpCommsId();
static const SceNpCommunicationSignature* GetSceNpCommsSig();
private:
void InitialiseAfterOnline();
void ErrorHandlingTick();
void UpdateOnlineStatus(int status) { m_onlineStatus = status; }
int GetOnlineStatus() { return m_onlineStatus; }
ISQRNetworkManagerListener *m_listener;
SQRNetworkPlayer *GetPlayerIfReady(SQRNetworkPlayer *player);
// Internal state
void SetState(eSQRNetworkManagerInternalState state);
void ResetToIdle();
eSQRNetworkManagerInternalState m_state;
eSQRNetworkManagerState m_stateExternal;
bool m_nextIdleReasonIsFull;
bool m_isHosting;
SceNpMatching2RoomMemberId m_localMemberId;
int m_localPlayerCount;
int m_localPlayerJoined; // Client only, keep a count of how many local players we have confirmed as joined to the application
SceNpMatching2RoomId m_room;
unsigned char m_currentSmallId;
int m_soc;
bool m_offlineGame;
bool m_offlineSQR;
int m_resendExternalRoomDataCountdown;
bool m_matching2initialised;
PresenceSyncInfo m_inviteReceived[MAX_SIMULTANEOUS_INVITES];
int m_inviteIndex;
PresenceSyncInfo *m_gameBootInvite;
bool m_doBootInviteCheck;
bool m_isInSession;
static SceNpBasicAttachmentDataId s_lastInviteIdToRetry;
int m_onlineStatus;
bool m_bLinkDisconnected;
private:
CRITICAL_SECTION m_csRoomSyncData;
RoomSyncData m_roomSyncData;
void *m_joinExtData;
int m_joinExtDataSize;
std::vector<SQRNetworkPlayer *> m_vecTempPlayers;
SQRNetworkPlayer *m_aRoomSlotPlayers[MAX_ONLINE_PLAYER_COUNT]; // Maps from the players in m_roomSyncData, to SQRNetworkPlayers
void FindOrCreateNonNetworkPlayer(int slot, int playerType, SceNpMatching2RoomMemberId memberId, int localPlayerIdx, int smallId);
void MapRoomSlotPlayers(int roomSlotPlayerCount =-1);
void UpdateRoomSyncUIDsFromPlayers();
void UpdatePlayersFromRoomSyncUIDs();
void LocalDataSend(SQRNetworkPlayer *playerFrom, SQRNetworkPlayer *playerTo, const void *data, unsigned int dataSize);
int GetSessionIndex(SQRNetworkPlayer *player);
bool AddRemotePlayersAndSync( SceNpMatching2RoomMemberId memberId, int playerMask, bool *isFull = NULL );
void RemoveRemotePlayersAndSync( SceNpMatching2RoomMemberId memberId, int mask );
void RemoveNetworkPlayers( int mask );
void SetLocalPlayersAndSync();
void SyncRoomData();
SceNpMatching2RequestId m_setRoomDataRequestId;
SceNpMatching2RequestId m_setRoomIntDataRequestId;
SceNpMatching2RequestId m_roomExtDataRequestId;
// Server context management
bool GetMatchingContext(eSQRNetworkManagerInternalState asyncState);
bool GetServerContext();
bool GetServerContext2();
bool GetServerContext(SceNpMatching2ServerId serverId);
void DeleteServerContext();
bool SelectRandomServer();
void ServerContextTick();
int m_totalServerCount;
int m_serverCount;
SceNpMatching2ServerId *m_aServerId;
SceNpMatching2ServerId m_serverId;
bool m_serverContextValid;
SceNpMatching2RequestId m_serverSearchRequestId;
SceNpMatching2RequestId m_serverContextRequestId;
// Room creation management
SceNpMatching2RequestId m_getWorldRequestId;
SceNpMatching2RequestId m_createRoomRequestId;
SceNpMatching2WorldId m_worldId;
void RoomCreateTick();
// Room joining management
SceNpMatching2RoomId m_roomToJoin;
int m_localPlayerJoinMask;
SceNpMatching2RequestId m_joinRoomRequestId;
SceNpMatching2RequestId m_kickRequestId;
// Room leaving management
SceNpMatching2RequestId m_leaveRoomRequestId;
// Adding extra network players management
SceNpMatching2RequestId m_setRoomMemberInternalDataRequestId;
// Player state management
void NetworkPlayerConnectionComplete(SQRNetworkPlayer *player);
void NetworkPlayerSmallIdAllocated(SQRNetworkPlayer *player, unsigned char smallId);
void NetworkPlayerInitialDataReceived(SQRNetworkPlayer *player,void *data);
void NonNetworkPlayerComplete(SQRNetworkPlayer *player, unsigned char smallId);
void HandlePlayerJoined(SQRNetworkPlayer *player);
CRITICAL_SECTION m_csPlayerState;
// State and thread for managing basic event type messages
C4JThread *m_basicEventThread;
sys_event_port_t m_basicEventPort;
sys_event_queue_t m_basicEventQueue;
static int BasicEventThreadProc( void *lpParameter);
// State and storage for managing search for friends' games
eSQRNetworkManagerFriendSearchState m_friendSearchState;
SceNpMatching2ContextId m_matchingContext;
bool m_matchingContextValid;
SceNpMatching2RequestId m_friendSearchRequestId;
unsigned int m_friendCount;
C4JThread *m_getFriendCountThread;
static int GetFriendsThreadProc( void* lpParameter );
void FriendSearchTick();
SceNpMatching2RequestId m_roomDataExternalListRequestId;
void (* m_FriendSessionUpdatedFn)(bool success, void *pParam);
void *m_pParamFriendSessionUpdated;
void *m_pExtDataToUpdate;
// Results from searching for rooms that friends are playing in - 5 matched arrays to store their NpIds, rooms, servers, whether a room was found, and whether the external data had been received for the room. Also a count of how many elements are used in this array.
SceNpId m_aSearchResultNpId[MAX_FRIENDS];
SceNpMatching2RoomId m_aSearchResultRoomId[MAX_FRIENDS];
SceNpMatching2ServerId m_aSearchResultServerId[MAX_FRIENDS];
bool m_aSearchResultRoomFound[MAX_FRIENDS];
void *m_aSearchResultRoomExtDataReceived[MAX_FRIENDS];
unsigned int m_searchResultCount;
// Rudp management and local players
unordered_map<int,SQRNetworkPlayer *> m_RudpCtxToPlayerMap;
bool CreateRudpConnections(SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId peerMemberId, int playerMask, SceNpMatching2RoomMemberId playersPeerMemberId);
SQRNetworkPlayer *GetPlayerFromRudpCtx(int rudpCtx);
SQRNetworkPlayer *GetPlayerFromRoomMemberAndLocalIdx(int roomMember, int localIdx);
SceNpMatching2RequestId m_roomMemberDataRequestId;
// Callbacks (for matching)
bool RegisterCallbacks();
static void ContextCallback(SceNpMatching2ContextId id, SceNpMatching2Event event, SceNpMatching2EventCause eventCause, int errorCode, void *arg);
#ifdef __PS3__
static void DefaultRequestCallback(SceNpMatching2ContextId id, SceNpMatching2RequestId reqId, SceNpMatching2Event event, SceNpMatching2EventKey eventKey, int errorCode, size_t dataSize, void *arg);
static void RoomEventCallback(SceNpMatching2ContextId id, SceNpMatching2RoomId roomId, SceNpMatching2Event event, SceNpMatching2EventKey eventKey, int errorCode, size_t dataSize, void *arg);
#else
static void DefaultRequestCallback(SceNpMatching2ContextId id, SceNpMatching2RequestId reqId, SceNpMatching2Event event, int errorCode, const void *data, void *arg);
static void RoomEventCallback(SceNpMatching2ContextId id, SceNpMatching2RoomId roomId, SceNpMatching2Event event, int errorCode, const void *data, void *arg);
#endif
static void SignallingCallback(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId peerMemberId, SceNpMatching2Event event, int errorCode, void *arg);
// Callback for NpBasic
static int BasicEventCallback(int event, int retCode, uint32_t reqId, void *arg);
// Callback for NpManager
static void ManagerCallback(int event, int result, void *arg);
// Callback for sys util
static void SysUtilCallback(uint64_t status, uint64_t param, void *userdata);
// Callbacks for rudp
static void RudpContextCallback(int ctx_id, int event_id, int error_code, void *arg);
#ifdef __PS3__
static int RudpEventCallback(int event_id, int soc, uint8_t const *data, size_t datalen, struct sockaddr const *addr, socklen_t addrlen, void *arg);
#else
static int RudpEventCallback(int event_id, int soc, uint8_t const *data, size_t datalen, struct SceNetSockaddr const *addr, SceNetSocklen_t addrlen, void *arg);
#endif
// Callback for netctl
static void NetCtlCallback(int prev_state, int new_state, int event, int error_code, void *arg);
// Methods to be called when the server context has been created
void ServerContextValid_CreateRoom();
void ServerContextValid_JoinRoom();
// Mask utilities
int GetOldMask(SceNpMatching2RoomMemberId memberId);
int GetAddedMask(int newMask, int oldMask);
int GetRemovedMask(int newMask, int oldMask);
#ifdef __PS3__
// Response storage
char cUserInfoListStorage[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetUserInfoList] __attribute__((__aligned__(4)));
char cServerInfoStorage[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetServerInfo] __attribute__((__aligned__(4)));
char cWorldListStorage[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetWorldInfoList] __attribute__((__aligned__(4)));
char cCreateJoinRoomStorage[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_CreateJoinRoom] __attribute__((__aligned__(4)));
char cJoinRoomStorage[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_JoinRoom] __attribute__((__aligned__(4)));
char cRoomMemberDataInternal[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetRoomMemberDataInternal] __attribute__((__aligned__(4)));
char cRoomDataInternal[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomDataInternalUpdateInfo] __attribute__((__aligned__(4)));
char cRoomDataExternalList[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetRoomDataExternalList] __attribute__((__aligned__(4)));
char cRoomMemberDataInternalUpdate[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberDataInternalUpdateInfo] __attribute__((__aligned__(4)));
char cRoomDataUpdateInfo[SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomUpdateInfo] __attribute__((__aligned__(4)));
#endif
#ifndef _CONTENT_PACKAGE
static bool aForceError[SNM_FORCE_ERROR_COUNT];
#endif
bool ForceErrorPoint(eSQRForceError err);
public:
static void AttemptPSNSignIn(int (*SignInCompleteCallbackFn)(void *pParam, bool bContinue, int pad), void *pParam, bool callIfFailed = false);
static int (*s_SignInCompleteCallbackFn)(void *pParam, bool bContinue, int pad);
static bool s_signInCompleteCallbackIfFailed;
static void *s_SignInCompleteParam;
static int SetRichPresence(const void *data, unsigned int options);
void SetPresenceDataStartHostingGame();
int GetJoiningReadyPercentage();
private:
static void UpdateRichPresenceCustomData(void *data, unsigned int dataBytes);
static void TickRichPresence();
static void SendLastPresenceInfo();
static SceNpBasicPresenceDetails2 s_lastPresenceInfo;
static int s_resendPresenceCountdown;
static bool s_presenceStatusDirty;
static bool s_presenceDataDirty;
static PresenceSyncInfo s_lastPresenceSyncInfo;
static PresenceSyncInfo c_presenceSyncInfoNULL;
// 4J-PB - so we can stop the crash on PS3 when Iggy's LoadMovie is called from the ContextCallback
static bool m_bCallPSNSignInCallback;
// Debug
static long long s_roomStartTime;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <np.h>
#include <np/drm.h>
#include <np/commerce2.h>
#include "Common\Network\Sony\SonyCommerce.h"
#define SCE_TOOLKIT_NP_SKU_PRICE_LEN (SCE_NP_COMMERCE2_CURRENCY_CODE_LEN \
+ SCE_NP_COMMERCE2_CURRENCY_SYMBOL_LEN \
+ SCE_NP_COMMERCE2_THOUSAND_SEPARATOR_LEN \
+ SCE_NP_COMMERCE2_DECIMAL_LETTER_LEN) ///< The maximum length of a price in characters.
class SonyCommerce_PS3 : public SonyCommerce
{
enum State
{
e_state_noSession,
e_state_creatingSession,
e_state_createSessionDone,
e_state_idle,
};
/// This enum is used to verify the current utility that is running
enum Phase
{
e_phase_stopped = 0,
e_phase_idle,
e_phase_voucherRedeemPhase,
e_phase_productBrowsePhase,
e_phase_creatingSessionPhase,
e_phase_checkoutPhase,
e_phase_downloadListPhase
};
enum Message
{
e_message_commerceNone,
e_message_commerceCreateSession, ///< Create a commerce session
e_message_commerceGetCategoryInfo, ///< Information about a category in the Store
e_message_commerceGetProductList, ///< Get a list of products available in the Store
e_message_commerceGetDetailedProductInfo, ///< Get a list of products available in the Store, with additional details
e_message_commerceAddDetailedProductInfo, ///< Add additional details to a ProdcutInfo already retrieved
e_message_commerceStoreProductBrowse, ///< Launches the Store to a specified product
e_message_commerceUpgradeTrial, ///< Upgrade a trial to full game
e_message_commerceRedeemVoucher, ///< Redeem a voucher code
e_message_commerceGetEntitlementList, ///< Get a list of entitlements associated with the current PSN user.
e_message_commerceConsumeEntitlement, ///< Consume an amount from a consumable entitlement.
e_message_commerceCheckout, ///< Launch the Store checkout
e_message_commerceDownloadList, ///< Launch the download list
e_message_commerceEnd ///< End commerce2 processing
};
enum Event
{
e_event_none,
e_event_commerceSessionCreated, ///< An event generated when a commerce session has successfully been created.
e_event_commerceSessionAborted, ///< An event generated when the creation of commerce session has been aborted.
e_event_commerceGotCategoryInfo, ///< An event generated when some category information has been retrieved from the store.
e_event_commerceGotProductList, ///< An event generated when a list of products that are available has been retrieved from the store.
e_event_commerceGotDetailedProductInfo, ///< An event generated when some detailed product information has been retrieved from the store.
e_event_commerceAddedDetailedProductInfo, ///< An event generated when some detailed product information has been retrieved from the store.
e_event_commerceProductBrowseStarted, ///< An event generated when product overlay has started.
e_event_commerceProductBrowseSuccess, ///< An event generated when a product browse was completed successfully, and the user purchased the product.
e_event_commerceProductBrowseAborted, ///< An event generated when a product browse was aborted by the user (the user pressed back).
e_event_commerceProductBrowseFinished, ///< An event generated when a product browse has finished and it is now safe to free memory.
e_event_commerceVoucherInputStarted, ///< An event generated when a voucher code input overlay was started.
e_event_commerceVoucherInputSuccess, ///< An event generated when a voucher code input completed successfully.
e_event_commerceVoucherInputAborted, ///< An event generated when a voucher code input was aborted by the user (user pressed back).
e_event_commerceVoucherInputFinished, ///< An event generated when a voucher code input has finished. It is now safe to free memory.
e_event_commerceGotEntitlementList, ///< An event generated when a the list of entitlements has been received for the current user.
e_event_commerceConsumedEntitlement, ///< An event generated when the has successfully consumed an entitlement.
e_event_commerceCheckoutStarted, ///< An event generated when a store checkout overlay has started.
e_event_commerceCheckoutSuccess, ///< An event generated when user has successfully purchased from the checkout.
e_event_commerceCheckoutAborted, ///< An event generated when the checkout was aborted by the user (user pressed back).
e_event_commerceCheckoutFinished, ///< An event generated when a store checkout overlay has finished.
e_event_commerceDownloadListStarted, ///< An event generated when a download list overlay has started.
e_event_commerceDownloadListSuccess, ///< An event generated when the user has ended the download list.
e_event_commerceDownloadListFinished, ///< An event generated when a download list overlay has finished.
e_event_commerceError ///< An event generated when a commerce error has occurred.
};
static bool m_bLicenseChecked;
static bool m_bCommerceInitialised;
static SceNpCommerce2SessionInfo m_sessionInfo;
static State m_state;
static int m_errorCode;
static LPVOID m_callbackParam;
static Event m_event;
static Message m_message;
// static uint32_t m_requestID;
static void* m_receiveBuffer;
static std::vector<ProductInfo> *m_pProductInfoList;
static ProductInfoDetailed *m_pProductInfoDetailed;
static ProductInfo *m_pProductInfo;
static CategoryInfo* m_pCategoryInfo;
static char* m_pCategoryID;
static const char* m_pProductID;
static std::queue<Message> m_messageQueue;
static CallbackFunc m_callbackFunc;
static CheckoutInputParams m_checkoutInputParams;
static DownloadListInputParams m_downloadInputParams;
static sys_memory_container_t m_memContainer;
static bool m_bUpgradingTrial;
static C4JThread* m_tickThread;
static CallbackFunc m_trialUpgradeCallbackFunc;
static LPVOID m_trialUpgradeCallbackParam;
static CRITICAL_SECTION m_queueLock;
static void runCallback()
{
assert(m_callbackFunc);
CallbackFunc func = m_callbackFunc;
m_callbackFunc = NULL;
if(func)
func(m_callbackParam, m_errorCode);
m_errorCode = CELL_OK;
}
static void setCallback(CallbackFunc cb,LPVOID lpParam)
{
assert(m_callbackFunc == NULL);
m_callbackFunc = cb;
m_callbackParam = lpParam;
}
static uint32_t m_contextId; ///< The npcommerce2 context ID
static bool m_contextCreated; ///< npcommerce2 context ID created?
static Phase m_currentPhase; ///< Current commerce2 util
static char m_commercebuffer[SCE_NP_COMMERCE2_RECV_BUF_SIZE];
static void commerce2Handler(uint32_t contextId, uint32_t subjectId, int event, int errorCode, void *arg);
static void processMessage();
static void processEvent();
static int createContext();
static int createSession();
static void setError(int err) { m_errorCode = err; }
static int getCategoryInfo(CategoryInfo *info, char *categoryId);
static int getProductList(std::vector<ProductInfo>* productList, char *categoryId);
static int getDetailedProductInfo(ProductInfoDetailed *info, const char *productId, char *categoryId);
static int addDetailedProductInfo(ProductInfo *info, const char *productId, char *categoryId);
static int checkout(CheckoutInputParams &params);
static int downloadList(DownloadListInputParams &params);
static void UpgradeTrialCallback1(LPVOID lpParam,int err);
static void UpgradeTrialCallback2(LPVOID lpParam,int err);
static void Delete();
static int commerceEnd();
// static int upgradeTrial();
static int TickLoop(void* lpParam);
static void Init();
static int Shutdown();
static void CheckForTrialUpgradeKey_Callback(LPVOID param, bool bFullVersion);
public:
virtual void CreateSession(CallbackFunc cb, LPVOID lpParam);
virtual void CloseSession();
virtual void GetCategoryInfo(CallbackFunc cb, LPVOID lpParam, CategoryInfo *info, const char *categoryId);
virtual void GetProductList(CallbackFunc cb, LPVOID lpParam, std::vector<ProductInfo>* productList, const char *categoryId);
virtual void GetDetailedProductInfo(CallbackFunc cb, LPVOID lpParam, ProductInfoDetailed* productInfoDetailed, const char *productId, const char *categoryId);
virtual void AddDetailedProductInfo( CallbackFunc cb, LPVOID lpParam, ProductInfo* productInfo, const char *productId, const char *categoryId );
virtual void Checkout(CallbackFunc cb, LPVOID lpParam, const char* skuID);
virtual void DownloadAlreadyPurchased(CallbackFunc cb, LPVOID lpParam, const char* skuID);
virtual void UpgradeTrial(CallbackFunc cb, LPVOID lpParam);
virtual void CheckForTrialUpgradeKey();
virtual bool LicenseChecked();
};

View File

@@ -0,0 +1,289 @@
#include "stdafx.h"
#include "SonyHttp_PS3.h"
// static const int sc_HTTPPoolSize = (32 * 1024);
// static const int sc_SSLPoolSize = (256 * 1024U);
// static const int sc_CookiePoolSize = (256 * 1024U);
static const int sc_HTTPPoolSize = (32 * 1024);
static const int sc_SSLPoolSize = (512 * 1024U);
static const int sc_CookiePoolSize = (256 * 1024U);
void* SonyHttp_PS3::uriPool = NULL;
void* SonyHttp_PS3::httpPool = NULL;
void* SonyHttp_PS3::sslPool = NULL;
void* SonyHttp_PS3::cookiePool = NULL;
CellHttpClientId SonyHttp_PS3::client;
CellHttpTransId SonyHttp_PS3::trans;
bool SonyHttp_PS3:: bInitialised = false;
bool SonyHttp_PS3::loadCerts(size_t *numBufPtr, CellHttpsData **caListPtr)
{
CellHttpsData *caList = NULL;
size_t size = 0;
int ret = 0;
char *buf = NULL;
caList = (CellHttpsData *)malloc(sizeof(CellHttpsData)*2);
if (NULL == caList) {
app.DebugPrintf("failed to malloc cert data");
return false;
}
ret = cellSslCertificateLoader(CELL_SSL_LOAD_CERT_ALL, NULL, 0, &size);
if (ret < 0) {
app.DebugPrintf("cellSslCertifacateLoader() failed(1): 0x%08x", ret);
return ret;
}
buf = (char*)malloc(size);
if (NULL == buf) {
app.DebugPrintf("failed to malloc cert buffer");
free(caList);
return false;
}
ret = cellSslCertificateLoader(CELL_SSL_LOAD_CERT_ALL, buf, size, NULL);
if (ret < 0) {
app.DebugPrintf("cellSslCertifacateLoader() failed(2): 0x%08x", ret);
free(buf);
free(caList);
return false;
}
(&caList[0])->ptr = buf;
(&caList[0])->size = size;
*caListPtr = caList;
*numBufPtr = 1;
return true;
}
bool SonyHttp_PS3::init()
{
int ret;
client = 0;
trans = 0;
/*E startup procedures */
httpPool = malloc(sc_HTTPPoolSize);
if (httpPool == NULL) {
app.DebugPrintf("failed to malloc libhttp memory pool\n");
return false;
}
ret = cellHttpInit(httpPool, sc_HTTPPoolSize);
if (0 > ret)
{
app.DebugPrintf("unable to start libhttp... (0x%x)\n", ret);
return false;
}
cookiePool = malloc(sc_CookiePoolSize);
if (cookiePool == NULL) {
app.DebugPrintf("failed to malloc ssl memory pool\n");
return false;
}
ret = cellHttpInitCookie(cookiePool, sc_CookiePoolSize);
if (ret < 0 && ret != CELL_HTTP_ERROR_ALREADY_INITIALIZED)
{
app.DebugPrintf("cellHttpInitCookie failed... (0x%x)\n", ret);
return false;
}
sslPool = malloc(sc_SSLPoolSize);
if (sslPool == NULL) {
app.DebugPrintf("failed to malloc ssl memory pool\n");
return false;
}
ret = cellSslInit(sslPool, sc_SSLPoolSize);
if (0 > ret)
{
app.DebugPrintf("unable to start cellSslInit... (0x%x)\n", ret);
return false;
}
size_t numBuf = 0;
CellHttpsData *caList = NULL;
if(!loadCerts(&numBuf, &caList))
return false;
ret = cellHttpsInit(numBuf, caList);
free(caList->ptr);
free(caList);
if (ret < 0 && ret != CELL_HTTP_ERROR_ALREADY_INITIALIZED)
{
app.DebugPrintf("unable to start https: 0x%08x", ret);
return false;
}
ret = cellHttpCreateClient(&client);
if (0 > ret)
{
app.DebugPrintf("unable to create http client... (0x%x)\n", ret);
return false;
}
bInitialised = true;
return true;
}
void SonyHttp_PS3::shutdown()
{
if (trans)
{
cellHttpDestroyTransaction(trans);
trans = 0;
}
if (client)
{
cellHttpDestroyClient(client);
client = 0;
}
cellHttpEnd();
free(httpPool);
}
bool SonyHttp_PS3::parseUri(const char* szUri, CellHttpUri& parsedUri)
{
/*E the main part */
size_t poolSize = 0;
int ret = cellHttpUtilParseUri(NULL, szUri, NULL, 0, &poolSize);
if (0 > ret)
{
app.DebugPrintf("error parsing URI... (0x%x)\n\n", ret);
return false;
}
if (NULL == (uriPool = malloc(poolSize)))
{
app.DebugPrintf("error mallocing uriPool (%d)\n", poolSize);
return false;
}
ret = cellHttpUtilParseUri(&parsedUri, szUri, uriPool, poolSize, NULL);
if (0 > ret)
{
free(uriPool);
app.DebugPrintf("error parsing URI... (0x%x)\n\n", ret);
return false;
}
return true;
}
void* SonyHttp_PS3::getData(const char* url, int* pDataSize)
{
CellHttpUri uri;
int ret;
bool has_cl = true;
uint64_t length = 0;
uint64_t recvd;
const char *serverName;
size_t localRecv = 0;
if(!parseUri(url, uri))
return NULL;
app.DebugPrintf(" scheme: %s\n", uri.scheme);
app.DebugPrintf(" hostname: %s\n", uri.hostname);
app.DebugPrintf(" port: %d\n", uri.port);
app.DebugPrintf(" path: %s\n", uri.path);
app.DebugPrintf(" username: %s\n", uri.username);
app.DebugPrintf(" password: %s\n", uri.password);
ret = cellHttpCreateTransaction(&trans, client, CELL_HTTP_METHOD_GET, &uri);
free(uriPool);
if (0 > ret)
{
app.DebugPrintf("failed to create http transaction... (0x%x)\n\n", ret);
return NULL;
}
ret = cellHttpSendRequest(trans, NULL, 0, NULL);
if (0 > ret)
{
app.DebugPrintf("failed to complete http transaction... (0x%x)\n\n", ret);
/*E continue down to check status code, just in case */
cellHttpDestroyTransaction(trans);
trans = 0;
}
{
int code = 0;
ret = cellHttpResponseGetStatusCode(trans, &code);
if (0 > ret)
{
app.DebugPrintf("failed to receive http response... (0x%x)\n\n", ret);
cellHttpDestroyTransaction(trans);
trans = 0;
return NULL;
}
app.DebugPrintf("Status Code is %d\n", code);
}
ret = cellHttpResponseGetContentLength(trans, &length);
if (0 > ret)
{
if (ret == CELL_HTTP_ERROR_NO_CONTENT_LENGTH)
{
app.DebugPrintf("Only supporting data that has a content length : CELL_HTTP_ERROR_NO_CONTENT_LENGTH\n", ret);
cellHttpDestroyTransaction(trans);
trans = 0;
return NULL;
}
else
{
app.DebugPrintf("error in receiving content length... (0x%x)\n\n", ret);
cellHttpDestroyTransaction(trans);
trans = 0;
return NULL;
}
}
int bufferSize = length;
char* buffer = (char*)malloc(bufferSize+1);
recvd = 0;
// 4J-PB - seems to be some limit to a read with cellHttpRecvResponse, even though it claims it's read all the data, it hasn't
// reducing this to read 10k at a time.
int iMaxRead=10240;
app.DebugPrintf("\n===BEGINNING OF TRANSMISSION===\n");
while(recvd<length)
{
ret = cellHttpRecvResponse(trans, &buffer[recvd], iMaxRead, &localRecv);
if (0 > ret)
{
app.DebugPrintf("error receiving body... (0x%x)\n\n", ret);
free(buffer);
cellHttpDestroyTransaction(trans);
trans = 0;
return NULL;
}
else
{
if(localRecv==0) break;
}
recvd += localRecv;
}
buffer[bufferSize] = '\0';
ret = 0;
app.DebugPrintf("\n===END OF TRANSMISSION===\n\n");
*pDataSize = bufferSize;
cellHttpDestroyTransaction(trans);
trans = 0;
return buffer;
}
bool SonyHttp_PS3::getDataFromURL( const char* szURL, void** ppOutData, int* pDataSize)
{
if(!bInitialised)
return false;
*ppOutData = getData(szURL, pDataSize);
if(*ppOutData)
return true;
return false;
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <cell/http.h>
class SonyHttp_PS3
{
static bool loadCerts(size_t *numBufPtr, CellHttpsData **caListPtr);
static void* getData(const char* url, int* pDataSize);
static bool parseUri(const char* szUri, CellHttpUri& parsedUri);
static void *uriPool;
static void *httpPool;
static void* sslPool;
static void* cookiePool;
static CellHttpClientId client;
static CellHttpTransId trans;
static bool bInitialised;
public:
bool init();
void shutdown();
bool getDataFromURL(const char* szURL, void** ppOutData, int* pDataSize);
};

View File

@@ -0,0 +1,518 @@
#include "stdafx.h"
#include "SonyRemoteStorage_PS3.h"
#include <stdio.h>
#include <string>
#include <stdlib.h>
// #include <cell/sysmodule.h>
// #include <cell/http.h>
// #include <cell/ssl.h>
// #include <netex/net.h>
// #include <netex/libnetctl.h>
// #include <np.h>
// #include <sysutil/sysutil_common.h>
// #include <sys/timer.h>
// #include <sys/paths.h>
// #include <sysutil\sysutil_savedata.h>
// 4J-PB - ticketing changed to our SCEE product id
#define TICKETING_SERVICE_ID "EP4433-NPEB01899_00" //"EP9009-NPWA00114_00"
#define CLIENT_ID "969e9d21-527c-4c22-b539-f8e479f690bc"
void SonyRemoteStorage_PS3::npauthhandler(int event, int result, void *arg)
{
#ifdef __PS3__
if (event != SCE_NP_MANAGER_EVENT_GOT_TICKET || result <= 0)
{
app.DebugPrintf("Could not retrieve ticket: 0x%x\n", result);
}
else
{
psnTicketSize = result;
psnTicket = malloc(psnTicketSize);
if (psnTicket == NULL)
{
app.DebugPrintf("Failed to allocate for ticket\n");
}
int ret = sceNpManagerGetTicket(psnTicket, &psnTicketSize);
if (ret < 0)
{
app.DebugPrintf("Could not retrieve ticket: 0x%x\n", ret);
free(psnTicket);
psnTicket = 0;
return;
}
}
m_waitingForTicket = false;
#endif
}
int SonyRemoteStorage_PS3::initPreconditions()
{
int ret = 0;
SceNpId npId;
ret = sceNpManagerGetNpId(&npId);
if(ret < 0)
{
return ret;
}
SceNpTicketVersion ticketVersion;
ticketVersion.major = 3;
ticketVersion.minor = 0;
ret = sceNpManagerRequestTicket2(&npId, &ticketVersion, TICKETING_SERVICE_ID, NULL, 0, NULL, 0);
if(ret < 0)
{
return ret;
}
m_waitingForTicket = true;
while(m_waitingForTicket)
{
cellSysutilCheckCallback();
sys_timer_usleep(50000); //50 milliseconds.
}
if(psnTicket == NULL)
return -1;
return 0;
}
void SonyRemoteStorage_PS3::staticInternalCallback(const SceRemoteStorageEvent event, int32_t retCode, void * userData)
{
((SonyRemoteStorage_PS3*)userData)->internalCallback(event, retCode);
}
void SonyRemoteStorage_PS3::internalCallback(const SceRemoteStorageEvent event, int32_t retCode)
{
m_lastErrorCode = retCode;
switch(event)
{
case ERROR_OCCURRED:
app.DebugPrintf("An error occurred with retCode: 0x%x \n", retCode);
// shutdown(); // removed, as the remote storage lib now tries to reconnect if an error has occurred
m_status = e_error;
runCallback();
m_bTransferStarted = false;
break;
case GET_DATA_RESULT:
if(retCode >= 0)
{
app.DebugPrintf("Get Data success \n");
m_status = e_getDataSucceeded;
}
else
{
app.DebugPrintf("An error occurred while Get Data was being processed. retCode: 0x%x \n", retCode);
m_status = e_error;
}
runCallback();
m_bTransferStarted = false;
break;
case GET_DATA_PROGRESS:
app.DebugPrintf("Get data progress: %i%%\n", retCode);
m_status = e_getDataInProgress;
m_dataProgress = retCode;
m_startTime = System::currentTimeMillis();
break;
case GET_STATUS_RESULT:
if(retCode >= 0)
{
app.DebugPrintf("Get Status success \n");
app.DebugPrintf("Remaining Syncs for this user: %llu\n", outputGetStatus->remainingSyncs);
app.DebugPrintf("Number of files on the cloud: %d\n", outputGetStatus->numFiles);
for(int i = 0; i < outputGetStatus->numFiles; i++)
{
app.DebugPrintf("\n*** File %d information: ***\n", (i + 1));
app.DebugPrintf("File name: %s \n", outputGetStatus->data[i].fileName);
app.DebugPrintf("File description: %s \n", outputGetStatus->data[i].fileDescription);
app.DebugPrintf("MD5 Checksum: %s \n", outputGetStatus->data[i].md5Checksum);
app.DebugPrintf("Size of the file: %u bytes \n", outputGetStatus->data[i].fileSize);
app.DebugPrintf("Timestamp: %s \n", outputGetStatus->data[i].timeStamp);
app.DebugPrintf("Visibility: \"%s\" \n", (outputGetStatus->data[i].visibility == 0)?"Private":((outputGetStatus->data[i].visibility == 1)?"Public read only":"Public read and write"));
}
m_status = e_getStatusSucceeded;
}
else
{
app.DebugPrintf("An error occurred while Get Status was being processed. retCode: 0x%x \n", retCode);
m_status = e_error;
}
runCallback();
break;
case PSN_SIGN_IN_REQUIRED:
app.DebugPrintf("User's PSN sign-in through web browser is required \n");
m_status = e_signInRequired;
runCallback();
break;
case SET_DATA_RESULT:
if(retCode >= 0)
{
app.DebugPrintf("Set Data success \n");
m_status = e_setDataSucceeded;
}
else
{
app.DebugPrintf("An error occurred while Set Data was being processed. retCode: 0x%x \n", retCode);
m_status = e_error;
}
runCallback();
m_bTransferStarted = false;
break;
case SET_DATA_PROGRESS:
app.DebugPrintf("Set data progress: %i%%\n", retCode);
m_status = e_setDataInProgress;
m_dataProgress = retCode;
break;
case USER_ACCOUNT_LINKED:
app.DebugPrintf("User's account has been linked with PSN \n");
m_bInitialised = true;
m_status = e_accountLinked;
runCallback();
break;
case WEB_BROWSER_RESULT:
app.DebugPrintf("This function is not used on PS Vita, as the account will be linked, it is not needed to open a browser to link it \n");
assert(0);
break;
default:
app.DebugPrintf("This should never happen \n");
assert(0);
break;
}
}
bool SonyRemoteStorage_PS3::init(CallbackFunc cb, LPVOID lpParam)
{
m_callbackFunc = cb;
m_callbackParam = lpParam;
m_bTransferStarted = false;
m_bAborting = false;
if(m_bInitialised)
{
runCallback();
return true;
}
if(m_bInitialised)
{
internalCallback(USER_ACCOUNT_LINKED, 0);
return true;
}
int ret = initPreconditions();
if(ret < 0)
{
return false;
}
SceRemoteStorageInitParams params;
params.callback = staticInternalCallback;
params.userData = this;
params.thread.threadAffinity = 0; //Not used in PS3
params.thread.threadPriority = 1000; //Must be between [0-3071], being 0 the highest.
params.psnTicket = psnTicket;
params.psnTicketSize = psnTicketSize;
strcpy(params.clientId, CLIENT_ID);
params.timeout.connectMs = 30 * 1000; //30 seconds is the default
params.timeout.resolveMs = 30 * 1000; //30 seconds is the default
params.timeout.receiveMs = 120 * 1000; //120 seconds is the default
params.timeout.sendMs = 120 * 1000; //120 seconds is the default
params.pool.memPoolSize = 7 * 1024 * 1024;
if(m_memPoolBuffer == NULL)
m_memPoolBuffer = malloc(params.pool.memPoolSize);
params.pool.memPoolBuffer = m_memPoolBuffer;
// SceRemoteStorageAbortReqParams abortParams;
ret = sceRemoteStorageInit(params);
if(ret >= 0 || ret == SCE_REMOTE_STORAGE_ERROR_ALREADY_INITIALISED)
{
// abortParams.requestId = ret;
//ret = sceRemoteStorageAbort(abortParams);
app.DebugPrintf("Session will be created \n");
//if(ret >= 0)
//{
// printf("Session aborted \n");
//} else
//{
// printf("Error aborting session: 0x%x \n", ret);
//}
}
else
{
app.DebugPrintf("Error creating session: 0x%x \n", ret);
return false;
}
return true;
}
bool SonyRemoteStorage_PS3::getRemoteFileInfo(SceRemoteStorageStatus* pInfo, CallbackFunc cb, LPVOID lpParam)
{
m_callbackFunc = cb;
m_callbackParam = lpParam;
outputGetStatus = pInfo;
SceRemoteStorageStatusReqParams params;
reqId = sceRemoteStorageGetStatus(params, outputGetStatus);
m_status = e_getStatusInProgress;
if(reqId >= 0)
{
app.DebugPrintf("Get Status request sent \n");
return true;
}
else
{
app.DebugPrintf("Error sending Get Status request: 0x%x \n", reqId);
return false;
}
}
void SonyRemoteStorage_PS3::abort()
{
m_bAborting = true;
app.DebugPrintf("Aborting...\n");
if(m_bTransferStarted)
{
app.DebugPrintf("transfer has started so we'll call sceRemoteStorageAbort...\n");
SceRemoteStorageAbortReqParams params;
params.requestId = reqId;
int ret = sceRemoteStorageAbort(params);
if(ret >= 0)
{
app.DebugPrintf("Abort request done \n");
}
else
{
app.DebugPrintf("Error in Abort request: 0x%x \n", ret);
}
}
}
bool SonyRemoteStorage_PS3::setDataInternal()
{
CompressSaveData(); // check if we need to re-save the file compressed first
strcpy(m_saveFilename, m_setDataSaveInfo->UTF8SaveFilename);
strcpy(m_saveFileDesc, m_setDataSaveInfo->UTF8SaveTitle);
SceRemoteStorageSetDataReqParams params;
params.visibility = PUBLIC_READ_WRITE;
strcpy(params.pathLocation, m_saveFilename);
sprintf(params.fileName, getRemoteSaveFilename());
DescriptionData descData;
ZeroMemory(&descData, sizeof(DescriptionData));
descData.m_platform[0] = SAVE_FILE_PLATFORM_LOCAL & 0xff;
descData.m_platform[1] = (SAVE_FILE_PLATFORM_LOCAL >> 8) & 0xff;
descData.m_platform[2] = (SAVE_FILE_PLATFORM_LOCAL >> 16) & 0xff;
descData.m_platform[3] = (SAVE_FILE_PLATFORM_LOCAL >> 24)& 0xff;
if(m_thumbnailData)
{
unsigned int uiHostOptions;
bool bHostOptionsRead;
DWORD uiTexturePack;
char seed[22];
app.GetImageTextData(m_thumbnailData, m_thumbnailDataSize,(unsigned char *)seed, uiHostOptions, bHostOptionsRead, uiTexturePack);
__int64 iSeed = strtoll(seed,NULL,10);
char seedHex[17];
sprintf(seedHex,"%016llx",iSeed);
memcpy(descData.m_seed,seedHex,16); // Don't copy null
// Save the host options that this world was last played with
char hostOptions[9];
sprintf(hostOptions,"%08x",uiHostOptions);
memcpy(descData.m_hostOptions,hostOptions,8); // Don't copy null
// Save the texture pack id
char texturePack[9];
sprintf(texturePack,"%08x",uiTexturePack);
memcpy(descData.m_texturePack,texturePack,8); // Don't copy null
}
memcpy(descData.m_saveNameUTF8, m_saveFileDesc, strlen(m_saveFileDesc)+1); // plus null
memcpy(params.fileDescription, &descData, sizeof(descData));
strcpy(params.ps3DataFilename, "GAMEDATA");
params.ps3FileType = CELL_SAVEDATA_FILETYPE_NORMALFILE;
memcpy(params.secureFileId, m_secureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE);
if(m_bAborting)
{
runCallback();
return false;
}
reqId = sceRemoteStorageSetData(params);
app.DebugPrintf("\n*******************************\n");
if(reqId >= 0)
{
app.DebugPrintf("Set Data request sent \n");
m_bTransferStarted = true;
m_status = e_setDataInProgress;
return true;
}
else
{
app.DebugPrintf("Error sending Set Data request: 0x%x \n", reqId);
return false;
}
}
bool SonyRemoteStorage_PS3::getData( const char* remotePath, const char* localPath, CallbackFunc cb, LPVOID lpParam )
{
m_callbackFunc = cb;
m_callbackParam = lpParam;
SceRemoteStorageGetDataReqParams params;
strcpy(params.pathLocation, localPath);//"ABCD12345-RS-DATA");
strcpy(params.fileName, remotePath);//"/test/small.txt");
strcpy(params.ps3DataFilename, "GAMEDATA");
params.ps3FileType = CELL_SAVEDATA_FILETYPE_NORMALFILE;
memcpy(params.secureFileId, m_secureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE);
reqId = sceRemoteStorageGetData(params, &outputGetData);
app.DebugPrintf("\n*******************************\n");
if(reqId >= 0)
{
app.DebugPrintf("Get Data request sent \n");
m_bTransferStarted = true;
m_status = e_getDataInProgress;
} else
{
app.DebugPrintf("Error sending Get Data request: 0x%x \n", reqId);
}
}
void SonyRemoteStorage_PS3::runCallback()
{
assert(m_callbackFunc);
if(m_callbackFunc)
{
m_callbackFunc(m_callbackParam, m_status, m_lastErrorCode);
}
m_lastErrorCode = ERROR_SUCCESS;
}
int SonyRemoteStorage_PS3::SaveCompressCallback(LPVOID lpParam,bool bRes)
{
SonyRemoteStorage_PS3* pRS = (SonyRemoteStorage_PS3*)lpParam;
pRS->m_compressedSaveState = e_state_Idle;
return 0;
}
int SonyRemoteStorage_PS3::LoadCompressCallback(void *pParam,bool bIsCorrupt, bool bIsOwner)
{
SonyRemoteStorage_PS3* pRS = (SonyRemoteStorage_PS3*)pParam;
int origFilesize = StorageManager.GetSaveSize();
void* pOrigSaveData = malloc(origFilesize);
unsigned int retFilesize;
StorageManager.GetSaveData( pOrigSaveData, &retFilesize );
// check if this save file is already compressed
if(*((int*)pOrigSaveData) != 0)
{
app.DebugPrintf("compressing save data\n");
// Assume that the compression will make it smaller so initially attempt to allocate the current file size
// We add 4 bytes to the start so that we can signal compressed data
// And another 4 bytes to store the decompressed data size
unsigned int compLength = origFilesize+8;
byte *compData = (byte *)malloc( compLength );
Compression::UseDefaultThreadStorage();
Compression::getCompression()->Compress(compData+8,&compLength,pOrigSaveData,origFilesize);
ZeroMemory(compData,8);
int saveVer = 0;
memcpy( compData, &saveVer, sizeof(int) );
memcpy( compData+4, &origFilesize, sizeof(int) );
StorageManager.FreeSaveData();
StorageManager.SetSaveData(compData,compLength+8);
pRS->m_compressedSaveState = e_state_CompressedSave;
}
else
{
// already compressed, do nothing
pRS->m_compressedSaveState = e_state_Idle;
}
return 0;
}
void SonyRemoteStorage_PS3::CompressSaveData()
{
app.DebugPrintf("CompressSaveData\n");
m_compressedSaveState = e_state_LoadingSave;
app.DebugPrintf("Loading save\n");
waitForStorageManagerIdle();
C4JStorage::ESaveGameState eLoadStatus=StorageManager.LoadSaveData(m_setDataSaveInfo, &LoadCompressCallback, this);
if(eLoadStatus != C4JStorage::ESaveGame_Load)
{
app.DebugPrintf("Failed to load savegame for compression!!!!!!\n");
m_compressedSaveState = e_state_Idle;
return;
}
while(m_compressedSaveState == e_state_LoadingSave)
{
Sleep(10);
}
if(m_compressedSaveState == e_state_CompressedSave)
{
waitForStorageManagerIdle();
app.DebugPrintf("Saving compressed save\n");
waitForStorageManagerIdle();
StorageManager.SetDefaultSaveImage(); // we can't get the save image back to overwrite, so set it to the default
C4JStorage::ESaveGameState storageState = StorageManager.SaveSaveData( &SaveCompressCallback, this, true ); // only save the data file, so we don't overwrite the icon
if(storageState == C4JStorage::ESaveGame_Save)
{
m_compressedSaveState = e_state_SavingSave;
while(m_compressedSaveState == e_state_SavingSave)
{
Sleep(10);
}
}
else
{
app.DebugPrintf("StorageManager.SaveSaveData failed, save is left uncompressed\n");
}
}
waitForStorageManagerIdle();
app.DebugPrintf("done\n");
assert(m_compressedSaveState == e_state_Idle);
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include "Common\Network\Sony\sceRemoteStorage\header\sceRemoteStorage.h"
class SonyRemoteStorage_PS3 : public SonyRemoteStorage
{
public:
virtual bool init(CallbackFunc cb, LPVOID lpParam);
virtual bool getRemoteFileInfo(SceRemoteStorageStatus* pInfo, CallbackFunc cb, LPVOID lpParam);
virtual bool getData(const char* remotePath, const char* localPath, CallbackFunc cb, LPVOID lpParam);
virtual void abort();
virtual bool setDataInternal();
bool isWaitingForTicket() { return m_waitingForTicket; }
void npauthhandler(int event, int result, void *arg);
void SetSecureID(char* id) { memcpy(m_secureFileId, id, CELL_SAVEDATA_SECUREFILEID_SIZE); }
void CompressSaveData();
bool dataCompressDone() { return (m_compressedSaveState == e_state_Idle);}
private:
int reqId;
void * psnTicket;
size_t psnTicketSize;
bool m_waitingForTicket;
bool initialized;
SceRemoteStorageStatus* outputGetStatus;
SceRemoteStorageData outputGetData;
enum CompressSaveState
{
e_state_LoadingSave,
e_state_CompressedSave,
e_state_SavingSave,
e_state_Idle
};
CompressSaveState m_compressedSaveState;
char m_secureFileId[CELL_SAVEDATA_SECUREFILEID_SIZE];
int32_t m_lastErrorCode;
int m_getDataProgress;
int m_setDataProgress;
char m_saveFilename[SCE_REMOTE_STORAGE_DATA_NAME_MAX_LEN];
char m_saveFileDesc[SCE_REMOTE_STORAGE_DATA_DESCRIPTION_MAX_LEN];
char m_remoteFilename[SCE_REMOTE_STORAGE_DATA_NAME_MAX_LEN];
int initPreconditions();
static void staticInternalCallback(const SceRemoteStorageEvent event, int32_t retCode, void * userData);
void internalCallback(const SceRemoteStorageEvent event, int32_t retCode);
virtual void runCallback();
static int SaveCompressCallback(LPVOID lpParam,bool bRes);
static int LoadCompressCallback(void *pParam,bool bIsCorrupt, bool bIsOwner);
};

View File

@@ -0,0 +1,764 @@
#include "stdafx.h"
/* SCE CONFIDENTIAL
PlayStation(R)3 Programmer Tool Runtime Library 430.001
* Copyright (C) 2008 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
#include "SonyVoiceChat.h"
#include <arpa/inet.h> /* inet_ntoa() */
/* for displaying extra information */
#ifndef _CONTENT_PACKAGE
#define AVC2_GAME_DEBUG
#endif
#ifdef AVC2_GAME_DEBUG
#define INF(...) printf( "INF:" __VA_ARGS__ )
#define ERR(...) printf( "ERR:" __VA_ARGS__ )
#else
#define INF(...)
#define ERR(...)
#endif
#define UNUSED_VARIABLE(x) (void)(x)
//#define DISABLE_VOICE_CHAT
static CellSysutilAvc2InitParam g_chat_avc2param;
EAVCEvent SonyVoiceChat::sm_event = AVC_EVENT_EPSILON;
EAVCState SonyVoiceChat::sm_state = AVC_STATE_IDLE;
SQRNetworkManager_PS3* SonyVoiceChat::sm_pNetworkManager;
bool SonyVoiceChat::sm_bEnabled = true;
uint8_t SonyVoiceChat::sm_micStatus = CELL_AVC2_MIC_STATUS_UNKNOWN;
bool SonyVoiceChat::sm_bLoaded = false;
bool SonyVoiceChat::sm_bUnloading = false;
unordered_map<SceNpMatching2RoomMemberId, bool> SonyVoiceChat::sm_bTalkingMap;
bool SonyVoiceChat::sm_bCanStart = false;
bool SonyVoiceChat::sm_isChatRestricted = false;
int SonyVoiceChat::sm_currentBitrate = 28000;
void SonyVoiceChat::init( SQRNetworkManager_PS3* pNetMan )
{
if(sm_state != AVC_STATE_IDLE)
return;
sm_pNetworkManager = pNetMan;
setState(AVC_STATE_CHAT_INIT);
ProfileManager.GetChatAndContentRestrictions(0,false,&sm_isChatRestricted,NULL,NULL);
}
void SonyVoiceChat::shutdown()
{
if( sm_state == AVC_STATE_IDLE ||
sm_state == AVC_STATE_CHAT_LEAVE ||
sm_state == AVC_STATE_CHAT_UNLOAD ||
sm_state == AVC_STATE_CHAT_RESET )
{
// we're either shut down already, or in the process
return;
}
setEvent(AVC_EVENT_EXIT_GAME);
}
void SonyVoiceChat::setEnabled( bool bEnabled )
{
if(sm_bEnabled != bEnabled)
{
if(sm_bCanStart)
{
if(bEnabled)
startStream();
else
stopStream();
}
sm_bEnabled = bEnabled;
}
}
int SonyVoiceChat::eventcb_load(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_LOAD_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_LOAD_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_LOAD_SUCCEEDED);
sm_bLoaded = true;
// set the packet contention value here
CellSysutilAvc2Attribute attr;
memset( &attr, 0x00, sizeof(attr) );
attr.attr_id = CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_PACKET_CONTENTION;
attr.attr_param.int_param = 3;
int ret = cellSysutilAvc2SetAttribute(&attr);
if( ret != CELL_OK )
{
app.DebugPrintf("CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_PACKET_CONTENTION failed !!! 0x%08x\n", ret);
}
}
else /* if( event_id == CELL_AVC2_EVENT_LOAD_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_LOAD_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_LOAD_FAILED);
}
return ret;
}
int SonyVoiceChat::eventcb_join(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_JOIN_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_JOIN_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_JOIN_SUCCEEDED);
}
else /* if( event_id == CELL_AVC2_EVENT_JOIN_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_JOIN_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_ERROR);
}
sm_bTalkingMap.clear();
return ret;
}
int SonyVoiceChat::eventcb_leave( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_LEAVE_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_LEAVE_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setState(AVC_STATE_CHAT_LEAVE);
setEvent(AVC_EVENT_CHAT_LEAVE_SUCCEEDED);
}
else /* if( event_id == CELL_AVC2_EVENT_LEAVE_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_LEAVE_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setState(AVC_STATE_CHAT_LEAVE);
setEvent(AVC_EVENT_ERROR);
}
return ret;
}
int SonyVoiceChat::eventcb_unload(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_UNLOAD_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_UNLOAD_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_UNLOAD_SUCCEEDED);
sm_bLoaded = false;
sm_bUnloading = false;
}
else /* if( event_id == CELL_AVC2_EVENT_UNLOAD_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_UNLOAD_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_ERROR);
}
return ret;
}
int SonyVoiceChat::eventcb_voiceDetected(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
UNUSED_VARIABLE( userdata );
// To the upper 32 bits, the room member ID of the player is passed.
// In the lower 32 bits, a value of 0 (mute) or a value between 1 (low volume)
// and 10 (high volume) is passed as the audio signal value when the notification
// method is the level method, or a value of 1 (start of speaking) or 0 (end of speaking)
// is stored when the notification method is the trigger method.
SceNpMatching2RoomMemberId roomMemberID = (SceNpMatching2RoomMemberId)(event_param >> 32);
uint32_t volume = (uint32_t)(event_param & 0xffffffff);
// The precision of voice detection is not very high. Since the audio signal values may
// always be relatively high depending on the audio input device and the noise level in the
// room, you should set a large reference value for determining whether or not a player is
// speaking. Relatively good results can be obtained when an audio signal value of at
// least 9 is used to determine if a player is speaking.
bool bTalking = false;
if(volume >= 9)
bTalking = true;
sm_bTalkingMap[roomMemberID] = bTalking;
return CELL_OK;
}
/* Callback function for handling AV Chat2 Utility events */
void SonyVoiceChat::eventcb( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
static struct _cb_func_tbl
{
CellSysutilAvc2EventId event;
int (*func)( CellSysutilAvc2EventId event_id,
CellSysutilAvc2EventParam event_param,
void *userdata );
} event_tbl[] =
{
{ CELL_AVC2_EVENT_LOAD_SUCCEEDED, eventcb_load },
{ CELL_AVC2_EVENT_LOAD_FAILED, eventcb_load },
{ CELL_AVC2_EVENT_JOIN_SUCCEEDED, eventcb_join },
{ CELL_AVC2_EVENT_JOIN_FAILED, eventcb_join },
{ CELL_AVC2_EVENT_LEAVE_SUCCEEDED, eventcb_leave },
{ CELL_AVC2_EVENT_LEAVE_FAILED, eventcb_leave },
{ CELL_AVC2_EVENT_UNLOAD_SUCCEEDED, eventcb_unload },
{ CELL_AVC2_EVENT_UNLOAD_FAILED, eventcb_unload },
{ CELL_AVC2_EVENT_SYSTEM_NEW_MEMBER_JOINED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_MEMBER_LEFT, NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_ESTABLISHED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_CANNOT_ESTABLISHED,NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_DISCONNECTED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_VOICE_DETECTED, eventcb_voiceDetected },
};
int ret = 0;
for( unsigned int i=0; i<sizeof(event_tbl)/sizeof(struct _cb_func_tbl) ; ++i )
{
if( event_tbl[ i ].event == event_id && event_tbl[ i ].func )
{
ret = (*event_tbl[ i ].func)( event_id, event_param, userdata );
if( ret < 0 )
{
ERR("ret=0x%x\n", ret );
}
break;
}
}
}
int SonyVoiceChat::load()
{
int ret = CELL_OK;
INF("----------------------------\n");
INF("| cellSysutilAvc2LoadAsync |\n");
INF("----------------------------\n");
ret = cellSysutilAvc2LoadAsync( sm_pNetworkManager->m_matchingContext,
SYS_MEMORY_CONTAINER_ID_INVALID,
eventcb,
NULL,
&g_chat_avc2param );
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2LoadAsync: ret=0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::join()
{
int ret = CELL_OK;
INF("---------------------------------------------------\n");
INF("| cellSysutilAvc2JoinChatRequest \n");
INF("---------------------------------------------------\n");
ret = cellSysutilAvc2JoinChatRequest( &sm_pNetworkManager->m_room );
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2JoinChatRequest: ret=0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::leave()
{
int ret = CELL_OK;
INF("-----------------------------------\n");
INF("| cellSysutilAvc2LeaveChatRequest |\n");
INF("-----------------------------------\n");
ret = cellSysutilAvc2LeaveChatRequest();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2LeaveChatRequest() = 0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::unload()
{
int ret = CELL_OK;
INF("------------------------------\n");
INF("| cellSysutilAvc2UnloadAsync |\n");
INF("------------------------------\n");
ret = cellSysutilAvc2UnloadAsync();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvcUnloadAsync() = 0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
sm_bUnloading = true;
return ret;
}
int SonyVoiceChat::start()
{
sm_bCanStart = (sm_isChatRestricted == false);
int ret = CELL_OK;
if(sm_bEnabled)
ret = startStream();
return ret;
}
int SonyVoiceChat::stop()
{
sm_bCanStart = false;
int ret = CELL_OK;
if(sm_bEnabled)
ret = stopStream();
setEvent(AVC_EVENT_CHAT_SESSION_STOPPED);
return ret;
}
int SonyVoiceChat::startStream()
{
int ret = CELL_OK;
INF("---------------------------------\n");
INF("| cellSysutilAvc2StartStreaming |\n");
INF("---------------------------------\n");
ret = cellSysutilAvc2StartStreaming();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StartStreaming: ret=0x%x\n", ret );
}
ret = cellSysutilAvc2StartVoiceDetection();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StartVoiceDetection: ret=0x%x\n", ret );
}
return ret;
}
int SonyVoiceChat::stopStream()
{
int ret = cellSysutilAvc2StopVoiceDetection();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StopVoiceDetection: ret=0x%x\n", ret );
}
INF("--------------------------------\n");
INF("| cellSysutilAvc2StopStreaming |\n");
INF("--------------------------------\n");
ret = cellSysutilAvc2StopStreaming();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StopStreaming: ret=0x%x\n", ret );
}
return ret;
}
int SonyVoiceChat::initialize(void)
{
int ret;
/* Must use cellSysutilAvc2InitParam() for clearing CellSysutilAvc2InitParam struct*/
ret = cellSysutilAvc2InitParam(CELL_SYSUTIL_AVC2_INIT_PARAM_VERSION, &g_chat_avc2param);
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2InitParam failed (0x%x)\n", ret );
return ret;
}
/* Setting application specific parameters */
g_chat_avc2param.media_type = CELL_SYSUTIL_AVC2_VOICE_CHAT;
g_chat_avc2param.max_players = AVC2_PARAM_DEFAULT_MAX_PLAYERS;
g_chat_avc2param.voice_param.voice_quality = CELL_SYSUTIL_AVC2_VOICE_QUALITY_NORMAL;
g_chat_avc2param.voice_param.max_speakers = AVC2_PARAM_DEFAULT_MAX_SPEAKERS;
g_chat_avc2param.spu_load_average = 50;
g_chat_avc2param.streaming_mode.mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL;
setEvent(AVC_EVENT_CHAT_INIT_SUCCEEDED);
setState(AVC_STATE_CHAT_INIT);
return ret;
}
int SonyVoiceChat::finalize(void)
{
setEvent(AVC_EVENT_CHAT_FINALIZE_SUCCEEDED);
return CELL_OK;
}
void SonyVoiceChat::tick()
{
#ifdef DISABLE_VOICE_CHAT
return;
#endif
static state_transition_table tbl[] =
{
/* now state event func after the transition state */
{ AVC_STATE_CHAT_INIT, AVC_EVENT_EPSILON, initialize, AVC_STATE_CHAT_INIT },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_CHAT_INIT_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_LOAD },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_EPSILON, load, AVC_STATE_CHAT_LOAD },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_CHAT_LOAD_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_JOIN },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_EPSILON, join, AVC_STATE_CHAT_JOIN },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_CHAT_JOIN_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_EPSILON, start, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_EXIT_GAME, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_ERROR, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_LAN_DISCONNECT, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_CHAT_SESSION_STOPPED, invoke_epsilon_event, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_EPSILON, leave, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_CHAT_LEAVE_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_EPSILON, unload, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_CHAT_UNLOAD_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_EPSILON, finalize, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_CHAT_FINALIZE_SUCCEEDED, invoke_epsilon_event, AVC_STATE_IDLE },
};
do_state_transition( &tbl[0], sizeof( tbl ) / sizeof( state_transition_table ) );
setBitRate();
}
void SonyVoiceChat::do_state_transition( state_transition_table *tbl, int tbl_size )
{
int ret = CELL_OK;
// if( sm_event == AVC_EVENT_LAN_DISCONNECT ||
// sm_event == AVC_EVENT_EXIT_GAME ||
// sm_event == AVC_EVENT_ERROR ||
// sm_event == AVC_EVENT_FATAL_ERROR )
// {
// g_gamedata.finalize = 1;
// }
// if( sm_event == AVC_EVENT_FATAL_ERROR )
// {
// g_gamedata.exit = true;
// }
bool bCalledFunc = false;
for( int i = 0; i < tbl_size; i++ )
{
if( sm_state == ( tbl + i )->state )
{
if( sm_event == ( tbl + i )->event )
{
sm_event = AVC_EVENT_NON;
ret = (*( tbl + i )->func)();
bCalledFunc = true;
if( ret != CELL_OK )
{
ERR("ret = 0x%x\n", ret );
}
setState(( tbl + i )->new_state);
break;
}
}
}
if(bCalledFunc == false)
{
assert( (sm_event == AVC_EVENT_NON) ||
(sm_state == AVC_STATE_IDLE && sm_event == AVC_EVENT_EPSILON) );
}
}
int SonyVoiceChat::invoke_epsilon_event(void)
{
setEvent(AVC_EVENT_EPSILON);
return CELL_OK;
}
bool SonyVoiceChat::hasMicConnected(const SceNpMatching2RoomMemberId *players_id)
{
CellSysutilAvc2PlayerInfo players_info;
int err = cellSysutilAvc2GetPlayerInfo(players_id, &players_info);
if(err == CELL_OK)
{
if(players_info.connected && players_info.joined)
{
if(players_info.mic_attached == CELL_AVC2_MIC_STATUS_ATTACHED_ON)
return true;
}
}
return false;
}
void SonyVoiceChat::mute( bool bMute )
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetVoiceMuting(bMute);
assert(err == CELL_OK);
}
}
void SonyVoiceChat::mutePlayer( const SceNpMatching2RoomMemberId member_id, bool bMute ) /*Turn chat audio from a specified player on or off */
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetPlayerVoiceMuting(member_id, bMute);
assert(err == CELL_OK);
}
}
void SonyVoiceChat::muteLocalPlayer( bool bMute ) /*Turn microphone input on or off */
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetVoiceMuting(bMute);
assert(err == CELL_OK);
}
}
bool SonyVoiceChat::isMuted()
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetVoiceMuting(&bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
bool SonyVoiceChat::isMutedPlayer( const SceNpMatching2RoomMemberId member_id)
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetPlayerVoiceMuting(member_id, &bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
bool SonyVoiceChat::isMutedLocalPlayer()
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetVoiceMuting(&bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
void SonyVoiceChat::setVolume( float vol )
{
if(sm_bLoaded && !sm_bUnloading)
{
// The volume level can be set to a value in the range 0.0 to 40.0.
// Volume levels are linear values such that if 1.0 is specified, the
// volume level will be 1 times the reference power (0dB), and if 0.5
// is specified, the volume level will be 0.5 times the reference power
// (-6dB). If 0.0 is specified, chat audio will no longer be audible.
int err =cellSysutilAvc2SetSpeakerVolumeLevel(vol * 40.0f);
assert(err==CELL_OK);
}
}
float SonyVoiceChat::getVolume()
{
if(sm_bLoaded && !sm_bUnloading)
{
float vol;
int err = cellSysutilAvc2GetSpeakerVolumeLevel(&vol);
assert(err == CELL_OK);
return (vol / 40.0f);
}
return 0;
}
bool SonyVoiceChat::isTalking( SceNpMatching2RoomMemberId* players_id )
{
AUTO_VAR(it, sm_bTalkingMap.find(*players_id));
if (it != sm_bTalkingMap.end() )
return it->second;
return false;
}
void SonyVoiceChat::setBitRate()
{
if(sm_state != AVC_STATE_CHAT_SESSION_PROCESSING)
return;
int numPlayers = sm_pNetworkManager->GetPlayerCount();
// This internal attribute represents the maximum voice bit rate. attr_param
// is an integer value. The units are bps, and the specifiable values are
// 4000, 8000, 16000, 20000, 24000, and 28000. The initial value is 28000.
static int bitRates[8] = { 28000, 28000,
28000, 28000,
24000, 20000,
16000, 16000};
int bitRate = bitRates[numPlayers-1];
if(bitRate == sm_currentBitrate)
return;
CellSysutilAvc2Attribute attr;
memset( &attr, 0x00, sizeof(attr) );
attr.attr_id = CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_MAX_BITRATE;
attr.attr_param.int_param = bitRate;
int ret = cellSysutilAvc2SetAttribute(&attr);
if( ret == CELL_OK )
{
sm_currentBitrate = bitRate;
}
else
{
app.DebugPrintf("SonyVoiceChat::setBitRate failed !!! 0x%08x\n", ret);
}
}
#define CASE_STR_VALUE(s) case s: return #s;
const char* getStateString(EAVCState state)
{
switch(state)
{
CASE_STR_VALUE(AVC_STATE_IDLE);
CASE_STR_VALUE(AVC_STATE_CHAT_INIT)
CASE_STR_VALUE(AVC_STATE_CHAT_LOAD);
CASE_STR_VALUE(AVC_STATE_CHAT_JOIN);
CASE_STR_VALUE(AVC_STATE_CHAT_SESSION_PROCESSING);
CASE_STR_VALUE(AVC_STATE_CHAT_LEAVE);
CASE_STR_VALUE(AVC_STATE_CHAT_RESET);
CASE_STR_VALUE(AVC_STATE_CHAT_UNLOAD);
CASE_STR_VALUE(AVC_STATE_EXIT);
default:
return "unknown state";
}
}
const char* getEventString(EAVCEvent state)
{
switch(state)
{
CASE_STR_VALUE(AVC_EVENT_NON);
CASE_STR_VALUE(AVC_EVENT_EPSILON);
CASE_STR_VALUE(AVC_EVENT_LAN_DISCONNECT);
CASE_STR_VALUE(AVC_EVENT_ONLINE);
CASE_STR_VALUE(AVC_EVENT_OFFLINE);
CASE_STR_VALUE(AVC_EVENT_EXIT_GAME);
CASE_STR_VALUE(AVC_EVENT_ROOM_CREATE);
CASE_STR_VALUE(AVC_EVENT_ROOM_SEARCH);
CASE_STR_VALUE(AVC_EVENT_ERROR);
CASE_STR_VALUE(AVC_EVENT_FATAL_ERROR);
CASE_STR_VALUE(AVC_EVENT_NETDIALOG_FINISHED);
CASE_STR_VALUE(AVC_EVENT_NETDIALOG_UNLOADED);
CASE_STR_VALUE(AVC_EVENT_NP2_INIT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_FINALIZE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_START_CONTEXT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_STOP_CONTEXT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_MEMBER_LEFT);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_MEMBER_JOINED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LOAD_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LOAD_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_JOIN_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_JOIN_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LEAVE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LEAVE_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_UNLOAD_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_UNLOAD_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_INIT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_FINALIZE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_SESSION_STOPPED);
CASE_STR_VALUE(AVC_EVENT_CREATE_JOIN_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_SEARCH_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_JOIN_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_LEAVE_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_SIGNALING_ESTABLISHED);
CASE_STR_VALUE(AVC_EVENT_SIGNALING_DEAD);
CASE_STR_VALUE(AVC_EVENT_UI_CLOSE_SUCCEEDED);
default:
return "unknown event";
}
}
void SonyVoiceChat::printStateAndEvent()
{
app.DebugPrintf("============== State %20s, Event %20s\n", getStateString(sm_state), getEventString(sm_event));
}
void SonyVoiceChat::setEvent( EAVCEvent event )
{
sm_event = event;
printStateAndEvent();
}
void SonyVoiceChat::setState( EAVCState state )
{
sm_state = state;
printStateAndEvent();
}

View File

@@ -0,0 +1,157 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cell/sysmodule.h>
#include <sys/process.h>
#include <sysutil/sysutil_avc2.h> /* for using AV Chat2 Utility */
#include <np.h> /* for using NP Matching */
#include <netex/net.h>
#include <netex/libnetctl.h>
#include <sysutil/sysutil_sysparam.h>
#define AVC2_PARAM_DEFAULT_MAX_PLAYERS (8)
#define AVC2_PARAM_DEFAULT_MAX_SPEAKERS (4)
/* state list */
enum EAVCState
{
AVC_STATE_IDLE = 0,
AVC_STATE_CHAT_INIT,
AVC_STATE_CHAT_LOAD,
AVC_STATE_CHAT_JOIN,
AVC_STATE_CHAT_SESSION_PROCESSING,
AVC_STATE_CHAT_LEAVE,
AVC_STATE_CHAT_RESET,
AVC_STATE_CHAT_UNLOAD,
AVC_STATE_EXIT,
};
/* event list */
enum EAVCEvent
{
AVC_EVENT_NON = AVC_STATE_EXIT + 1,
AVC_EVENT_EPSILON,
AVC_EVENT_LAN_DISCONNECT,
AVC_EVENT_ONLINE,
AVC_EVENT_OFFLINE,
AVC_EVENT_EXIT_GAME,
AVC_EVENT_ROOM_CREATE,
AVC_EVENT_ROOM_SEARCH,
AVC_EVENT_ERROR,
AVC_EVENT_FATAL_ERROR,
AVC_EVENT_NETDIALOG_FINISHED,
AVC_EVENT_NETDIALOG_UNLOADED,
AVC_EVENT_NP2_INIT_SUCCEEDED,
AVC_EVENT_NP2_FINALIZE_SUCCEEDED,
AVC_EVENT_NP2_START_CONTEXT_SUCCEEDED,
AVC_EVENT_NP2_STOP_CONTEXT_SUCCEEDED,
AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,
AVC_EVENT_NP2_ROOM_MEMBER_LEFT,
AVC_EVENT_NP2_ROOM_MEMBER_JOINED,
AVC_EVENT_CHAT_LOAD_SUCCEEDED,
AVC_EVENT_CHAT_LOAD_FAILED,
AVC_EVENT_CHAT_JOIN_SUCCEEDED,
AVC_EVENT_CHAT_JOIN_FAILED,
AVC_EVENT_CHAT_LEAVE_SUCCEEDED,
AVC_EVENT_CHAT_LEAVE_FAILED,
AVC_EVENT_CHAT_UNLOAD_SUCCEEDED,
AVC_EVENT_CHAT_UNLOAD_FAILED,
AVC_EVENT_CHAT_INIT_SUCCEEDED,
AVC_EVENT_CHAT_FINALIZE_SUCCEEDED,
AVC_EVENT_CHAT_SESSION_STOPPED,
AVC_EVENT_CREATE_JOIN_ROOM_SUCCEEDED,
AVC_EVENT_SEARCH_ROOM_SUCCEEDED,
AVC_EVENT_JOIN_ROOM_SUCCEEDED,
AVC_EVENT_LEAVE_ROOM_SUCCEEDED,
AVC_EVENT_SIGNALING_ESTABLISHED,
AVC_EVENT_SIGNALING_DEAD,
AVC_EVENT_UI_CLOSE_SUCCEEDED,
};
typedef struct
{
int state;
int event;
int (*func)(void);
EAVCState new_state;
} state_transition_table;
class SonyVoiceChat
{
public:
static void init(SQRNetworkManager_PS3* pNetMan);
static void shutdown();
static void tick();
static void setEnabled(bool bEnabled);
static bool hasMicConnected(const SceNpMatching2RoomMemberId *players_id);
static bool isTalking(SceNpMatching2RoomMemberId* players_id);
static void mute(bool bMute); //Turn chat audio on or off
static void mutePlayer(const SceNpMatching2RoomMemberId member_id, bool bMute); //Turn chat audio from a specified player on or off;
static void muteLocalPlayer(bool bMute); //Turn microphone input on or off;
static bool isMuted();
static bool isMutedPlayer(const SceNpMatching2RoomMemberId member_id);
static bool isMutedLocalPlayer(); //Turn microphone input on or off;
static void setVolume(float vol); // 0.0f - 1.0f range
static float getVolume(); // 0.0f - 1.0f range
static bool isShuttingDown() { return (sm_state == AVC_STATE_CHAT_LEAVE || sm_state == AVC_STATE_CHAT_UNLOAD || AVC_STATE_CHAT_RESET); }
static void signalRoomDestroyed() { if(!isShuttingDown()) sm_event = AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT;}
static void signalRoomKickedOut() { if(!isShuttingDown()) sm_event = AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT;}
static void signalDisconnected() { if(!isShuttingDown()) sm_event = AVC_EVENT_LAN_DISCONNECT;}
private:
// static np2_matching2_info sm_matchingInfo;
static EAVCEvent sm_event;
static EAVCState sm_state;
static SQRNetworkManager_PS3* sm_pNetworkManager;
static bool sm_bEnabled;
static uint8_t sm_micStatus;
static bool sm_bLoaded;
static bool sm_bUnloading;
static unordered_map<SceNpMatching2RoomMemberId, bool> sm_bTalkingMap;
static bool sm_bCanStart; // set to true on init, false on disconnect, used to see if we should start after a re-enable
static bool sm_isChatRestricted; // true if the parental controls have been set on the main users account
static int sm_currentBitrate;
static int eventcb_load(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static int eventcb_join(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static int eventcb_leave( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static int eventcb_unload(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static int eventcb_voiceDetected(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static void eventcb( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata);
static int initialize();
static int finalize();
static int load();
static int unload();
static int join();
static int leave();
static int start();
static int stop();
static int startStream();
static int stopStream();
// static int update_target();
static void do_state_transition( state_transition_table *tbl, int tbl_size);
static int invoke_epsilon_event();
static void setBitRate();
static void setEvent(EAVCEvent event);
static void setState(EAVCState state);
static void printStateAndEvent();
};