Init
This commit is contained in:
237
Samples/RakVoiceFMOD/FMODVoiceAdapter.cpp
Normal file
237
Samples/RakVoiceFMOD/FMODVoiceAdapter.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017-2020, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "slikenet/peerinterface.h"
|
||||
#include "slikenet/MessageIdentifiers.h"
|
||||
|
||||
#include "FMODVoiceAdapter.h"
|
||||
#include "fmod_errors.h"
|
||||
|
||||
|
||||
/// To test sending to myself
|
||||
//#define _TEST_LOOPBACK
|
||||
|
||||
|
||||
// Number of RakVoice frames in the fmod sound
|
||||
#define FRAMES_IN_SOUND 4
|
||||
|
||||
using namespace SLNet;
|
||||
|
||||
FMODVoiceAdapter FMODVoiceAdapter::instance;
|
||||
|
||||
FMODVoiceAdapter::FMODVoiceAdapter(){
|
||||
rakVoice=0;
|
||||
fmodSystem = 0;
|
||||
recSound=0;
|
||||
sound=0;
|
||||
channel=0;
|
||||
mute=false;
|
||||
}
|
||||
|
||||
FMODVoiceAdapter* FMODVoiceAdapter::Instance(){
|
||||
return &instance;
|
||||
}
|
||||
|
||||
bool FMODVoiceAdapter::SetupAdapter(FMOD::System *fmodSystem, RakVoice *rakVoice)
|
||||
{
|
||||
FMOD_RESULT fmodErr;
|
||||
|
||||
RakAssert(fmodSystem);
|
||||
RakAssert(rakVoice);
|
||||
// Make sure rakVoice was initialized
|
||||
RakAssert((rakVoice->IsInitialized())&&(rakVoice->GetRakPeerInterface()!= nullptr));
|
||||
|
||||
this->fmodSystem = fmodSystem;
|
||||
this->rakVoice = rakVoice;
|
||||
lastPlayPos = 0;
|
||||
lastRecordingPos = 0;
|
||||
|
||||
//
|
||||
// Create the FMOD sound used to record
|
||||
//
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
|
||||
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
|
||||
exinfo.numchannels = 1;
|
||||
exinfo.format = FMOD_SOUND_FORMAT_PCM16;
|
||||
exinfo.defaultfrequency = rakVoice->GetSampleRate();
|
||||
exinfo.length = rakVoice->GetBufferSizeBytes()*FRAMES_IN_SOUND;
|
||||
|
||||
fmodErr = fmodSystem->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &recSound);
|
||||
if (fmodErr!=FMOD_OK)
|
||||
return false;
|
||||
|
||||
// Create the FMOD sound used to play incoming sound data
|
||||
fmodErr = fmodSystem->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound);
|
||||
if (fmodErr!=FMOD_OK)
|
||||
return false;
|
||||
|
||||
// Start playing the sound used for output
|
||||
sound->setMode(FMOD_LOOP_NORMAL);
|
||||
fmodErr= fmodSystem->playSound(FMOD_CHANNEL_REUSE, sound, false, &channel);
|
||||
if (fmodErr!=FMOD_OK)
|
||||
return false;
|
||||
|
||||
// Start recording
|
||||
fmodErr=fmodSystem->recordStart(0,recSound, true);
|
||||
if (fmodErr!=FMOD_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FMODVoiceAdapter::Update(void)
|
||||
{
|
||||
RakAssert(fmodSystem);
|
||||
UpdateSound(true);
|
||||
UpdateSound(false);
|
||||
}
|
||||
|
||||
void FMODVoiceAdapter::Release(void)
|
||||
{
|
||||
FMOD_RESULT err;
|
||||
|
||||
if (fmodSystem== nullptr) return;
|
||||
|
||||
// Stop recording
|
||||
bool recording=false;
|
||||
err = fmodSystem->isRecording(0,&recording);
|
||||
RakAssert(err==FMOD_OK);
|
||||
if (recording){
|
||||
fmodSystem->recordStop(0);
|
||||
}
|
||||
|
||||
// Stop what we hear
|
||||
bool playing;
|
||||
err = channel->isPlaying(&playing);
|
||||
RakAssert(err==FMOD_OK);
|
||||
if (playing){
|
||||
channel->stop();
|
||||
}
|
||||
|
||||
if (recSound!= nullptr)
|
||||
{
|
||||
recSound->release();
|
||||
recSound = nullptr;
|
||||
}
|
||||
|
||||
if (sound!= nullptr)
|
||||
{
|
||||
sound->release();
|
||||
sound = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FMODVoiceAdapter::SetMute(bool mute)
|
||||
{
|
||||
this->mute = mute;
|
||||
}
|
||||
|
||||
|
||||
void FMODVoiceAdapter::UpdateSound(bool isRec)
|
||||
{
|
||||
FMOD_RESULT fmodErr;
|
||||
unsigned int soundLength;
|
||||
const int sampleSize = 2;
|
||||
|
||||
FMOD::Sound *snd = (isRec) ? recSound : sound;
|
||||
unsigned int& lastPos = (isRec) ? lastRecordingPos : lastPlayPos;
|
||||
|
||||
// get current Play or recording position
|
||||
unsigned int currPos;
|
||||
if (isRec){
|
||||
fmodErr=fmodSystem->getRecordPosition(0,&currPos);
|
||||
RakAssert(fmodErr==FMOD_OK);
|
||||
} else {
|
||||
fmodErr=channel->getPosition(&currPos, FMOD_TIMEUNIT_PCM);
|
||||
RakAssert(fmodErr==FMOD_OK);
|
||||
}
|
||||
|
||||
// Get length of sound in samples
|
||||
fmodErr=snd->getLength(&soundLength, FMOD_TIMEUNIT_PCM);
|
||||
RakAssert(fmodErr==FMOD_OK);
|
||||
|
||||
// calculate some variables we'll need ahead
|
||||
int bufferSizeBytes = rakVoice->GetBufferSizeBytes();
|
||||
|
||||
// Round down the current position to a multiple of buffer size in samples
|
||||
currPos -= currPos % (bufferSizeBytes/sampleSize);
|
||||
|
||||
if ( ((!isRec)||(isRec && !mute)) && (currPos != lastPos) )
|
||||
{
|
||||
void *ptr1, *ptr2;
|
||||
unsigned int len1, len2;
|
||||
int blockLength;
|
||||
|
||||
blockLength = (int)currPos - (int)lastPos;
|
||||
// Check for wrap around, and adjust
|
||||
if (blockLength < 0)
|
||||
{
|
||||
blockLength += soundLength;
|
||||
}
|
||||
|
||||
// Lock to get access to the raw data
|
||||
snd->lock(lastPos * sampleSize, blockLength * sampleSize, &ptr1, &ptr2, &len1, &len2);
|
||||
|
||||
// Since the length and current position are both a multiple of bufferSizeBytes
|
||||
// just treat treat one full buffer at a time
|
||||
int numFrames = len1 / bufferSizeBytes;
|
||||
while(numFrames--){
|
||||
if (isRec) {
|
||||
BroadcastFrame(ptr1);
|
||||
} else {
|
||||
rakVoice->ReceiveFrame(ptr1);
|
||||
}
|
||||
ptr1 = (char*)ptr1 + bufferSizeBytes;
|
||||
}
|
||||
numFrames = len2 / bufferSizeBytes;
|
||||
while(numFrames--) {
|
||||
if (isRec){
|
||||
BroadcastFrame(ptr2);
|
||||
} else {
|
||||
rakVoice->ReceiveFrame(ptr2);
|
||||
}
|
||||
ptr2 = (char*)ptr2 + bufferSizeBytes;
|
||||
}
|
||||
|
||||
snd->unlock(ptr1, ptr2, len1, len2);
|
||||
}
|
||||
|
||||
lastPos = currPos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FMODVoiceAdapter::BroadcastFrame(void *ptr)
|
||||
{
|
||||
#ifndef _TEST_LOOPBACK
|
||||
unsigned i;
|
||||
|
||||
unsigned int numPeers = rakVoice->GetRakPeerInterface()->GetMaximumNumberOfPeers();
|
||||
for (i=0; i < numPeers; i++)
|
||||
{
|
||||
rakVoice->SendFrame(rakVoice->GetRakPeerInterface()->GetGUIDFromIndex(i), ptr);
|
||||
}
|
||||
#else
|
||||
rakVoice->SendFrame(SLNet::UNASSIGNED_SYSTEM_ADDRESS, ptr);
|
||||
#endif
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user