mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1142 lines
33 KiB
C
1142 lines
33 KiB
C
![]() |
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
#include "gvPS3Headset.h"
|
||
|
#if !defined(GV_NO_PS3_HEADSET)
|
||
|
#include "gvDevice.h"
|
||
|
#include "gvCodec.h"
|
||
|
#include "gvSource.h"
|
||
|
#include "gvUtil.h"
|
||
|
#include <types.h>
|
||
|
#include <sys/event.h>
|
||
|
#include <cell/audio.h>
|
||
|
#include <cell/mic.h>
|
||
|
#include <cell/sysmodule.h>
|
||
|
#include <cell/mixer.h>
|
||
|
|
||
|
|
||
|
#if !defined(_PS3)
|
||
|
#error This file should only be used with the PlayStation3
|
||
|
#endif
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// definitions
|
||
|
#define GVI_PLAYBACK_STAYAHEAD_MILLISECONDS 50
|
||
|
|
||
|
// Used as a starting value for the audio port queue key
|
||
|
#define GVI_AUDIO_QUEUE_KEY_BASE 0x0000998877660000ULL
|
||
|
|
||
|
// Used as a starting value for the capture event queue key
|
||
|
#define GVI_CAPTURE_QUEUE_KEY_BASE 0x0000000072110700UL
|
||
|
|
||
|
#define GVI_AUDIO_QUEUE_DEPTH 4
|
||
|
#define GVI_CAPTURE_VOLUME_MAX 241
|
||
|
#define GVI_PLAYBACK_NUM_BLOCKS CELL_AUDIO_BLOCK_32
|
||
|
#define GVI_PLAYBACK_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES
|
||
|
#define GVI_PLAYBACK_SAMPLE_RATE 48000 //Hz
|
||
|
#define GVI_PS3_MIC_BUFFER_MS 1000
|
||
|
#define GVI_LOCAL_TALK_MAX 10
|
||
|
#define GVI_PLAYBACK_SAMPLE_FACTOR (GVI_PLAYBACK_SAMPLE_RATE / gviGetSampleRate())
|
||
|
#define GVI_NUM_CHANNELS CELL_AUDIO_PORT_2CH
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// structs
|
||
|
typedef struct
|
||
|
{
|
||
|
sys_event_t m_captureCallbackEvent;
|
||
|
sys_event_queue_t m_captureCallbackQueue;
|
||
|
uint64_t m_captureEventQueueKey;
|
||
|
GVBool m_capturing;
|
||
|
GVScalar m_captureVolume;
|
||
|
GVFrameStamp m_captureClock;
|
||
|
GVScalar m_captureThreshold;
|
||
|
GVFrameStamp m_captureLastCrossedThresholdTime;
|
||
|
float *m_capturePreConvertBuffer;
|
||
|
size_t m_capturePreConvertBufferLen;
|
||
|
GVSample *m_captureBuffer;
|
||
|
|
||
|
int m_captureBufferBytes;
|
||
|
int m_deviceNum; // used to keep the microphone device number
|
||
|
GVBool m_captureMicOpen;
|
||
|
|
||
|
GVBool m_playing;
|
||
|
GVScalar m_playbackVolume;
|
||
|
GVFrameStamp m_playbackClock;
|
||
|
GVISourceList m_playbackSources;
|
||
|
GVSample *m_playbackBuffer;
|
||
|
gsi_u32 m_playbackCellAudioPortNum;
|
||
|
CellAudioPortConfig m_playbackCellAudioConfig;
|
||
|
sys_event_queue_t m_playbackQueue;
|
||
|
uint64_t m_playbackQueueKey;
|
||
|
int m_playbackPortPos;
|
||
|
} GVIPS3HeadsetData;
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// globals
|
||
|
static GVIDeviceList GVIDevices;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// gets the device by the deviceID
|
||
|
static GVIDevice * gviFindDeviceByID(GVDeviceID deviceID)
|
||
|
{
|
||
|
GVIDevice * device;
|
||
|
int num;
|
||
|
int i;
|
||
|
|
||
|
num = gviGetNumDevices(GVIDevices);
|
||
|
for(i = 0 ; i < num ; i++)
|
||
|
{
|
||
|
device = gviGetDevice(GVIDevices, i);
|
||
|
if(device->m_deviceID == deviceID)
|
||
|
return device;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// frees the device
|
||
|
static void gviFreeArrayDevice(void * elem)
|
||
|
{
|
||
|
GS_ASSERT(elem);
|
||
|
GVIDevice * device = *(GVIDevice **)elem;
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
int result;
|
||
|
|
||
|
// turn off mic if its a capture device and if the mic port is open
|
||
|
if (data->m_capturing && cellMicIsOpen(data->m_deviceNum))
|
||
|
result = cellMicClose(data->m_deviceNum);
|
||
|
|
||
|
// Destroy the callback and playback queues
|
||
|
if (data->m_playbackQueue)
|
||
|
cellAudioRemoveNotifyEventQueue(data->m_playbackQueueKey);
|
||
|
if (data->m_captureCallbackQueue)
|
||
|
cellMicRemoveNotifyEventQueue(data->m_captureEventQueueKey);
|
||
|
if (data->m_playbackQueue)
|
||
|
sys_event_queue_destroy(data->m_playbackQueue, 0);
|
||
|
if (data->m_captureCallbackQueue)
|
||
|
sys_event_queue_destroy(data->m_captureCallbackQueue, 0);
|
||
|
|
||
|
// close audio port
|
||
|
if (data->m_playing)
|
||
|
cellAudioPortClose(data->m_playbackCellAudioPortNum);
|
||
|
|
||
|
// playback specific cleanup
|
||
|
if(device->m_types & GV_PLAYBACK)
|
||
|
{
|
||
|
if(data->m_playbackSources)
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
gsifree(data->m_playbackBuffer);
|
||
|
}
|
||
|
|
||
|
// capture specific cleanup
|
||
|
if(device->m_types & GV_CAPTURE)
|
||
|
{
|
||
|
gsifree(data->m_captureBuffer);
|
||
|
gsifree(data->m_capturePreConvertBuffer);
|
||
|
}
|
||
|
|
||
|
// free the device
|
||
|
gviFreeDevice(device);
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// starts up the headset
|
||
|
GVBool gviPS3HeadsetStartup(void)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
// create the array of devices
|
||
|
GVIDevices = gviNewDeviceList(gviFreeArrayDevice);
|
||
|
if(!GVIDevices)
|
||
|
return GVFalse;
|
||
|
|
||
|
// initialize the mic library
|
||
|
result = cellSysmoduleLoadModule(CELL_SYSMODULE_MIC);
|
||
|
if(result != CELL_OK)
|
||
|
{
|
||
|
gviFreeDeviceList(GVIDevices);
|
||
|
GVIDevices = NULL;
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
result = cellMicInit();
|
||
|
if(result != CELL_OK)
|
||
|
{
|
||
|
gviFreeDeviceList(GVIDevices);
|
||
|
GVIDevices = NULL;
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// initialize the audio library
|
||
|
result = cellSysmoduleLoadModule(CELL_SYSMODULE_AUDIO);
|
||
|
if(result != CELL_OK)
|
||
|
{
|
||
|
gviFreeDeviceList(GVIDevices);
|
||
|
GVIDevices = NULL;
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
result = cellAudioInit();
|
||
|
if(result != CELL_OK && result != CELL_AUDIO_ERROR_ALREADY_INIT)
|
||
|
{
|
||
|
gviFreeDeviceList(GVIDevices);
|
||
|
cellMicEnd();
|
||
|
GVIDevices = NULL;
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// unloads the headset
|
||
|
void gviPS3HeadsetCleanup(void)
|
||
|
{
|
||
|
// free the device array
|
||
|
if(GVIDevices)
|
||
|
{
|
||
|
gviFreeDeviceList(GVIDevices);
|
||
|
GVIDevices = NULL;
|
||
|
}
|
||
|
|
||
|
cellMicEnd();
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// process playback if there is any in the queue
|
||
|
static GVBool gviPlaybackDeviceThink(GVIDevice * device)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
int remainingSamples;
|
||
|
int numFrames;
|
||
|
GVBool wroteToBuffer;
|
||
|
int i, j, k;
|
||
|
sys_event_t playbackQueueEvent;
|
||
|
int result;
|
||
|
int playbackReadPos;
|
||
|
unsigned int currentBlock;
|
||
|
int totalSamples;
|
||
|
|
||
|
// don't do anything if we're not playing
|
||
|
if(!data->m_playing)
|
||
|
return GVTrue;
|
||
|
|
||
|
// check the queue
|
||
|
result = sys_event_queue_receive(data->m_playbackQueue, &playbackQueueEvent, 1);
|
||
|
if(result == ETIMEDOUT)
|
||
|
{
|
||
|
return GVTrue;
|
||
|
}
|
||
|
if(result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
totalSamples = (GVI_PLAYBACK_NUM_BLOCKS * GVI_PLAYBACK_BLOCK_SAMPLES);
|
||
|
|
||
|
currentBlock = (unsigned int)*(uint64_t *)(data->m_playbackCellAudioConfig.readIndexAddr);
|
||
|
playbackReadPos = (currentBlock * GVI_PLAYBACK_BLOCK_SAMPLES);
|
||
|
|
||
|
if(data->m_playbackPortPos == -1)
|
||
|
{
|
||
|
unsigned int nextBlock = (currentBlock + 1) % GVI_PLAYBACK_NUM_BLOCKS; // write target is next block
|
||
|
data->m_playbackPortPos = (nextBlock * GVI_PLAYBACK_BLOCK_SAMPLES);
|
||
|
}
|
||
|
|
||
|
remainingSamples = (((playbackReadPos + totalSamples) - data->m_playbackPortPos) % totalSamples);
|
||
|
|
||
|
// figure out the number of frames that we can write
|
||
|
numFrames = ((remainingSamples / GVI_PLAYBACK_SAMPLE_FACTOR) / GVISamplesPerFrame);
|
||
|
|
||
|
// write the frames
|
||
|
for(i = 0 ; i < numFrames ; i++)
|
||
|
{
|
||
|
// write a frame of sources to our buffer
|
||
|
wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, data->m_playbackBuffer, 1);
|
||
|
|
||
|
// clear it if nothing was written
|
||
|
if(!wroteToBuffer)
|
||
|
memset(data->m_playbackBuffer, 0, (unsigned int)GVIBytesPerFrame);
|
||
|
|
||
|
// filter
|
||
|
if(device->m_playbackFilterCallback)
|
||
|
device->m_playbackFilterCallback(device, data->m_playbackBuffer, data->m_playbackClock);
|
||
|
|
||
|
// write to port buffer from m_playbackBuffer
|
||
|
// converting from sample to float
|
||
|
// converting from 8khz or 16KHz to 48khz and mono to stereo (write each sample 6-12
|
||
|
// times depending on sample rate)
|
||
|
for(j = 0 ; j < GVISamplesPerFrame ; j++)
|
||
|
{
|
||
|
float sample = ((float)data->m_playbackBuffer[j] / (float)SHRT_MAX);
|
||
|
for(k = 0; k < GVI_PLAYBACK_SAMPLE_FACTOR; k++)
|
||
|
{
|
||
|
float *dest = (float *)(data->m_playbackCellAudioConfig.portAddr +
|
||
|
(data->m_playbackPortPos * GVI_NUM_CHANNELS * sizeof(float)));
|
||
|
*dest++ = sample;
|
||
|
*dest = sample;
|
||
|
data->m_playbackPortPos++;
|
||
|
data->m_playbackPortPos %= totalSamples;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update the clock
|
||
|
data->m_playbackClock++;
|
||
|
}
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// called every once in a while to process playback
|
||
|
void gviPS3HeadsetThink(void)
|
||
|
{
|
||
|
GVIDevice * device;
|
||
|
GVBool rcode;
|
||
|
int num;
|
||
|
int i;
|
||
|
|
||
|
if(!GVIDevices)
|
||
|
return;
|
||
|
|
||
|
// loop through the devices backwards to that we can remove devices as we go
|
||
|
num = gviGetNumDevices(GVIDevices);
|
||
|
for(i = (num - 1) ; i >= 0 ; i--)
|
||
|
{
|
||
|
// get the device
|
||
|
device = gviGetDevice(GVIDevices, i);
|
||
|
|
||
|
// // check if playback is setup on the device
|
||
|
if(device->m_types & GV_PLAYBACK)
|
||
|
{
|
||
|
// let it think
|
||
|
rcode = gviPlaybackDeviceThink(device);
|
||
|
|
||
|
// check if the device was unplugged
|
||
|
if(!rcode)
|
||
|
gviDeviceUnplugged(device);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// gets the devices detected
|
||
|
int gviPS3HeadsetListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types)
|
||
|
{
|
||
|
int index;
|
||
|
int numDevices = 0;
|
||
|
|
||
|
maxDevices = min(maxDevices, CELL_MAX_MICS);
|
||
|
|
||
|
for(index = 0 ; index < maxDevices ; index++)
|
||
|
{
|
||
|
if(cellMicIsAttached(index))
|
||
|
{
|
||
|
int deviceType;
|
||
|
if (cellMicGetType(index, &deviceType) == CELL_OK)
|
||
|
{
|
||
|
if (deviceType == CELLMIC_TYPE_USBAUDIO)
|
||
|
{
|
||
|
devices[numDevices].m_id = index;
|
||
|
devices[numDevices].m_deviceType = GV_CAPTURE | GV_PLAYBACK;
|
||
|
devices[numDevices].m_defaultDevice = (GVDeviceType)0;
|
||
|
_tcscpy(devices[numDevices].m_name, _T("USB Headset"));
|
||
|
devices[numDevices].m_hardwareType = GVHardwarePS3Headset;
|
||
|
}
|
||
|
else if (deviceType == CELLMIC_TYPE_BLUETOOTH)
|
||
|
{
|
||
|
devices[numDevices].m_id = index;
|
||
|
devices[numDevices].m_deviceType = GV_CAPTURE | GV_PLAYBACK;
|
||
|
devices[numDevices].m_defaultDevice = (GVDeviceType)0;
|
||
|
_tcscpy(devices[numDevices].m_name, _T("Bluetooth Headset"));
|
||
|
devices[numDevices].m_hardwareType = GVHardwarePS3Headset;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
numDevices++;
|
||
|
}
|
||
|
}
|
||
|
return numDevices;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// unloades the device from the device array
|
||
|
static void gviPS3HeadsetFreeDevice(GVIDevice * device)
|
||
|
{
|
||
|
// delete it from the array
|
||
|
// it will clear out internal data in the array's free function
|
||
|
gviDeleteDeviceFromList(GVIDevices, device);
|
||
|
}
|
||
|
|
||
|
static GVBool gviPS3HeadsetInitHeadphone(GVIPS3HeadsetData *data)
|
||
|
{
|
||
|
int result;
|
||
|
CellAudioPortParam audioParam;
|
||
|
sys_event_queue_attribute_t aQueueAttr;
|
||
|
int aCount;
|
||
|
|
||
|
audioParam.attr = CELL_AUDIO_PORTATTR_OUT_SECONDARY;
|
||
|
audioParam.nBlock = GVI_PLAYBACK_NUM_BLOCKS;
|
||
|
audioParam.nChannel = GVI_NUM_CHANNELS;
|
||
|
|
||
|
// set the audio port value to something really abnormal
|
||
|
// so that if the open function fails, the gviPS3HeadsetClose
|
||
|
// will close the port only if a valid port number is assigned
|
||
|
data->m_playbackCellAudioPortNum = 0xFFFFFFFF;
|
||
|
|
||
|
// Playback
|
||
|
///////////
|
||
|
|
||
|
result = cellAudioPortOpen(&audioParam, &data->m_playbackCellAudioPortNum);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// get the config for the audio port so we can use it to write data to the audio port ring buffer
|
||
|
result = cellAudioGetPortConfig(data->m_playbackCellAudioPortNum, &data->m_playbackCellAudioConfig);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// Event queue notify tells us when the system is ready to play new data
|
||
|
aCount = 0;
|
||
|
sys_event_queue_attribute_initialize(aQueueAttr);
|
||
|
aQueueAttr.attr_protocol = SYS_SYNC_FIFO;
|
||
|
data->m_playbackQueueKey = GVI_AUDIO_QUEUE_KEY_BASE;
|
||
|
|
||
|
while (aCount < 10)
|
||
|
{
|
||
|
result = sys_event_queue_create(&data->m_playbackQueue, &aQueueAttr,
|
||
|
data->m_playbackQueueKey, GVI_AUDIO_QUEUE_DEPTH);
|
||
|
if (result == CELL_OK)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
// search unused key
|
||
|
data->m_playbackQueueKey = GVI_AUDIO_QUEUE_KEY_BASE | (rand() & 0x0ffff);
|
||
|
aCount++;
|
||
|
}
|
||
|
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// register event queue to libaudio
|
||
|
result = cellAudioSetNotifyEventQueue(data->m_playbackQueueKey);
|
||
|
if (result < 0)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
GVBool gviPS3HeadsetInitMic(GVIPS3HeadsetData *data)
|
||
|
{
|
||
|
int result = 0;
|
||
|
int aMsg = 0;
|
||
|
int aDevNum=0;
|
||
|
|
||
|
int aCount = 0;
|
||
|
sys_event_queue_attribute_t equeue_attr = {SYS_SYNC_FIFO, SYS_PPU_QUEUE, ""};
|
||
|
|
||
|
// Event queue key for libmic
|
||
|
// checks for an event occurrence
|
||
|
//create event queue to recv "MicIn" callback from MIOS
|
||
|
data->m_captureEventQueueKey = GVI_CAPTURE_QUEUE_KEY_BASE;
|
||
|
|
||
|
while ( (aCount++) < 100 )
|
||
|
{
|
||
|
result = sys_event_queue_create(&data->m_captureCallbackQueue,
|
||
|
&equeue_attr, data->m_captureEventQueueKey, 32);
|
||
|
if (result == CELL_OK) break;
|
||
|
data->m_captureEventQueueKey = GVI_CAPTURE_QUEUE_KEY_BASE | ( rand() & 0xffff);
|
||
|
}
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
//install "MicIn" system-callback(with devnum == -1) to recv attach/detach event
|
||
|
result = cellMicSetNotifyEventQueue(data->m_captureEventQueueKey);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// Wait up to 10 ms before checking if the mike is attached
|
||
|
result = sys_event_queue_receive(data->m_captureCallbackQueue,
|
||
|
&data->m_captureCallbackEvent, 10000);
|
||
|
if(result == ETIMEDOUT)
|
||
|
return GVFalse;
|
||
|
|
||
|
aMsg = (int)data->m_captureCallbackEvent.data1;
|
||
|
aDevNum = (int)data->m_captureCallbackEvent.data2;
|
||
|
|
||
|
if (aMsg == CELLMIC_ATTACH && aDevNum == data->m_deviceNum)
|
||
|
{
|
||
|
// start with the default audio device
|
||
|
result = cellMicOpenEx(data->m_deviceNum, GVI_PLAYBACK_SAMPLE_RATE, 1,
|
||
|
GV_SAMPLES_PER_SECOND, GVI_PS3_MIC_BUFFER_MS, CELLMIC_SIGTYPE_DSP);
|
||
|
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
data->m_captureMicOpen = GVTrue;
|
||
|
}
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
void gviPS3HeadsetCloseHeadphone(GVIPS3HeadsetData *data)
|
||
|
{
|
||
|
// Remove and Destroy the callback and playback queues
|
||
|
if (data->m_playbackQueue)
|
||
|
cellAudioRemoveNotifyEventQueue(data->m_playbackQueue);
|
||
|
if (data->m_playbackQueue)
|
||
|
sys_event_queue_destroy(data->m_playbackQueue, 0);
|
||
|
|
||
|
// the audio port needs to be closed if a device wasn't initialized properly
|
||
|
if (data->m_playbackCellAudioPortNum != 0xFFFFFFFF)
|
||
|
cellAudioPortClose(data->m_playbackCellAudioPortNum);
|
||
|
}
|
||
|
|
||
|
void gviPS3HeadsetCloseMic(GVIPS3HeadsetData *data)
|
||
|
{
|
||
|
// Remove and Destroy the callback and playback queues
|
||
|
if (data->m_captureCallbackQueue)
|
||
|
cellAudioRemoveNotifyEventQueue(data->m_captureCallbackQueue);
|
||
|
if (data->m_captureCallbackQueue)
|
||
|
sys_event_queue_destroy(data->m_captureCallbackQueue, 0);
|
||
|
|
||
|
// The mic should be closed if it is open
|
||
|
if (cellMicIsOpen(data->m_deviceNum))
|
||
|
cellMicClose(data->m_deviceNum);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// initializes the device for playback
|
||
|
static GVBool gviStartPlaybackDevice(GVIPS3HeadsetData * data)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
sys_event_queue_drain(data->m_playbackQueue);
|
||
|
|
||
|
data->m_playbackPortPos = -1;
|
||
|
|
||
|
result = cellAudioPortStart(data->m_playbackCellAudioPortNum);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
// clear the clock
|
||
|
data->m_playbackClock = 0;
|
||
|
|
||
|
// started playing
|
||
|
data->m_playing = GVTrue;
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// initializes the device for capture
|
||
|
static GVBool gviStartCaptureDevice(GVIPS3HeadsetData * data)
|
||
|
{
|
||
|
int result;
|
||
|
// start the mic capture
|
||
|
if (data->m_captureMicOpen)
|
||
|
{
|
||
|
result = cellMicStart(data->m_deviceNum);
|
||
|
if (result != CELL_OK)
|
||
|
return GVFalse;
|
||
|
}
|
||
|
else
|
||
|
return GVFalse;
|
||
|
|
||
|
cellMicReset(data->m_deviceNum);
|
||
|
// no data in the capture buffer
|
||
|
data->m_captureBufferBytes = 0;
|
||
|
data->m_capturePreConvertBufferLen = 0;
|
||
|
|
||
|
// started capturing
|
||
|
data->m_capturing = GVTrue;
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// stops the device
|
||
|
static void gviPS3HeadsetStopDevice(GVIDevice * device, GVDeviceType type)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
cellAudioPortStop(data->m_playbackCellAudioPortNum);
|
||
|
|
||
|
// clear the playback buffer
|
||
|
memset(data->m_playbackBuffer, 0, GVIBytesPerFrame);
|
||
|
|
||
|
// stopped playing
|
||
|
data->m_playing = GVFalse;
|
||
|
|
||
|
// clear any pending sources & buffers
|
||
|
gviClearSourceList(data->m_playbackSources);
|
||
|
}
|
||
|
if(type & GV_CAPTURE)
|
||
|
{
|
||
|
// stop the capture buffer
|
||
|
cellMicStop(data->m_deviceNum);
|
||
|
|
||
|
// clear capture buffer
|
||
|
memset(data->m_captureBuffer, 0, GVIBytesPerFrame);
|
||
|
|
||
|
// stopped capturing
|
||
|
data->m_capturing = GVFalse;
|
||
|
|
||
|
// so a stop then start isn't continuous
|
||
|
data->m_captureClock++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// starts the device
|
||
|
static GVBool gviPS3HeadsetStartDevice(GVIDevice * device, GVDeviceType type)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
if(type == GV_PLAYBACK)
|
||
|
{
|
||
|
return gviStartPlaybackDevice(data);
|
||
|
}
|
||
|
if(type == GV_CAPTURE)
|
||
|
{
|
||
|
return gviStartCaptureDevice(data);
|
||
|
}
|
||
|
if(type == GV_CAPTURE_AND_PLAYBACK)
|
||
|
{
|
||
|
if(!gviStartPlaybackDevice(data))
|
||
|
return GVFalse;
|
||
|
if(!gviStartCaptureDevice(data))
|
||
|
{
|
||
|
gviPS3HeadsetStopDevice(device, GV_PLAYBACK);
|
||
|
return GVFalse;
|
||
|
}
|
||
|
return GVTrue;
|
||
|
}
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// checks to see if the device is ready
|
||
|
static GVBool gviPS3HeadsetIsDeviceStarted(GVIDevice * device, GVDeviceType type)
|
||
|
{
|
||
|
// NULL device means not even created or started
|
||
|
GS_ASSERT(device);
|
||
|
if (!device)
|
||
|
return GVFalse;
|
||
|
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
if(type == GV_PLAYBACK)
|
||
|
return data->m_playing;
|
||
|
if(type == GV_CAPTURE)
|
||
|
return data->m_capturing;
|
||
|
if(type == GV_CAPTURE_AND_PLAYBACK)
|
||
|
return (data->m_playing && data->m_capturing);
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// sets the volume for the device
|
||
|
static void gviPS3HeadsetSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
cellAudioSetPortLevel(data->m_playbackCellAudioPortNum, volume);
|
||
|
data->m_playbackVolume = volume;
|
||
|
}
|
||
|
if(type & GV_CAPTURE)
|
||
|
{
|
||
|
cellMicSetDeviceAttr(data->m_deviceNum, CELLMIC_DEVATTR_VOLUME, (int)(volume * GVI_CAPTURE_VOLUME_MAX), 0);
|
||
|
data->m_captureVolume = volume;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// gets the device volume
|
||
|
static GVScalar gviPS3HeadsetGetDeviceVolume(GVIDevice * device, GVDeviceType type)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
if(type & GV_PLAYBACK)
|
||
|
return data->m_playbackVolume;
|
||
|
return data->m_captureVolume;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// sets the capture threshold
|
||
|
static void gviPS3HeadsetSetCaptureThreshold(GVIDevice * device, GVScalar threshold)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
data->m_captureThreshold = threshold;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// gets the capture threshold
|
||
|
static GVScalar gviPS3HeadsetGetCaptureThreshold(GVIDevice * device)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
return data->m_captureThreshold;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// gets the available capture bytes
|
||
|
static int gviPS3HeadsetGetAvailableCaptureBytes(GVDevice device)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
// don't do anything if we're not capturing
|
||
|
if(!data->m_capturing)
|
||
|
return 0;
|
||
|
|
||
|
// no call listed in the Sony documentation, so just return 1
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
GVBool gviPS3HeadsetHandleMicAttach(GVIPS3HeadsetData *data)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
// start with the default audio device
|
||
|
result = cellMicOpenEx(data->m_deviceNum, GVI_PLAYBACK_SAMPLE_RATE, 1,
|
||
|
GV_SAMPLES_PER_SECOND, GVI_PS3_MIC_BUFFER_MS, CELLMIC_SIGTYPE_DSP);
|
||
|
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
data->m_captureMicOpen = GVTrue;
|
||
|
result = cellMicStart(data->m_deviceNum);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
result = cellMicReset(data->m_deviceNum);
|
||
|
if (result != CELL_OK)
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// processes the captured frame
|
||
|
static void gviProcessCapturedFrame(GVDevice device, GVSample *frameIn, GVByte* frameOut, GVScalar *volume, GVBool *threshold)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
GVScalar frameVolume;
|
||
|
|
||
|
// get the volume if requested
|
||
|
if(volume)
|
||
|
{
|
||
|
frameVolume = gviGetSamplesVolume(frameIn, GVISamplesPerFrame);
|
||
|
if(frameVolume > *volume)
|
||
|
*volume = frameVolume;
|
||
|
}
|
||
|
|
||
|
// check against the threshold
|
||
|
if(threshold && !*threshold)
|
||
|
{
|
||
|
if(volume)
|
||
|
{
|
||
|
// we already got the volume, so use that to check
|
||
|
*threshold = (*volume >= data->m_captureThreshold);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// we didn't get a volume, so check the samples directly
|
||
|
*threshold = gviIsOverThreshold(frameIn, GVISamplesPerFrame, data->m_captureThreshold);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// filter
|
||
|
if(device->m_captureFilterCallback)
|
||
|
device->m_captureFilterCallback(device, frameIn, data->m_captureClock);
|
||
|
|
||
|
// increment the capture clock
|
||
|
data->m_captureClock++;
|
||
|
|
||
|
// encode the buffer into the packet
|
||
|
gviEncode(frameOut, frameIn);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// captures a packet
|
||
|
static GVBool gviPS3HeadsetCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
GVBool overThreshold;
|
||
|
int result;
|
||
|
int numFrames;
|
||
|
int readSize;
|
||
|
int lenAvailable;
|
||
|
int framesAvailable;
|
||
|
GVByte * frameOut;
|
||
|
float *frameIn;
|
||
|
int aCaptureQueueMsg;
|
||
|
int aDeviceIndex;
|
||
|
int sample;
|
||
|
int localtalk;
|
||
|
// figure out how many encoded bytes they can handle
|
||
|
lenAvailable = *len;
|
||
|
|
||
|
// clear the len and volume
|
||
|
*len = 0;
|
||
|
if(volume)
|
||
|
*volume = 0;
|
||
|
|
||
|
// don't do anything if we're not capturing
|
||
|
if(!data->m_capturing)
|
||
|
return GVFalse;
|
||
|
|
||
|
// set the frameStamp
|
||
|
*frameStamp = data->m_captureClock;
|
||
|
|
||
|
// figure out how many frames they can handle
|
||
|
framesAvailable = (lenAvailable / GVIEncodedFrameSize);
|
||
|
overThreshold = GVFalse;
|
||
|
|
||
|
frameOut = packet;
|
||
|
//frameIn = data->m_capturePreConvertBuffer;
|
||
|
// handle the data one frame at a time
|
||
|
for(numFrames = 0 ; numFrames < framesAvailable ; numFrames++)
|
||
|
{
|
||
|
// Wait up to 1 us before checking if the mike is attached
|
||
|
result = sys_event_queue_receive(data->m_captureCallbackQueue,
|
||
|
&data->m_captureCallbackEvent, 1);
|
||
|
if(result == ETIMEDOUT)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
aCaptureQueueMsg = (int)data->m_captureCallbackEvent.data1;
|
||
|
aDeviceIndex = (int)data->m_captureCallbackEvent.data2;
|
||
|
if (aDeviceIndex != data->m_deviceNum)
|
||
|
continue;
|
||
|
|
||
|
if (aCaptureQueueMsg == CELLMIC_ATTACH)
|
||
|
{
|
||
|
if (!gviPS3HeadsetHandleMicAttach(data))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (aCaptureQueueMsg == CELLMIC_DETACH)
|
||
|
{
|
||
|
gviDeviceUnplugged(device);
|
||
|
return GVFalse;
|
||
|
}
|
||
|
else if (aCaptureQueueMsg == CELLMIC_DATA)
|
||
|
{
|
||
|
// read this frame
|
||
|
//readSize = (GVIBytesPerFrame - data->m_captureBufferBytes);
|
||
|
readSize = ((GVISamplesPerFrame - data->m_capturePreConvertBufferLen) * sizeof(float));
|
||
|
frameIn = data->m_capturePreConvertBuffer + data->m_capturePreConvertBufferLen;
|
||
|
readSize = cellMicRead(data->m_deviceNum, frameIn, readSize);
|
||
|
|
||
|
cellMicGetSignalState(0, CELLMIC_SIGSTATE_LOCTALK, &localtalk);
|
||
|
if (localtalk < (int)(GVI_LOCAL_TALK_MAX * data->m_captureThreshold))
|
||
|
{
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
if (readSize == CELL_MICIN_ERROR_DEVICE_NOT_FOUND)
|
||
|
{
|
||
|
gviDeviceUnplugged(device);
|
||
|
return GVFalse;
|
||
|
}
|
||
|
|
||
|
data->m_capturePreConvertBufferLen += (readSize / sizeof(float));
|
||
|
if(data->m_capturePreConvertBufferLen < GVISamplesPerFrame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// convert the data from 32 bit Big Endian Floats [-1.0,1.0]
|
||
|
// to 16 bit short and write the values into the buffer
|
||
|
for (sample = 0; sample < GVISamplesPerFrame; sample++)
|
||
|
{
|
||
|
data->m_captureBuffer[sample] = (GVSample)((SHRT_MAX)*data->m_capturePreConvertBuffer[sample]);
|
||
|
}
|
||
|
|
||
|
// process the frame
|
||
|
gviProcessCapturedFrame(device, data->m_captureBuffer, frameOut, volume, &overThreshold);
|
||
|
|
||
|
// we got a full frame, so there's no leftover
|
||
|
data->m_captureBufferBytes = 0;
|
||
|
|
||
|
// update the frame pointer
|
||
|
frameOut += GVIEncodedFrameSize;
|
||
|
|
||
|
data->m_capturePreConvertBufferLen = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check if this packet crossed the threshold
|
||
|
if(overThreshold)
|
||
|
{
|
||
|
// store the time we crossed it
|
||
|
data->m_captureLastCrossedThresholdTime = data->m_captureClock;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// check if we are still on the overhang from a previous crossing
|
||
|
overThreshold = ((GVFrameStamp)(*frameStamp - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES);
|
||
|
}
|
||
|
|
||
|
// set the len
|
||
|
*len = (numFrames * GVIEncodedFrameSize);
|
||
|
|
||
|
// return false if we didn't get a packet
|
||
|
if(!overThreshold || (*len == 0))
|
||
|
return GVFalse;
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// sends the packet to the mixer
|
||
|
static void gviPS3HeadsetPlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
// don't do anything if we're not playing
|
||
|
if(!data->m_playing)
|
||
|
return;
|
||
|
|
||
|
//add it
|
||
|
gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// checks to see if we're talking
|
||
|
static GVBool gviPS3HeadsetIsSourceTalking(GVDevice device, GVSource source)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
// don't do anything if we're not playing
|
||
|
if(!data->m_playing)
|
||
|
return GVFalse;
|
||
|
|
||
|
return gviIsSourceTalking(data->m_playbackSources, source);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// lists the talking sources
|
||
|
static int gviPS3HeadsetListTalkingSources(GVDevice device, GVSource sources[], int maxSources)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
|
||
|
// don't do anything if we're not playing
|
||
|
if(!data->m_playing)
|
||
|
return GVFalse;
|
||
|
|
||
|
return gviListTalkingSources(data->m_playbackSources, sources, maxSources);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// initializes the device
|
||
|
static GVBool gviPS3HeadsetInitDevice(GVIDevice * device, int deviceIndex, GVDeviceType type)
|
||
|
{
|
||
|
GVIPS3HeadsetData * data;
|
||
|
|
||
|
// get a pointer to the data
|
||
|
data = (GVIPS3HeadsetData *)device->m_data;
|
||
|
data->m_deviceNum = deviceIndex;
|
||
|
|
||
|
// handle playback specific stuff
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
// create the array of sources
|
||
|
data->m_playbackSources = gviNewSourceList();
|
||
|
if(!data->m_playbackSources)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// allocate the buffer to hold one frame
|
||
|
data->m_playbackBuffer = (GVSample *)gsimemalign(16, (unsigned int)(GVIBytesPerFrame));
|
||
|
if(!data->m_playbackBuffer)
|
||
|
{
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (!gviPS3HeadsetInitHeadphone(data))
|
||
|
{
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
gsifree(data->m_playbackBuffer);
|
||
|
gviPS3HeadsetCloseHeadphone(data);
|
||
|
return NULL;
|
||
|
}
|
||
|
data->m_playbackVolume = 1.0;
|
||
|
}
|
||
|
|
||
|
// handle capture specific stuff
|
||
|
if(type & GV_CAPTURE)
|
||
|
{
|
||
|
// set some data vars
|
||
|
data->m_captureClock = 0;
|
||
|
data->m_captureVolume = 1.0;
|
||
|
data->m_capturePreConvertBufferLen = 0;
|
||
|
|
||
|
data->m_captureLastCrossedThresholdTime = (GVFrameStamp)(data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1);
|
||
|
|
||
|
// allocate the buffer
|
||
|
data->m_captureBuffer = (GVSample *)gsimemalign(16, (unsigned int)(GVIBytesPerFrame));
|
||
|
if(!data->m_captureBuffer)
|
||
|
{
|
||
|
// Need to free any resources in data for playback
|
||
|
// Also library needs to close audio port and mic
|
||
|
// The library still needs to remain
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
gsifree(data->m_playbackBuffer);
|
||
|
gviPS3HeadsetCloseHeadphone(data);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
data->m_capturePreConvertBuffer = (float *)gsimemalign(16,(unsigned int)(GVISamplesPerFrame * sizeof(float)));
|
||
|
if(!data->m_capturePreConvertBuffer)
|
||
|
{
|
||
|
// Need to free any resources in data for playback
|
||
|
// Also library needs to close audio port and mic
|
||
|
// The library still needs to remain
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
gsifree(data->m_playbackBuffer);
|
||
|
gviPS3HeadsetCloseHeadphone(data);
|
||
|
}
|
||
|
|
||
|
// Still need to free capture buffer
|
||
|
gsifree(data->m_captureBuffer);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!gviPS3HeadsetInitMic(data))
|
||
|
{
|
||
|
// Need to free any resources in data for playback
|
||
|
// Also library needs to close audio port and mic
|
||
|
// The library still needs to remain
|
||
|
if(type & GV_PLAYBACK)
|
||
|
{
|
||
|
gviFreeSourceList(data->m_playbackSources);
|
||
|
gsifree(data->m_playbackBuffer);
|
||
|
gviPS3HeadsetCloseHeadphone(data);
|
||
|
}
|
||
|
gviPS3HeadsetCloseMic(data);
|
||
|
gsifree(data->m_captureBuffer);
|
||
|
gsifree(data->m_capturePreConvertBuffer);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return GVTrue;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// initializes a new device
|
||
|
GVDevice gviPS3HeadsetNewDevice(GVDeviceID deviceID, GVDeviceType type)
|
||
|
{
|
||
|
GVIDevice * device;
|
||
|
GVBool result;
|
||
|
|
||
|
// check for no type
|
||
|
if(!(type & GV_CAPTURE_AND_PLAYBACK))
|
||
|
return NULL;
|
||
|
|
||
|
// check if the device already exists
|
||
|
if(gviFindDeviceByID(deviceID))
|
||
|
return NULL;
|
||
|
|
||
|
// create a new device
|
||
|
device = gviNewDevice(deviceID, GVHardwarePS3Headset, type, sizeof(GVIPS3HeadsetData));
|
||
|
if(!device)
|
||
|
return NULL;
|
||
|
|
||
|
// init the device
|
||
|
result = gviPS3HeadsetInitDevice(device, deviceID, type);
|
||
|
if(result == GVFalse)
|
||
|
{
|
||
|
gviFreeDevice(device);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// store the pointers
|
||
|
device->m_methods.m_freeDevice = gviPS3HeadsetFreeDevice;
|
||
|
device->m_methods.m_startDevice = gviPS3HeadsetStartDevice;
|
||
|
device->m_methods.m_stopDevice = gviPS3HeadsetStopDevice;
|
||
|
device->m_methods.m_isDeviceStarted = gviPS3HeadsetIsDeviceStarted;
|
||
|
device->m_methods.m_setDeviceVolume = gviPS3HeadsetSetDeviceVolume;
|
||
|
device->m_methods.m_getDeviceVolume = gviPS3HeadsetGetDeviceVolume;
|
||
|
device->m_methods.m_setCaptureThreshold = gviPS3HeadsetSetCaptureThreshold;
|
||
|
device->m_methods.m_getCaptureThreshold = gviPS3HeadsetGetCaptureThreshold;
|
||
|
device->m_methods.m_getAvailableCaptureBytes = gviPS3HeadsetGetAvailableCaptureBytes;
|
||
|
device->m_methods.m_capturePacket = gviPS3HeadsetCapturePacket;
|
||
|
device->m_methods.m_playPacket = gviPS3HeadsetPlayPacket;
|
||
|
device->m_methods.m_isSourceTalking = gviPS3HeadsetIsSourceTalking;
|
||
|
device->m_methods.m_listTalkingSources = gviPS3HeadsetListTalkingSources;
|
||
|
|
||
|
// add it to the list
|
||
|
gviAppendDeviceToList(GVIDevices, device);
|
||
|
return device;
|
||
|
}
|
||
|
|
||
|
#endif //!defined(GV_NO_PS3_HEADSET)
|