-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
888d6b7
commit 58fdbe5
Showing
7 changed files
with
465 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,373 @@ | ||
#include "nw4r/snd/snd_RemoteSpeaker.h" | ||
#include "nw4r/snd/snd_RemoteSpeakerManager.h" | ||
#include "nw4r/ut.h" | ||
#include <string.h> | ||
|
||
namespace nw4r { | ||
namespace snd { | ||
|
||
RemoteSpeaker::RemoteSpeaker() | ||
: mInitFlag(false), | ||
mPlayFlag(false), | ||
mEnableFlag(false), | ||
mFirstEncodeFlag(false), | ||
mValidCallbackFlag(false), | ||
mCommandBusyFlag(false), | ||
mState(STATE_INVALID), | ||
mUserCommand(COMMAND_NONE), | ||
mInternalCommand(COMMAND_NONE), | ||
mWpadCallback(NULL) { | ||
|
||
OSCreateAlarm(&mContinueAlarm); | ||
OSSetAlarmUserData(&mContinueAlarm, this); | ||
|
||
OSCreateAlarm(&mIntervalAlarm); | ||
OSSetAlarmUserData(&mIntervalAlarm, this); | ||
} | ||
|
||
void RemoteSpeaker::InitParam() { | ||
ClearParam(); | ||
|
||
mContinueFlag = false; | ||
mPlayFlag = false; | ||
mEnableFlag = true; | ||
mIntervalFlag = false; | ||
} | ||
|
||
void RemoteSpeaker::ClearParam() { | ||
mPlayFlag = false; | ||
mEnableFlag = false; | ||
|
||
OSCancelAlarm(&mContinueAlarm); | ||
mContinueFlag = false; | ||
|
||
OSCancelAlarm(&mIntervalAlarm); | ||
mIntervalFlag = false; | ||
} | ||
|
||
bool RemoteSpeaker::Setup(WPADCallback pCallback) { | ||
ut::AutoInterruptLock lock; | ||
|
||
InitParam(); | ||
|
||
if (mWpadCallback != NULL) { | ||
mWpadCallback(mChannelIndex, WPAD_ERR_OK); | ||
mValidCallbackFlag = false; | ||
} | ||
|
||
mUserCommand = COMMAND_SPEAKER_ON; | ||
mWpadCallback = pCallback; | ||
mInitFlag = true; | ||
|
||
return true; | ||
} | ||
|
||
void RemoteSpeaker::Shutdown(WPADCallback pCallback) { | ||
ut::AutoInterruptLock lock; | ||
|
||
ClearParam(); | ||
|
||
if (mWpadCallback != NULL) { | ||
mWpadCallback(mChannelIndex, WPAD_ERR_OK); | ||
mValidCallbackFlag = false; | ||
} | ||
|
||
mUserCommand = COMMAND_SPEAKER_OFF; | ||
mWpadCallback = pCallback; | ||
mInitFlag = false; | ||
} | ||
|
||
bool RemoteSpeaker::EnableOutput(bool enable) { | ||
if (!mInitFlag) { | ||
return false; | ||
} | ||
|
||
mEnableFlag = enable; | ||
return true; | ||
} | ||
|
||
bool RemoteSpeaker::IsEnabledOutput() const { | ||
if (!mInitFlag) { | ||
return false; | ||
} | ||
|
||
return mEnableFlag; | ||
} | ||
|
||
void RemoteSpeaker::Update() { | ||
if (mCommandBusyFlag) { | ||
return; | ||
} | ||
|
||
SpeakerCommand command = | ||
mUserCommand != COMMAND_NONE ? mUserCommand : mInternalCommand; | ||
|
||
mUserCommand = COMMAND_NONE; | ||
mInternalCommand = COMMAND_NONE; | ||
|
||
ExecCommand(command); | ||
} | ||
|
||
void RemoteSpeaker::ExecCommand(SpeakerCommand command) { | ||
switch (command) { | ||
case COMMAND_NONE: { | ||
break; | ||
} | ||
|
||
case COMMAND_SPEAKER_ON: { | ||
mValidCallbackFlag = true; | ||
mCommandBusyFlag = true; | ||
mState = STATE_EXEC_SPEAKER_ON; | ||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_ON, SpeakerOnCallback); | ||
break; | ||
} | ||
|
||
case COMMAND_SPEAKER_PLAY: { | ||
mValidCallbackFlag = true; | ||
mCommandBusyFlag = true; | ||
mState = STATE_EXEC_SPEAKER_PLAY; | ||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_PLAY, | ||
SpeakerPlayCallback); | ||
break; | ||
} | ||
|
||
case COMMAND_SPEAKER_OFF: { | ||
mValidCallbackFlag = true; | ||
mCommandBusyFlag = true; | ||
mState = STATE_EXEC_SPEAKER_OFF; | ||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_OFF, SpeakerOffCallback); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
void RemoteSpeaker::UpdateStreamData(const s16* pRmtSamples) { | ||
if (!IsAvailable()) { | ||
return; | ||
} | ||
|
||
bool playFlag = true; | ||
bool silentFlag = mEnableFlag ? IsAllSampleZero(pRmtSamples) : true; | ||
|
||
if (silentFlag /*|| mForceResumeFlag*/) { | ||
playFlag = false; | ||
} | ||
|
||
bool firstFlag = !mPlayFlag && playFlag; | ||
bool lastFlag = mPlayFlag && !playFlag; | ||
|
||
if (playFlag) { | ||
ut::AutoInterruptLock lock; | ||
|
||
if (!WPADCanSendStreamData(mChannelIndex)) { | ||
return; | ||
} | ||
|
||
u32 wencMode = !mFirstEncodeFlag ? WENC_FLAG_USER_INFO : 0; | ||
mFirstEncodeFlag = false; | ||
|
||
u8 adpcmBuffer[SAMPLES_PER_ENCODED_PACKET]; | ||
WENCGetEncodeData(&mEncodeInfo, wencMode, pRmtSamples, | ||
SAMPLES_PER_AUDIO_PACKET, adpcmBuffer); | ||
|
||
s32 result = WPADSendStreamData(mChannelIndex, adpcmBuffer, | ||
SAMPLES_PER_ENCODED_PACKET); | ||
if (result != WPAD_ERR_OK) { | ||
mInternalCommand = COMMAND_SPEAKER_ON; | ||
mState = STATE_INVALID; | ||
InitParam(); | ||
|
||
return; | ||
} | ||
} | ||
|
||
if (firstFlag) { | ||
ut::AutoInterruptLock lock; | ||
|
||
if (!mContinueFlag) { | ||
OSSetAlarm(&mContinueAlarm, | ||
OS_SEC_TO_TICKS(CONTINUOUS_PLAY_INTERVAL_MINUTES * 60LL), | ||
ContinueAlarmHandler); | ||
|
||
mContinueBeginTime = OSGetTime(); | ||
mContinueFlag = true; | ||
} | ||
|
||
OSCancelAlarm(&mIntervalAlarm); | ||
mIntervalFlag = false; | ||
} | ||
|
||
if (lastFlag) { | ||
ut::AutoInterruptLock lock; | ||
|
||
mIntervalFlag = true; | ||
OSCancelAlarm(&mIntervalAlarm); | ||
OSSetAlarm(&mIntervalAlarm, OS_SEC_TO_TICKS(1LL), IntervalAlarmHandler); | ||
} | ||
|
||
mPlayFlag = playFlag; | ||
} | ||
|
||
bool RemoteSpeaker::IsAllSampleZero(const s16* pSample) { | ||
const u32* pBuffer = reinterpret_cast<const u32*>(pSample); | ||
bool zeroFlag = true; | ||
|
||
for (int i = 0; i < SAMPLES_PER_ENCODED_PACKET; i++) { | ||
if (pBuffer[i] != 0) { | ||
zeroFlag = false; | ||
break; | ||
} | ||
} | ||
|
||
return zeroFlag; | ||
} | ||
|
||
void RemoteSpeaker::SpeakerOnCallback(s32 chan, s32 result) { | ||
RemoteSpeaker& r = | ||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan); | ||
|
||
switch (result) { | ||
case WPAD_ERR_OK: { | ||
r.mFirstEncodeFlag = true; | ||
memset(&r.mEncodeInfo, 0, sizeof(WENCInfo)); | ||
|
||
r.mState = STATE_SPEAKER_ON; | ||
r.mInternalCommand = COMMAND_SPEAKER_PLAY; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_COMMUNICATION_ERROR: { | ||
r.mInternalCommand = COMMAND_SPEAKER_ON; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_TRANSFER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_NO_CONTROLLER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
default: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
} | ||
|
||
if (result != WPAD_ERR_OK && result != WPAD_ERR_COMMUNICATION_ERROR) { | ||
r.NotifyCallback(chan, result); | ||
} | ||
|
||
r.mCommandBusyFlag = false; | ||
} | ||
|
||
void RemoteSpeaker::SpeakerPlayCallback(s32 chan, s32 result) { | ||
RemoteSpeaker& r = | ||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan); | ||
|
||
switch (result) { | ||
case WPAD_ERR_OK: { | ||
r.mState = STATE_SPEAKER_PLAY; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_COMMUNICATION_ERROR: { | ||
r.mInternalCommand = COMMAND_SPEAKER_PLAY; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_TRANSFER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_NO_CONTROLLER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
default: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
} | ||
|
||
if (result != WPAD_ERR_COMMUNICATION_ERROR) { | ||
r.NotifyCallback(chan, result); | ||
} | ||
|
||
r.mCommandBusyFlag = false; | ||
} | ||
|
||
void RemoteSpeaker::SpeakerOffCallback(s32 chan, s32 result) { | ||
RemoteSpeaker& r = | ||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan); | ||
|
||
switch (result) { | ||
case WPAD_ERR_OK: { | ||
r.mState = STATE_SPEAKER_OFF; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_COMMUNICATION_ERROR: { | ||
r.mInternalCommand = COMMAND_SPEAKER_OFF; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_TRANSFER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
case WPAD_ERR_NO_CONTROLLER: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
|
||
default: { | ||
r.mState = STATE_INVALID; | ||
break; | ||
} | ||
} | ||
|
||
if (result != WPAD_ERR_COMMUNICATION_ERROR) { | ||
r.NotifyCallback(chan, result); | ||
} | ||
|
||
r.mCommandBusyFlag = false; | ||
} | ||
|
||
void RemoteSpeaker::NotifyCallback(s32 chan, s32 result) { | ||
if (mValidCallbackFlag && mWpadCallback != NULL) { | ||
mWpadCallback(chan, result); | ||
mWpadCallback = NULL; | ||
} | ||
} | ||
|
||
void RemoteSpeaker::ContinueAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) { | ||
#pragma unused(pCtx) | ||
|
||
ut::AutoInterruptLock lock; | ||
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm)); | ||
} | ||
|
||
void RemoteSpeaker::IntervalAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) { | ||
#pragma unused(pCtx) | ||
|
||
ut::AutoInterruptLock lock; | ||
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm)); | ||
|
||
if (p->mIntervalFlag) { | ||
OSCancelAlarm(&p->mContinueAlarm); | ||
// p->mForceResumeFlag = false; | ||
p->mContinueFlag = false; | ||
} | ||
|
||
p->mIntervalFlag = false; | ||
} | ||
|
||
} // namespace snd | ||
} // namespace nw4r |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,74 @@ | ||
#include "nw4r/snd/snd_RemoteSpeakerManager.h" | ||
#include "rvl/AX.h" | ||
|
||
namespace nw4r { | ||
namespace snd { | ||
namespace detail { | ||
|
||
RemoteSpeakerManager& RemoteSpeakerManager::GetInstance() { | ||
static RemoteSpeakerManager instance; | ||
return instance; | ||
} | ||
|
||
RemoteSpeakerManager::RemoteSpeakerManager() : mInitialized(false) { | ||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { | ||
mSpeaker[i].SetChannelIndex(i); | ||
} | ||
} | ||
|
||
RemoteSpeaker& RemoteSpeakerManager::GetRemoteSpeaker(int i) { | ||
return mSpeaker[i]; | ||
} | ||
|
||
void RemoteSpeakerManager::Setup() { | ||
if (mInitialized) { | ||
return; | ||
} | ||
|
||
OSCreateAlarm(&mRemoteSpeakerAlarm); | ||
|
||
OSSetPeriodicAlarm(&mRemoteSpeakerAlarm, OSGetTime(), | ||
OS_NSEC_TO_TICKS(SPEAKER_ALARM_PERIOD_NSEC), | ||
RemoteSpeakerAlarmProc); | ||
|
||
mInitialized = true; | ||
} | ||
|
||
void RemoteSpeakerManager::Shutdown() { | ||
if (!mInitialized) { | ||
return; | ||
} | ||
|
||
OSCancelAlarm(&mRemoteSpeakerAlarm); | ||
mInitialized = false; | ||
} | ||
|
||
void RemoteSpeakerManager::RemoteSpeakerAlarmProc(OSAlarm* pAlarm, | ||
OSContext* pCtx) { | ||
#pragma unused(pAlarm) | ||
#pragma unused(pCtx) | ||
|
||
RemoteSpeakerManager& r = GetInstance(); | ||
|
||
s16 samples[RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET]; | ||
if (AXRmtGetSamplesLeft() < RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET) { | ||
return; | ||
} | ||
|
||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { | ||
if (r.mSpeaker[i].IsAvailable()) { | ||
AXRmtGetSamples(i, samples, | ||
RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET); | ||
|
||
r.mSpeaker[i].UpdateStreamData(samples); | ||
} | ||
|
||
r.mSpeaker[i].Update(); | ||
} | ||
|
||
AXRmtAdvancePtr(RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET); | ||
} | ||
|
||
} // namespace detail | ||
} // namespace snd | ||
} // namespace nw4r |