|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tfilepath.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tsound.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tsound_io.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tsop.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tthread.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "texception.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tsystem.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <iostream></iostream>
|
|
Toshihiro Shimizu |
890ddd |
#include <linux soundcard.h=""></linux>
|
|
Toshihiro Shimizu |
890ddd |
#include <set></set>
|
|
Toshihiro Shimizu |
890ddd |
#include <sys time.h=""></sys>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include <unistd.h></unistd.h>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include <fcntl.h></fcntl.h>
|
|
Toshihiro Shimizu |
890ddd |
#include <sys ioctl.h=""></sys>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//using namespace std;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//forward declaration
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int openMixer();
|
|
Toshihiro Shimizu |
890ddd |
int getCurrentRecordSource(int mixer);
|
|
Toshihiro Shimizu |
890ddd |
bool writeVolume(int volume, int mixer, int indexDev);
|
|
Toshihiro Shimizu |
890ddd |
bool selectInputDevice(TSoundInputDevice::Source dev);
|
|
Toshihiro Shimizu |
890ddd |
string parseError(int error);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// bisogna interagire con /dev/dsp per il settaggio delle
|
|
Toshihiro Shimizu |
890ddd |
// caratteristiche della traccia tipo bit, rate, canali e
|
|
Toshihiro Shimizu |
890ddd |
// per effettuare lettura/scrittura ossia record/play
|
|
Toshihiro Shimizu |
890ddd |
//
|
|
Toshihiro Shimizu |
890ddd |
// mentre bisogna interagire con /dev/mixer per modificare
|
|
Toshihiro Shimizu |
890ddd |
// i valori del volume e per selezionare il dispositivo da
|
|
Toshihiro Shimizu |
890ddd |
// cui registrare e ascoltare
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class SmartWatch
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
struct timeval m_start_tv;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 m_totalus;
|
|
Toshihiro Shimizu |
890ddd |
bool m_stopped;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
SmartWatch() : m_totalus(0), m_stopped(true)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
timerclear(&m_start_tv);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
void start()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_stopped = false;
|
|
Toshihiro Shimizu |
890ddd |
gettimeofday(&m_start_tv, 0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
void stop()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
struct timeval tv;
|
|
Toshihiro Shimizu |
890ddd |
gettimeofday(&tv, 0);
|
|
Toshihiro Shimizu |
890ddd |
m_totalus = (tv.tv_sec - m_start_tv.tv_sec) * 1000000 + (tv.tv_usec - m_start_tv.tv_usec);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
double getTotalTime()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!m_stopped) //questa e' una porcata!
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
stop();
|
|
Toshihiro Shimizu |
890ddd |
m_stopped = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return m_totalus / 1000.;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void addDelay(double ms)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_start_tv.tv_usec += (long)(ms * 1000.);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
// CLASSI PER IL PLAYBACK
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
class TSoundOutputDeviceImp
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Toshihiro Shimizu |
890ddd |
static int m_count;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
int m_dev;
|
|
Toshihiro Shimizu |
890ddd |
bool m_stopped;
|
|
Toshihiro Shimizu |
890ddd |
bool m_isPlaying;
|
|
Toshihiro Shimizu |
890ddd |
bool m_looped;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat m_currentFormat;
|
|
Toshihiro Shimizu |
890ddd |
std::set<int> m_supportedRate;</int>
|
|
Toshihiro Shimizu |
890ddd |
static std::multimap<tuint32, tsoundtrackformat=""> m_supportFormats;</tuint32,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
typedef pair<tsoundtrackp, bool=""> WaitPair;</tsoundtrackp,>
|
|
Toshihiro Shimizu |
890ddd |
vector<waitpair> m_waitingTracks;</waitpair>
|
|
Toshihiro Shimizu |
890ddd |
std::set<tsoundoutputdevicelistener *=""> m_listeners;</tsoundoutputdevicelistener>
|
|
Toshihiro Shimizu |
890ddd |
TThread::Executor m_executor;
|
|
Toshihiro Shimizu |
890ddd |
TThread::Mutex m_mutex;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDeviceImp()
|
|
Toshihiro Shimizu |
890ddd |
: m_dev(-1), m_stopped(false), m_isPlaying(false), m_looped(false), m_supportedRate()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
if (m_count != 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TException("unable to create second instance of TSoundOutputDeviceImp");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
++m_count;
|
|
Toshihiro Shimizu |
890ddd |
checkSupportedFormat();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TSoundOutputDeviceImp() { --m_count; };
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
bool doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
bool verifyRate();
|
|
Toshihiro Shimizu |
890ddd |
void insertAllRate();
|
|
Toshihiro Shimizu |
890ddd |
void checkSupportedFormat();
|
|
Toshihiro Shimizu |
890ddd |
bool isSupportFormat(const TSoundTrackFormat &fmt);
|
|
Toshihiro Shimizu |
890ddd |
void setFormat(const TSoundTrackFormat &fmt);
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int TSoundOutputDeviceImp::m_count = 0;
|
|
Toshihiro Shimizu |
890ddd |
std::multimap<tuint32, tsoundtrackformat=""> TSoundOutputDeviceImp::m_supportFormats;</tuint32,>
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::doOpenDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev >= 0)
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
m_dev = open("/dev/dsp", O_WRONLY, 0);
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev < 0) {
|
|
Toshihiro Shimizu |
890ddd |
string errMsg = strerror(errno);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp"
|
|
Toshihiro Shimizu |
890ddd |
/*"Unable to open device /dev/dsp; check permissions"*/);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//le chiamate a questa ioctl sono state commentate perche' pag 36 doc OSS
|
|
Toshihiro Shimizu |
890ddd |
//"this ioctl stop the device immadiately and returns it to a state where it
|
|
Toshihiro Shimizu |
890ddd |
//can accept new parameters. It Should not be called after opening the device
|
|
Toshihiro Shimizu |
890ddd |
//as it may cause unwanted side effect in his situation. require to abort play
|
|
Toshihiro Shimizu |
890ddd |
//or secord.Generally recommended to open and close device after using the RESET"
|
|
Toshihiro Shimizu |
890ddd |
//ioctl(m_dev, SNDCTL_DSP_RESET,0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// N.B. e' bene che la dimensione sia piccola cosi' l'attesa, in seguito
|
|
Toshihiro Shimizu |
890ddd |
// alla richiesta di stop,
|
|
Toshihiro Shimizu |
890ddd |
// e' minore in questo caso vogliamo 32 frammenti ognuno di 256 byte
|
|
Toshihiro Shimizu |
890ddd |
// Se non chiamata questa ioctl il device la calcola per conto suo
|
|
Toshihiro Shimizu |
890ddd |
// ma alcune volte la dimensione dei frammenti potrebbe essere eccessiva e
|
|
Toshihiro Shimizu |
890ddd |
// creare dei click e dei silenzi in attesi ad esempio nel playback dentro
|
|
Toshihiro Shimizu |
890ddd |
// zcomp, quindi e' meglio settarla. 32 rappresenta il numero di frammenti
|
|
Toshihiro Shimizu |
890ddd |
// di solito e' documentato che 2 siano sufficienti ma potrebbero essere pochi
|
|
Toshihiro Shimizu |
890ddd |
// soprattutto se si interagisce con altre console
|
|
Toshihiro Shimizu |
890ddd |
//int fraginfo = ( 32<<16)|8;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fraginfo = 0xffffffff;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SETFRAGMENT, &fraginfo) == -1)
|
|
Toshihiro Shimizu |
890ddd |
perror("SETFRAGMENT");
|
|
Toshihiro Shimizu |
890ddd |
//if(fraginfo != ((32<<16)|8))
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << std::hex << fraginfo<
|
|
Toshihiro Shimizu |
890ddd |
//exit(0);
|
|
Toshihiro Shimizu |
890ddd |
audio_buf_info info;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1)
|
|
Toshihiro Shimizu |
890ddd |
perror("GETOSPACE");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << info.fragments << " frammenti " << " da " << info.fragsize << " = " << info.fragsize*info.fragments << " bytes" <
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::doCloseDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev < 0)
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_dev, SNDCTL_DSP_POST, 0);
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_dev, SNDCTL_DSP_RESET, 0);
|
|
Toshihiro Shimizu |
890ddd |
int tmpDev = m_dev;
|
|
Toshihiro Shimizu |
890ddd |
bool not_closed = (close(m_dev) < 0);
|
|
Toshihiro Shimizu |
890ddd |
if (not_closed) {
|
|
Toshihiro Shimizu |
890ddd |
while (true) {
|
|
Toshihiro Shimizu |
890ddd |
m_dev = tmpDev;
|
|
Toshihiro Shimizu |
890ddd |
perror("non chiude il device :");
|
|
Toshihiro Shimizu |
890ddd |
not_closed = (close(m_dev) < 0);
|
|
Toshihiro Shimizu |
890ddd |
if (!not_closed)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_dev, SNDCTL_DSP_RESET, 0);
|
|
Toshihiro Shimizu |
890ddd |
m_dev = -1;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDeviceImp::insertAllRate()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(8000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(11025);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(16000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(22050);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(32000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(44100);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(48000);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::verifyRate()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::set<int>::iterator it;</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (it = m_supportedRate.begin();
|
|
Toshihiro Shimizu |
890ddd |
it != m_supportedRate.end(); ++it) {
|
|
Toshihiro Shimizu |
890ddd |
int sampleRate = *it;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified sample rate aaaa");
|
|
Toshihiro Shimizu |
890ddd |
if (sampleRate != *it)
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.erase(*it);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (m_supportedRate.end() == m_supportedRate.begin())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDeviceImp::checkSupportedFormat()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!m_supportFormats.empty())
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
int test_formats[] = {
|
|
Toshihiro Shimizu |
890ddd |
AFMT_U8,
|
|
Toshihiro Shimizu |
890ddd |
AFMT_S8,
|
|
Toshihiro Shimizu |
890ddd |
AFMT_S16_LE,
|
|
Toshihiro Shimizu |
890ddd |
AFMT_S16_BE,
|
|
Toshihiro Shimizu |
890ddd |
/* // servono per supportare traccie a 24 e 32 bit ma non compaiono in
|
|
Toshihiro Shimizu |
890ddd |
// nessun file linux/soundcard.h in distribuzione sulle macchine che abbiamo
|
|
Toshihiro Shimizu |
890ddd |
// il che fa pensare che non sono supportati ancora
|
|
Toshihiro Shimizu |
890ddd |
AFMT_S32_LE,
|
|
Toshihiro Shimizu |
890ddd |
AFMT_S32_BE,
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
0};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int test_channels[] = {
|
|
Toshihiro Shimizu |
890ddd |
1,
|
|
Toshihiro Shimizu |
890ddd |
2,
|
|
Toshihiro Shimizu |
890ddd |
0};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 test_sample_rates[] = {
|
|
Toshihiro Shimizu |
890ddd |
8000,
|
|
Toshihiro Shimizu |
890ddd |
11025,
|
|
Toshihiro Shimizu |
890ddd |
16000,
|
|
Toshihiro Shimizu |
890ddd |
22050,
|
|
Toshihiro Shimizu |
890ddd |
32000,
|
|
Toshihiro Shimizu |
890ddd |
44100,
|
|
Toshihiro Shimizu |
890ddd |
48000,
|
|
Toshihiro Shimizu |
890ddd |
0};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Open the device nonblocking, so the open call returns immediately.
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev)
|
|
Toshihiro Shimizu |
890ddd |
if ((m_dev = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
m_dev = -1;
|
|
Toshihiro Shimizu |
890ddd |
string errMsg = strerror(errno);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp\n: impossible check supported formats");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int mask;
|
|
Toshihiro Shimizu |
890ddd |
// Querying hardware supported formats.
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_GETFMTS, &mask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"Getting supported formats failed.");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; test_formats[i] != 0; i++) {
|
|
Toshihiro Shimizu |
890ddd |
// Test all the formats in test_formats which are supported by the hardware.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (mask & test_formats[i]) {
|
|
Toshihiro Shimizu |
890ddd |
// Test the format only if it is supported by the hardware.
|
|
Toshihiro Shimizu |
890ddd |
// Note: We also could test formats that are not supported by the hardware.
|
|
Toshihiro Shimizu |
890ddd |
// In some cases there exist OSS software converter, so that some formats
|
|
Toshihiro Shimizu |
890ddd |
// work but are not reported by the above SNDCTL_DSP_GETFMTS.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fmt = test_formats[i];
|
|
Toshihiro Shimizu |
890ddd |
// Try to set the format...
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SETFMT, &fmt) == -1)
|
|
Toshihiro Shimizu |
890ddd |
continue; //gli altri formati potrebbero essere supportati
|
|
Toshihiro Shimizu |
890ddd |
else {
|
|
Toshihiro Shimizu |
890ddd |
// and always check the variable after doing an ioctl!
|
|
Toshihiro Shimizu |
890ddd |
if (fmt == test_formats[i]) {
|
|
Toshihiro Shimizu |
890ddd |
// Test the supported channel numbers for this format.
|
|
Toshihiro Shimizu |
890ddd |
// Note: If you need a channel that is not tested here, simply add it to
|
|
Toshihiro Shimizu |
890ddd |
// the definition of the array test_channels in this file.
|
|
Toshihiro Shimizu |
890ddd |
for (int j = 0; test_channels[j] != 0; j++) {
|
|
Toshihiro Shimizu |
890ddd |
int test_channel = test_channels[j];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Try to set the channel number.
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_CHANNELS, &test_channel) == -1)
|
|
Toshihiro Shimizu |
890ddd |
continue; //altri canali potrebbero essere supportati
|
|
Toshihiro Shimizu |
890ddd |
else {
|
|
Toshihiro Shimizu |
890ddd |
if (test_channel == test_channels[j]) {
|
|
Toshihiro Shimizu |
890ddd |
// Last step: Test the supported sample rates for the current channel number
|
|
Toshihiro Shimizu |
890ddd |
// and format.
|
|
Toshihiro Shimizu |
890ddd |
// Note: If you need a sample rate that is not tested here, simply add it to
|
|
Toshihiro Shimizu |
890ddd |
// the definition of the array test_sample_rates in this file.
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; test_sample_rates[k] != 0; k++) {
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 test_rate = test_sample_rates[k];
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SPEED, &test_rate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
continue; //altri rates ppotrebbero essere supportati
|
|
Toshihiro Shimizu |
890ddd |
else {
|
|
Toshihiro Shimizu |
890ddd |
bool sign = true;
|
|
Toshihiro Shimizu |
890ddd |
int bits;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (fmt == AFMT_U8 || fmt == AFMT_S8) {
|
|
Toshihiro Shimizu |
890ddd |
bits = 8;
|
|
Toshihiro Shimizu |
890ddd |
if (fmt == AFMT_U8)
|
|
Toshihiro Shimizu |
890ddd |
sign = false;
|
|
Toshihiro Shimizu |
890ddd |
} else if (fmt == AFMT_S16_LE || fmt == AFMT_S16_BE)
|
|
Toshihiro Shimizu |
890ddd |
bits = 16;
|
|
Toshihiro Shimizu |
890ddd |
/*// vedi commento alla variabile test_formats
|
|
Toshihiro Shimizu |
890ddd |
else if(fmt == AFMT_S32_LE || fmt == AFMT_S32_BE)
|
|
Toshihiro Shimizu |
890ddd |
bits = 24;
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
// Add it to the format in the input property.
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << test_rate << " " <
|
|
Toshihiro Shimizu |
890ddd |
m_supportFormats.insert(std::make_pair(test_rate, TSoundTrackFormat(test_rate, bits, test_channel, sign)));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} // loop over the test_sample_rates
|
|
Toshihiro Shimizu |
890ddd |
} // channel set correctly ?
|
|
Toshihiro Shimizu |
890ddd |
} // ioctl for sample rate worked ?
|
|
Toshihiro Shimizu |
890ddd |
} // loop over the test_channels
|
|
Toshihiro Shimizu |
890ddd |
} // channel set correctly ?
|
|
Toshihiro Shimizu |
890ddd |
} // ioctl for channel worked ?
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// After testing all configurations for one format, the device is closed and reopened.
|
|
Toshihiro Shimizu |
890ddd |
// This is necessary to configure it to another format in a secure way.
|
|
Toshihiro Shimizu |
890ddd |
if (close(m_dev) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableCloseDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Problem to close the output device checking formats");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
} else if ((m_dev = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
m_dev = -1;
|
|
Toshihiro Shimizu |
890ddd |
string errMsg = strerror(errno);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp\n: impossible check supported formats");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} // format set correctly ?
|
|
Toshihiro Shimizu |
890ddd |
} // loop over the test_formats
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Close the device to make it forget the last format configurations.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (close(m_dev) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableCloseDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Problem to close the output device checking formats");
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
m_dev = -1;
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "FINITO " << m_supportFormats.size()<< std::endl;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::isSupportFormat(const TSoundTrackFormat &fmt)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (m_supportFormats.empty())
|
|
Toshihiro Shimizu |
890ddd |
checkSupportedFormat();
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::multimap<tuint32, tsoundtrackformat="">::iterator it;</tuint32,>
|
|
Toshihiro Shimizu |
890ddd |
pair<std::multimap<tuint32, tsoundtrackformat="">::iterator, std::multimap<tuint32, tsoundtrackformat="">::iterator> findRange;</tuint32,></std::multimap<tuint32,>
|
|
Toshihiro Shimizu |
890ddd |
findRange = m_supportFormats.equal_range(fmt.m_sampleRate);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
it = findRange.first;
|
|
Toshihiro Shimizu |
890ddd |
for (; it != findRange.second; ++it) {
|
|
Toshihiro Shimizu |
890ddd |
assert(it->first == fmt.m_sampleRate);
|
|
Toshihiro Shimizu |
890ddd |
if (it->second == fmt) {
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDeviceImp::setFormat(const TSoundTrackFormat &fmt)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int bps, ch, status;
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 sampleRate;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ch = fmt.m_channelCount;
|
|
Toshihiro Shimizu |
890ddd |
sampleRate = fmt.m_sampleRate;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev == -1)
|
|
Toshihiro Shimizu |
890ddd |
if (!doOpenDevice())
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (fmt.m_bitPerSample == 8) {
|
|
Toshihiro Shimizu |
890ddd |
if (fmt.m_signedSample)
|
|
Toshihiro Shimizu |
890ddd |
bps = AFMT_S8;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
bps = AFMT_U8;
|
|
Toshihiro Shimizu |
890ddd |
} else if (fmt.m_bitPerSample == 16) {
|
|
Toshihiro Shimizu |
890ddd |
bps = AFMT_S16_NE;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int bitPerSample = bps;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_dev, SNDCTL_DSP_SETFMT, &bps);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of bits");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_dev, SNDCTL_DSP_CHANNELS, &ch);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of channel");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified sample rate");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ch != fmt.m_channelCount || bps != bitPerSample || sampleRate != fmt.m_sampleRate) {
|
|
Toshihiro Shimizu |
890ddd |
doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
m_currentFormat = TSoundTrackFormat();
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_currentFormat = fmt;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TPlayTask : public TThread::Runnable
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
SmartWatch *m_stopWatch;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDeviceImp *m_devImp;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP m_sndtrack;
|
|
Toshihiro Shimizu |
890ddd |
static int m_skipBytes;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPlayTask(TSoundOutputDeviceImp *devImp, const TSoundTrackP &st);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TPlayTask() { delete m_stopWatch; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void run();
|
|
Toshihiro Shimizu |
890ddd |
void run2();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPlayTask::TPlayTask(TSoundOutputDeviceImp *devImp, const TSoundTrackP &st)
|
|
Toshihiro Shimizu |
890ddd |
: Runnable(), m_stopWatch(new SmartWatch), m_devImp(devImp), m_sndtrack(st)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (st->getFormat() != m_devImp->m_currentFormat)
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->doCloseDevice())
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->setFormat(st->getFormat());
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPlayTask::run()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
char *buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
int done = 0;
|
|
Toshihiro Shimizu |
890ddd |
int written = 0;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 sampleSize = (TINT32)m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
const double msToBytes = sampleSize * m_sndtrack->getSampleRate() / 1000.;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::milestone();
|
|
Toshihiro Shimizu |
890ddd |
double startupDelay = m_stopWatch->getTotalTime();
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "ritardo iniziale " << startupDelay << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
int miss = 0;
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start(); //e' meglio ignorare il ritardo iniziale
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / sampleSize) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int auxbuffersize = 0;
|
|
Toshihiro Shimizu |
890ddd |
int preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
int bytesToSkipNext;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP src = TSoundTrack::create(m_sndtrack->getFormat(), 1);
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP dst = src;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP newSrc = src;
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
do //gia' tracce accodate
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool changeSnd = false;
|
|
Toshihiro Shimizu |
890ddd |
do //c'e' il flag loop settato
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
while ((bytesLeft > 0)) {
|
|
Toshihiro Shimizu |
890ddd |
TThread::milestone();
|
|
Toshihiro Shimizu |
890ddd |
changeSnd = false;
|
|
Toshihiro Shimizu |
890ddd |
audio_buf_info info;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 bytesToWrite = 0;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 bytesToWriteNext = 0;
|
|
Toshihiro Shimizu |
890ddd |
double samplesDone = done / (double)sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
double trackTime = (samplesDone * 1000.) / m_sndtrack->getSampleRate();
|
|
Toshihiro Shimizu |
890ddd |
double curTime = m_stopWatch->getTotalTime();
|
|
Toshihiro Shimizu |
890ddd |
double delta = curTime - trackTime;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
delta
|
|
Toshihiro Shimizu |
890ddd |
== 0 sync
|
|
Toshihiro Shimizu |
890ddd |
< 0 audio piu' veloce del tempo di playback --> simuliamo un ritardo con un continue;
|
|
Toshihiro Shimizu |
890ddd |
> 0 audio piu' lento del playback -> skip una porzione di audio
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const double minDelay = -10;
|
|
Toshihiro Shimizu |
890ddd |
const double maxDelay = 0;
|
|
Toshihiro Shimizu |
890ddd |
//if (delta>maxDelay)
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "buffer underrun:" << delta << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "buffer " << (delta<mindelay?"overrun":delta>maxDelay?"underrun":"sync") << " " << delta<< std::endl;</mindelay?"overrun":delta>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (delta < minDelay) //overrun
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "out of sync -> audio troppo veloce" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
miss++;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fragmentsFree_bytes = info.fragsize * info.fragments;
|
|
Toshihiro Shimizu |
890ddd |
if (fragmentsFree_bytes == 0) {
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "no bytes left on device" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int bytesToSkip = 0;
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkipNext = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (delta > maxDelay) //underrun
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "out of sync -> audio troppo lento"<
|
|
Toshihiro Shimizu |
890ddd |
//skip di una porzione... delta in ms
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = tceil(delta * msToBytes); //numero di bytes da skippare
|
|
Toshihiro Shimizu |
890ddd |
//lo arrotondo al sample size
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip += sampleSize - (bytesToSkip % sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "bytes skippati "<< bytesToSkip << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
} else { //sto fra minDelay e maxDelay
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkipNext = bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = tmin(bytesLeft, bytesToSkip);
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkipNext -= bytesToSkip; //se !=0 => la corrente traccia non basta per avere il sync
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft -= bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
done += bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bytesToWrite = tmin(bytesLeft, fragmentsFree_bytes);
|
|
Toshihiro Shimizu |
890ddd |
bytesToWriteNext = fragmentsFree_bytes - bytesToWrite;
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToWrite >= 0);
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToWriteNext >= 0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToWrite % info.fragsize != 0) { //cerco di gestire il write di un frammento non intero
|
|
Toshihiro Shimizu |
890ddd |
auxbuffersize = ((bytesToWrite / info.fragsize) + 1) * info.fragsize;
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
auxbuffersize = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------write
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToSkipNext == 0) //la corrente traccia basta per lo skip
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 0 " << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
dst = m_sndtrack->extract(done / sampleSize, (done + bytesToWrite) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToSkip != 0) {
|
|
Toshihiro Shimizu |
890ddd |
//costruisco traccia su cui fare il crossfade
|
|
Toshihiro Shimizu |
890ddd |
//utilizzo il contenuto della traccia di crossfade
|
|
Toshihiro Shimizu |
890ddd |
dst = TSop::crossFade(0.2, src, dst);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
char *auxbuf = new char[fragmentsFree_bytes];
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf, (char *)dst->getRawData(), bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToWriteNext != 0) {
|
|
Toshihiro Shimizu |
890ddd |
int offset = bytesToWrite;
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_looped) {
|
|
Toshihiro Shimizu |
890ddd |
offset += bytesToWriteNext;
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = bytesToWriteNext;
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + offset, buf, preWrittenBytes);
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize, preWrittenBytes / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 1" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
while (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
int count = st->getSampleCount() * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToWriteNext >= count) {
|
|
Toshihiro Shimizu |
890ddd |
char *buffer = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + offset, buffer, count);
|
|
Toshihiro Shimizu |
890ddd |
bytesToWriteNext -= count;
|
|
Toshihiro Shimizu |
890ddd |
offset += count;
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 2" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks[0].second) {
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(count / sampleSize, count / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 3" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(count / sampleSize, count / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = bytesToWriteNext;
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + offset, buf, bytesToWriteNext);
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract((bytesToWriteNext) / sampleSize, (bytesToWriteNext) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 4" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} //end while
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (fragmentsFree_bytes > offset) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 5" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
int val = m_sndtrack->isSampleSigned() ? 0 : 127;
|
|
Toshihiro Shimizu |
890ddd |
memset(auxbuf + offset, val, fragmentsFree_bytes - offset); // ci metto silenzio
|
|
Toshihiro Shimizu |
890ddd |
newSrc = TSoundTrack::create(m_sndtrack->getFormat(), 1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, auxbuf, fragmentsFree_bytes);
|
|
Toshihiro Shimizu |
890ddd |
delete[] auxbuf;
|
|
Toshihiro Shimizu |
890ddd |
} else //devo skippare anche parte di una delle seguenti
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 6a" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToWriteNext > 0);
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToWriteNext == fragmentsFree_bytes - bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToWrite == 0);
|
|
Toshihiro Shimizu |
890ddd |
assert(bytesToSkip != 0);
|
|
Toshihiro Shimizu |
890ddd |
char *auxbuf = new char[fragmentsFree_bytes];
|
|
Toshihiro Shimizu |
890ddd |
//memcpy(auxbuf, buf+done, bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
//TSoundTrackP subCross = m_sndtrack->extract((done+bytesToWrite)/sampleSize, (done+bytesToWrite)/sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
//togli quelle da skippare
|
|
Toshihiro Shimizu |
890ddd |
int backupSkipNext = bytesToSkipNext;
|
|
Toshihiro Shimizu |
890ddd |
while (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
int count = st->getSampleCount() * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToSkipNext >= count) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 6b" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkipNext -= count;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 7" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//scrivi byteWriteNext fai crossfade e cerca quella successiva
|
|
Toshihiro Shimizu |
890ddd |
//con cui riempire
|
|
Toshihiro Shimizu |
890ddd |
TINT32 displacement = 0; //deve essere in munero di campioni non bytes
|
|
Toshihiro Shimizu |
890ddd |
dst = TSoundTrack::create(m_sndtrack->getFormat(), (fragmentsFree_bytes - bytesToWrite) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
int count = m_sndtrack->getSampleCount() * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
if (count >= bytesToSkipNext + bytesToWriteNext) //la traccia trovata e' suff sia per skippare che per scrivere
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = bytesToSkipNext + bytesToWriteNext;
|
|
Toshihiro Shimizu |
890ddd |
dst = m_sndtrack->extract(bytesToSkipNext / sampleSize, preWrittenBytes / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize, preWrittenBytes / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
} else //non e' suff per scrivere
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(m_sndtrack->extract(bytesToSkipNext / sampleSize, m_sndtrack->getSampleCount() - 1), 0);
|
|
Toshihiro Shimizu |
890ddd |
displacement = m_sndtrack->getSampleCount() - bytesToSkipNext / sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
bytesToWriteNext -= displacement * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
while (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
int count = st->getSampleCount() * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToWriteNext >= count) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 8" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(st, displacement);
|
|
Toshihiro Shimizu |
890ddd |
bytesToWriteNext -= count;
|
|
Toshihiro Shimizu |
890ddd |
displacement += count;
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks[0].second) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 9" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(count / sampleSize, count / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(count / sampleSize, count / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 10" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(st->extract(0L, bytesToWriteNext / sampleSize), displacement);
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = bytesToWriteNext;
|
|
Toshihiro Shimizu |
890ddd |
done = preWrittenBytes;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = m_sndtrack->getSampleCount() * sampleSize - done;
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize, preWrittenBytes / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkipNext = backupSkipNext;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = TSop::crossFade(0.2, src, dst);
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + bytesToWrite, (char *)st->getRawData(), fragmentsFree_bytes - bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//devo ricercare quella giusta che non deve essere skippata
|
|
Toshihiro Shimizu |
890ddd |
//ma sostitutita come traccia corrente
|
|
Toshihiro Shimizu |
890ddd |
//devo fare un cross fade
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, auxbuf, fragmentsFree_bytes);
|
|
Toshihiro Shimizu |
890ddd |
delete[] auxbuf;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//----------- end write
|
|
Toshihiro Shimizu |
890ddd |
src = newSrc;
|
|
Toshihiro Shimizu |
890ddd |
if (written == -1)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
std::cout << written << " " << (bytesToWrite + preWrittenBytes) << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
if (written != bytesToWrite + preWrittenBytes)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " update done 2" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft -= written;
|
|
Toshihiro Shimizu |
890ddd |
done += written;
|
|
Toshihiro Shimizu |
890ddd |
} //chiudo il while((bytesLeft > 0))
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " QUI 11" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
done = preWrittenBytes + bytesToSkipNext;
|
|
Toshihiro Shimizu |
890ddd |
written = 0;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = m_sndtrack->getSampleCount() * sampleSize - done;
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start();
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
} while (m_devImp->m_looped || changeSnd);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks.empty())
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
done = 0;
|
|
Toshihiro Shimizu |
890ddd |
written = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start(); //ignoro il ritardo iniziale
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} while (true); //ci sono gia' tracce accodate
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_executor.addTask(new TPlayTask(m_devImp, m_devImp->m_waitingTracks[0].first));
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
//std::cout<<"OPS ..... erase 4"<
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_devImp->m_dev != -1) {
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SYNC) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "unable to sync! " << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
throw TException("unable to sync!");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "miss = " << miss << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (TThread::Interrupt &e) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "Play interrupted " << e.getMessage() << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
} catch (TException &e) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "esco dal play " << e.getMessage() << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPlayTask::run2()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
char *buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
int done = 0;
|
|
Toshihiro Shimizu |
890ddd |
int written = 0;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 sampleSize = (TINT32)m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
const double msToBytes = sampleSize * m_sndtrack->getSampleRate() / 1000.;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::milestone();
|
|
Toshihiro Shimizu |
890ddd |
double startupDelay = m_stopWatch->getTotalTime();
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "ritardo iniziale " << startupDelay << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
int miss = 0;
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start(); //e' meglio ignorare il ritardo iniziale
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / sampleSize) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int auxbuffersize = 0;
|
|
Toshihiro Shimizu |
890ddd |
int preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP src = TSoundTrack::create(m_sndtrack->getFormat(), 1);
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP dst = src;
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
do //gia' tracce accodate
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool changeSnd = false;
|
|
Toshihiro Shimizu |
890ddd |
do //c'e' il flag loop settato
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
while ((bytesLeft > 0)) {
|
|
Toshihiro Shimizu |
890ddd |
changeSnd = false;
|
|
Toshihiro Shimizu |
890ddd |
TThread::milestone();
|
|
Toshihiro Shimizu |
890ddd |
audio_buf_info info;
|
|
Toshihiro Shimizu |
890ddd |
TINT32 bytesToWrite;
|
|
Toshihiro Shimizu |
890ddd |
double samplesDone = done / (double)sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
double trackTime = (samplesDone * 1000.) / m_sndtrack->getSampleRate();
|
|
Toshihiro Shimizu |
890ddd |
double curTime = m_stopWatch->getTotalTime();
|
|
Toshihiro Shimizu |
890ddd |
double delta = curTime - trackTime;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
delta
|
|
Toshihiro Shimizu |
890ddd |
== 0 sync
|
|
Toshihiro Shimizu |
890ddd |
< 0 audio piu' veloce del tempo di playback --> simuliamo un ritardo con un continue;
|
|
Toshihiro Shimizu |
890ddd |
> 0 audio piu' lento del playback -> skip una porzione di audio
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const double minDelay = -10;
|
|
Toshihiro Shimizu |
890ddd |
const double maxDelay = 0;
|
|
Toshihiro Shimizu |
890ddd |
//if (delta>maxDelay)
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "buffer underrun:" << delta << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "buffer " << (delta<mindelay?"overrun":delta>maxDelay?"underrun":"sync") << " " << delta<< std::endl;</mindelay?"overrun":delta>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (delta < minDelay) //overrun
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "out of sync -> audio troppo veloce" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
miss++;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fragmentsFree_bytes = info.fragsize * info.fragments;
|
|
Toshihiro Shimizu |
890ddd |
if (fragmentsFree_bytes == 0) {
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "no bytes left on device" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int bytesToSkip = 0;
|
|
Toshihiro Shimizu |
890ddd |
int bigSkip = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (delta > maxDelay) //underrun
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "out of sync -> audio troppo lento"<
|
|
Toshihiro Shimizu |
890ddd |
//skip di una porzione... delta in ms
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = tceil(delta * msToBytes); //numero di bytes da skippare
|
|
Toshihiro Shimizu |
890ddd |
//lo arrotondo al sample size
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip += sampleSize - (bytesToSkip % sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "bytes skippati "<< bytesToSkip << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
bigSkip = bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
} else { //sto fra minDelay e maxDelay
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bytesToSkip = tmin(bytesLeft, bytesToSkip);
|
|
Toshihiro Shimizu |
890ddd |
bigSkip -= bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft -= bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
done += bytesToSkip;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bytesToWrite = tmin(bytesLeft, fragmentsFree_bytes);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToWrite % info.fragsize != 0) { //cerco di gestire il write di un frammento non intero
|
|
Toshihiro Shimizu |
890ddd |
auxbuffersize = ((bytesToWrite / info.fragsize) + 1) * info.fragsize;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (bigSkip)
|
|
Toshihiro Shimizu |
890ddd |
while (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
int count = st->getSampleCount() * sampleSize;
|
|
Toshihiro Shimizu |
890ddd |
if (bigSkip >= count) {
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
bigSkip -= count;
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (auxbuffersize == 0) {
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToSkip != 0) {
|
|
Toshihiro Shimizu |
890ddd |
//costruisco traccia su cui fare il crossfade
|
|
Toshihiro Shimizu |
890ddd |
//utilizzo il contenuto della traccia di crossfade
|
|
Toshihiro Shimizu |
890ddd |
dst = m_sndtrack->extract(done / sampleSize, (done + bytesToWrite) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = TSop::crossFade(0.2, src, dst);
|
|
Toshihiro Shimizu |
890ddd |
char *buffer = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, buffer, bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, buf + done, bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
src = m_sndtrack->extract((done + bytesToWrite) / sampleSize, (done + bytesToWrite) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
} else { //auxbuffersize != 0 sse il numero di bytes residui nella traccia e' inferiore alla dimensione del frammento
|
|
Toshihiro Shimizu |
890ddd |
char *auxbuf = new char[auxbuffersize];
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP newSrc;
|
|
Toshihiro Shimizu |
890ddd |
dst = TSoundTrack::create(m_sndtrack->getFormat(), auxbuffersize / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf, buf + done, bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(m_sndtrack->extract(done / sampleSize, (done + bytesToWrite) / sampleSize), 0);
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = auxbuffersize - bytesToWrite;
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_looped) {
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + bytesToWrite, buf, preWrittenBytes);
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(m_sndtrack->extract(0, preWrittenBytes / sampleSize), bytesToWrite / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize, preWrittenBytes / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
newSrc = TSoundTrack::create(m_sndtrack->getFormat(), 1);
|
|
Toshihiro Shimizu |
890ddd |
static int added = 0;
|
|
Toshihiro Shimizu |
890ddd |
//se non c'e' alcuna altra traccia o e di diverso format
|
|
Toshihiro Shimizu |
890ddd |
//riempo il frammento con del silenzio
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks.empty() ||
|
|
Toshihiro Shimizu |
890ddd |
(m_sndtrack->getFormat() != m_devImp->m_waitingTracks[0].first->getFormat())) {
|
|
Toshihiro Shimizu |
890ddd |
int val = m_sndtrack->isSampleSigned() ? 0 : 127;
|
|
Toshihiro Shimizu |
890ddd |
memset(auxbuf + bytesToWrite, val, preWrittenBytes); // ci metto silenzio
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
while (true) //ci sono altre tracce accodate
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
int sampleBytes = st->getSampleCount() * st->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
if (sampleBytes >= preWrittenBytes - added) {
|
|
Toshihiro Shimizu |
890ddd |
//La traccia ha abbastanza campioni per riempire il frammento
|
|
Toshihiro Shimizu |
890ddd |
//quindi la sostituisco alla corrente del runnable e continuo
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + bytesToWrite, buf, preWrittenBytes - added);
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
changeSnd = true;
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(m_sndtrack->extract(0, (preWrittenBytes - added) / sampleSize), bytesToWrite / sampleSize + added);
|
|
Toshihiro Shimizu |
890ddd |
newSrc = m_sndtrack->extract((preWrittenBytes - added) / sampleSize, (preWrittenBytes - added) / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
} else { //occhio al loop
|
|
Toshihiro Shimizu |
890ddd |
//La traccia successiva e' piu corta del frammento da riempire quindi
|
|
Toshihiro Shimizu |
890ddd |
//ce la metto tutta e se non ha il flag di loop settato cerco di aggiungere
|
|
Toshihiro Shimizu |
890ddd |
//i byte della successiva
|
|
Toshihiro Shimizu |
890ddd |
memcpy(auxbuf + bytesToWrite, st->getRawData(), sampleBytes);
|
|
Toshihiro Shimizu |
890ddd |
dst->copy(st->extract(0, st->getSampleCount() - 1), bytesToWrite / sampleSize);
|
|
Toshihiro Shimizu |
890ddd |
added += st->getSampleCount();
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks[0].second) //e' quella che deve essere in loop
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = st;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
preWrittenBytes = 0;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = 0;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
changeSnd = true;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//la elimino e vedo se esiste la successiva altrimenti metto campioni "zero"
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
if (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
st = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
std::cout << " Traccia con meno campioni cerco la successiva" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
int val = m_sndtrack->isSampleSigned() ? 0 : 127;
|
|
Toshihiro Shimizu |
890ddd |
memset(auxbuf + bytesToWrite, val, preWrittenBytes - sampleBytes); // ci metto silenzio
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "OPS ..... silence" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} //end while(true)
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//qui andrebbe fatto un cross-fade se c'erano da skippare campioni => bytesToSkip != 0
|
|
Toshihiro Shimizu |
890ddd |
if (bytesToSkip != 0) {
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st = TSop::crossFade(0.2, src, dst);
|
|
Toshihiro Shimizu |
890ddd |
char *buffer = (char *)st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, buffer, bytesToWrite);
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
written = write(m_devImp->m_dev, auxbuf, auxbuffersize);
|
|
Toshihiro Shimizu |
890ddd |
src = newSrc;
|
|
Toshihiro Shimizu |
890ddd |
auxbuffersize = 0;
|
|
Toshihiro Shimizu |
890ddd |
delete[] auxbuf;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (written == -1)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
if (written != bytesToWrite + preWrittenBytes)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft -= written;
|
|
Toshihiro Shimizu |
890ddd |
done += written;
|
|
Toshihiro Shimizu |
890ddd |
} //chiudo il while((bytesLeft > 0))
|
|
Toshihiro Shimizu |
890ddd |
done = preWrittenBytes;
|
|
Toshihiro Shimizu |
890ddd |
written = 0;
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize() - done;
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start();
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} while (m_devImp->m_looped || changeSnd);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
//std::cout<<"OPS ..... non accodato"<
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//std::cout<<"OPS ..... accodato"<
|
|
Toshihiro Shimizu |
890ddd |
m_sndtrack = m_devImp->m_waitingTracks[0].first;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
buf = (char *)m_sndtrack->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
done = 0;
|
|
Toshihiro Shimizu |
890ddd |
written = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->start(); //ignoro il ritardo iniziale
|
|
Toshihiro Shimizu |
890ddd |
if (done > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) / double(m_sndtrack->getSampleRate()));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} while (true); //ci sono gia' tracce accodate
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_devImp->m_waitingTracks.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_executor.addTask(new TPlayTask(m_devImp, m_devImp->m_waitingTracks[0].first));
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
|
|
Toshihiro Shimizu |
890ddd |
//std::cout<<"OPS ..... erase 4"<
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_devImp->m_dev != -1) {
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SYNC) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "unable to sync! " << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
throw TException("unable to sync!");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//std::cout << "miss = " << miss << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (TThread::Interrupt &e) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "Play interrupted " << e.getMessage() << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
} catch (TException &e) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "esco dal play " << e.getMessage() << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->doOpenDevice()) {
|
|
Toshihiro Shimizu |
890ddd |
m_imp->insertAllRate();
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->verifyRate())
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"No default samplerate are supported");
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDevice::~TSoundOutputDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
close();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::installed()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool ret = false;
|
|
Toshihiro Shimizu |
890ddd |
int dev = ::open("/dev/dsp", O_WRONLY, 0);
|
|
Toshihiro Shimizu |
890ddd |
if (dev >= 0) {
|
|
Toshihiro Shimizu |
890ddd |
ret = true;
|
|
Toshihiro Shimizu |
890ddd |
::close(dev);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return ret;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::open(const TSoundTrackP &st)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_currentFormat = st->getFormat();
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::close()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
stop();
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev != -1) {
|
|
Toshihiro Shimizu |
890ddd |
bool closed = m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
if (!closed)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableCloseDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Error during the closing of the output device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::attach(TSoundOutputDeviceListener *listener)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_listeners.insert(listener);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::detach(TSoundOutputDeviceListener *listener)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_listeners.erase(listener);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert((scrubbing && !loop) || !scrubbing);
|
|
Toshihiro Shimizu |
890ddd |
if (!st->getSampleCount())
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_imp->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_looped)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::Busy,
|
|
Toshihiro Shimizu |
890ddd |
"Unable to queue another playback when the sound player is looping");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat format = st->getFormat();
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->isSupportFormat(format)) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"Unsupported format for playback");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_isPlaying) {
|
|
Toshihiro Shimizu |
890ddd |
assert(s1 >= s0);
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP subTrack = st->extract(s0, s1);
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_waitingTracks.push_back(std::make_pair(subTrack, loop));
|
|
Toshihiro Shimizu |
890ddd |
//std::cout<<"Sono in pushback"<
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if ((m_imp->m_dev == -1))
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->doOpenDevice())
|
|
Toshihiro Shimizu |
890ddd |
m_imp->setFormat(format);
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_isPlaying = true;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_stopped = false;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_looped = loop;
|
|
Toshihiro Shimizu |
890ddd |
//m_imp->m_currentFormat = st->getFormat();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(s1 >= s0);
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP subTrack = st->extract(s0, s1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_executor.addTask(new TPlayTask(m_imp, subTrack));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::stop()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_imp->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->m_isPlaying)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_executor.cancel();
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_imp->m_dev, SNDCTL_DSP_POST, 0);
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_stopped = true;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_looped = false;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_waitingTracks.clear();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
double TSoundOutputDevice::getVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't open the mixer device");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int devmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int recmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int stereo;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int outmask = devmask | ~recmask;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int index;
|
|
Toshihiro Shimizu |
890ddd |
if (outmask & (1 << SOUND_MIXER_ALTPCM))
|
|
Toshihiro Shimizu |
890ddd |
index = SOUND_MIXER_ALTPCM;
|
|
Toshihiro Shimizu |
890ddd |
else if (outmask & (1 << SOUND_MIXER_PCM))
|
|
Toshihiro Shimizu |
890ddd |
index = SOUND_MIXER_PCM;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int level;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, MIXER_READ(index), &level) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Error to read the volume");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
int left = level & 0xff;
|
|
Toshihiro Shimizu |
890ddd |
int right = ((level & 0xff00) >> 8);
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return (left + right) / 20.0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return (level & 0xff) / 10.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::setVolume(double volume)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't open the mixer device");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int devmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int recmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &recmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int stereo;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int outmask = devmask | ~recmask;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (outmask & (1 << SOUND_MIXER_ALTPCM)) {
|
|
Toshihiro Shimizu |
890ddd |
int vol, index = SOUND_MIXER_ALTPCM;
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
volume *= 10.0;
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)volume + ((int)(volume * 256.0));
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)(volume * 10.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(vol, mixer, index)) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Can't write the volume");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// metto anche l'altro ad un livello di sensibilita' adeguata
|
|
Toshihiro Shimizu |
890ddd |
if (outmask & (1 << SOUND_MIXER_PCM)) {
|
|
Toshihiro Shimizu |
890ddd |
int vol, index = SOUND_MIXER_PCM;
|
|
Toshihiro Shimizu |
890ddd |
double volDefault = 6.7;
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
volDefault *= 10.0;
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)volDefault + ((int)(volDefault * 256.0));
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)(volDefault * 10.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(vol, mixer, index)) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Can't write the volume");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else if (outmask & (1 << SOUND_MIXER_PCM)) {
|
|
Toshihiro Shimizu |
890ddd |
int vol, index = SOUND_MIXER_PCM;
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
volume *= 10.0;
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)volume + ((int)(volume * 256.0));
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)(volume * 10.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(vol, mixer, index)) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't write the volume");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::isPlaying() const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_imp->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_isPlaying;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::isLooping()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_imp->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_looped;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::setLooping(bool loop)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(m_imp->m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_looped = loop;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::supportsVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't open the mixer device");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int devmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int recmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &recmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int stereo;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Error in ioctl with mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int outmask = devmask | ~recmask;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if ((outmask & (1 << SOUND_MIXER_ALTPCM)) || (outmask & (1 << SOUND_MIXER_PCM))) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 sampleRate, int channelCount, int bitPerSample)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt;
|
|
Toshihiro Shimizu |
890ddd |
if (bitPerSample == 8)
|
|
Toshihiro Shimizu |
890ddd |
fmt = TSoundTrackFormat(sampleRate, channelCount, bitPerSample, false);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
fmt = TSoundTrackFormat(sampleRate, channelCount, bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->isSupportFormat(fmt))
|
|
Toshihiro Shimizu |
890ddd |
return fmt;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int bps, ch, status;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bps = bitPerSample;
|
|
Toshihiro Shimizu |
890ddd |
ch = channelCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev == -1)
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (bitPerSample <= 8) {
|
|
Toshihiro Shimizu |
890ddd |
bitPerSample = AFMT_U8;
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_signedSample = false;
|
|
Toshihiro Shimizu |
890ddd |
} else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) {
|
|
Toshihiro Shimizu |
890ddd |
bitPerSample = AFMT_S16_NE;
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_signedSample = true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_imp->m_dev, SNDCTL_DSP_SETFMT, &bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1) {
|
|
Toshihiro Shimizu |
890ddd |
perror("CHE palle ");
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of bits");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_bitPerSample = bitPerSample;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_imp->m_dev, SNDCTL_DSP_CHANNELS, &channelCount);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of channel");
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_channelCount = channelCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_supportedRate.find((int)sampleRate) == m_imp->m_supportedRate.end()) {
|
|
Toshihiro Shimizu |
890ddd |
std::set<int>::iterator it = m_imp->m_supportedRate.lower_bound((int)sampleRate);</int>
|
|
Toshihiro Shimizu |
890ddd |
if (it == m_imp->m_supportedRate.end()) {
|
|
Toshihiro Shimizu |
890ddd |
it = std::max_element(m_imp->m_supportedRate.begin(),
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_supportedRate.end());
|
|
Toshihiro Shimizu |
890ddd |
if (it != m_imp->m_supportedRate.end())
|
|
Toshihiro Shimizu |
890ddd |
sampleRate = *(m_imp->m_supportedRate.rbegin());
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"There isn't a supported rate");
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
sampleRate = *it;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_imp->m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified sample rate");
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_sampleRate = sampleRate;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ch != channelCount || bps != bitPerSample) {
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return fmt;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
const TSoundTrackFormat &format)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
return getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
format.m_sampleRate, format.m_channelCount, format.m_bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
// CLASSI PER IL RECORD
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TSoundInputDeviceImp
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
int m_dev;
|
|
Toshihiro Shimizu |
890ddd |
bool m_stopped;
|
|
Toshihiro Shimizu |
890ddd |
bool m_isRecording;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat m_currentFormat;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP m_st;
|
|
Toshihiro Shimizu |
890ddd |
std::set<int> m_supportedRate;</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TINT32 m_recordedSampleCount;
|
|
Toshihiro Shimizu |
890ddd |
vector<char *=""> m_recordedBlocks;</char>
|
|
Toshihiro Shimizu |
890ddd |
vector<int> m_samplePerBlocks;</int>
|
|
Toshihiro Shimizu |
890ddd |
bool m_oneShotRecording;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::Executor m_executor;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDeviceImp()
|
|
Toshihiro Shimizu |
890ddd |
: m_dev(-1), m_stopped(false), m_isRecording(false), m_st(0), m_supportedRate(), m_recordedBlocks(), m_samplePerBlocks(), m_oneShotRecording(false)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TSoundInputDeviceImp() {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool doOpenDevice(const TSoundTrackFormat &format,
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::Source devType);
|
|
Toshihiro Shimizu |
890ddd |
bool doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
void insertAllRate();
|
|
Toshihiro Shimizu |
890ddd |
bool verifyRate();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDeviceImp::doOpenDevice(const TSoundTrackFormat &format,
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::Source devType)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_dev = open("/dev/dsp", O_RDONLY);
|
|
Toshihiro Shimizu |
890ddd |
if (m_dev < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Cannot open the dsp device");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//ioctl(m_dev, SNDCTL_DSP_RESET,0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDeviceImp::doCloseDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (close(m_dev) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableCloseDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Cannot close the dsp device");
|
|
Toshihiro Shimizu |
890ddd |
m_dev = -1;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundInputDeviceImp::insertAllRate()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(8000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(11025);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(16000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(22050);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(32000);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(44100);
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.insert(48000);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDeviceImp::verifyRate()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::set<int>::iterator it;</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (it = m_supportedRate.begin();
|
|
Toshihiro Shimizu |
890ddd |
it != m_supportedRate.end(); ++it) {
|
|
Toshihiro Shimizu |
890ddd |
int sampleRate = *it;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified sample rate");
|
|
Toshihiro Shimizu |
890ddd |
if (sampleRate != *it)
|
|
Toshihiro Shimizu |
890ddd |
m_supportedRate.erase(*it);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (m_supportedRate.end() == m_supportedRate.begin())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TRecordTask : public TThread::Runnable
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDeviceImp *m_devImp;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRecordTask(TSoundInputDeviceImp *devImp)
|
|
Toshihiro Shimizu |
890ddd |
: Runnable(), m_devImp(devImp){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TRecordTask(){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void run();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TRecordTask::run()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// N.B. e' bene che la dimensione sia piccola cosi' l'attesa perche' termini
|
|
Toshihiro Shimizu |
890ddd |
// e' minore in questo caso vogliamo 16 frammenti ognuno di 4096 byte
|
|
Toshihiro Shimizu |
890ddd |
int fraginfo = (16 << 16) | 12;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SETFRAGMENT, &fraginfo) == -1)
|
|
Toshihiro Shimizu |
890ddd |
perror("SETFRAGMENT");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fragsize = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETBLKSIZE, &fragsize) == -1)
|
|
Toshihiro Shimizu |
890ddd |
perror("GETFRAGMENT");
|
|
Toshihiro Shimizu |
890ddd |
TINT32 byteRecordedSample = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_devImp->m_oneShotRecording) {
|
|
Toshihiro Shimizu |
890ddd |
TINT32 byteToSample = m_devImp->m_st->getSampleSize() * m_devImp->m_st->getSampleCount();
|
|
Toshihiro Shimizu |
890ddd |
char *buf = (char *)m_devImp->m_st->getRawData();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while ((byteRecordedSample < byteToSample) && m_devImp->m_isRecording) {
|
|
Toshihiro Shimizu |
890ddd |
int sample;
|
|
Toshihiro Shimizu |
890ddd |
if (fragsize > (byteToSample - byteRecordedSample))
|
|
Toshihiro Shimizu |
890ddd |
sample = byteToSample - byteRecordedSample;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
sample = fragsize;
|
|
Toshihiro Shimizu |
890ddd |
int nread = read(m_devImp->m_dev, buf + byteRecordedSample, sample);
|
|
Toshihiro Shimizu |
890ddd |
if (nread == -1)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
if (nread != sample)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
byteRecordedSample += nread;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
int bytePerSample = m_devImp->m_currentFormat.m_bitPerSample >> 3;
|
|
Toshihiro Shimizu |
890ddd |
switch (bytePerSample) {
|
|
Toshihiro Shimizu |
890ddd |
case 3:
|
|
Toshihiro Shimizu |
890ddd |
bytePerSample++;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
default:
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
bytePerSample *= m_devImp->m_currentFormat.m_channelCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (m_devImp->m_isRecording) {
|
|
Toshihiro Shimizu |
890ddd |
char *dataBuffer = new char[fragsize];
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_recordedBlocks.push_back(dataBuffer);
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_samplePerBlocks.push_back(fragsize);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int nread = read(m_devImp->m_dev, dataBuffer, fragsize);
|
|
Toshihiro Shimizu |
890ddd |
if (nread == -1)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
if (nread != fragsize)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_devImp->m_recordedSampleCount += (fragsize / bytePerSample);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_devImp->m_dev, SNDCTL_DSP_RESET, 0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::TSoundInputDevice() : m_imp(new TSoundInputDeviceImp)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_dev = open("/dev/dsp", O_RDONLY);
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Cannot open the dsp device");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->insertAllRate();
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->verifyRate())
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"No default samplerate are supported");
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::~TSoundInputDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev != -1)
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
delete m_imp;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::installed()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool ret = false;
|
|
Toshihiro Shimizu |
890ddd |
int dev = ::open("/dev/dsp", O_RDONLY);
|
|
Toshihiro Shimizu |
890ddd |
if (dev >= 0) {
|
|
Toshihiro Shimizu |
890ddd |
ret = true;
|
|
Toshihiro Shimizu |
890ddd |
::close(dev);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return ret;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundInputDevice::record(const TSoundTrackFormat &format, TSoundInputDevice::Source type)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedBlocks.clear();
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_samplePerBlocks.clear();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//registra creando una nuova traccia
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_oneShotRecording = false;
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev == -1)
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doOpenDevice(format, type);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!selectInputDevice(type))
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableSetDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Input device is not supported for recording");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt = getPreferredFormat(format);
|
|
Toshihiro Shimizu |
890ddd |
if (fmt != format)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"Unsupported format");
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (getVolume() == 0.0) {
|
|
Toshihiro Shimizu |
890ddd |
double volume = 5.0;
|
|
Toshihiro Shimizu |
890ddd |
setVolume(volume);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_currentFormat = format;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_isRecording = true;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_stopped = false;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedSampleCount = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//far partire il thread
|
|
Toshihiro Shimizu |
890ddd |
/*TRecordThread *recordThread = new TRecordThread(m_imp);
|
|
Toshihiro Shimizu |
890ddd |
if (!recordThread)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Problemi per creare il thread");
|
|
Toshihiro Shimizu |
890ddd |
recordThread->start();*/
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_executor.addTask(new TRecordTask(m_imp));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundInputDevice::record(const TSoundTrackP &st, TSoundInputDevice::Source type)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedBlocks.clear();
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_samplePerBlocks.clear();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_dev == -1)
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doOpenDevice(st->getFormat(), type);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!selectInputDevice(type))
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableSetDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Input device is not supported for recording");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt = getPreferredFormat(st->getFormat());
|
|
Toshihiro Shimizu |
890ddd |
if (fmt != st->getFormat())
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"Unsupported format");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (getVolume() == 0.0) {
|
|
Toshihiro Shimizu |
890ddd |
double volume = 5.0;
|
|
Toshihiro Shimizu |
890ddd |
setVolume(volume);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Sovrascive un'intera o parte di traccia gia' esistente
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_oneShotRecording = true;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_currentFormat = st->getFormat();
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_isRecording = true;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_stopped = false;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedSampleCount = 0;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_st = st;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedBlocks.push_back((char *)st->getRawData());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//far partire il thread
|
|
Toshihiro Shimizu |
890ddd |
/*TRecordThread *recordThread = new TRecordThread(m_imp);
|
|
Toshihiro Shimizu |
890ddd |
if (!recordThread)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Problemi per creare il thread");
|
|
Toshihiro Shimizu |
890ddd |
recordThread->start();*/
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_executor.addTask(new TRecordTask(m_imp));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP TSoundInputDevice::stop()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->m_isRecording)
|
|
Toshihiro Shimizu |
890ddd |
return st;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_isRecording = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// mettere istruzioni per fermare il rec
|
|
Toshihiro Shimizu |
890ddd |
ioctl(m_imp->m_dev, SNDCTL_DSP_SYNC, 0);
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doCloseDevice();
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// attendo 1/5 di secondo
|
|
Toshihiro Shimizu |
890ddd |
usleep(200000);
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_oneShotRecording)
|
|
Toshihiro Shimizu |
890ddd |
st = m_imp->m_st;
|
|
Toshihiro Shimizu |
890ddd |
else {
|
|
Toshihiro Shimizu |
890ddd |
st = TSoundTrack::create(m_imp->m_currentFormat, m_imp->m_recordedSampleCount);
|
|
Toshihiro Shimizu |
890ddd |
TINT32 bytesCopied = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)m_imp->m_recordedBlocks.size(); ++i) {
|
|
Toshihiro Shimizu |
890ddd |
memcpy(
|
|
Toshihiro Shimizu |
890ddd |
(void *)(st->getRawData() + bytesCopied),
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_recordedBlocks[i],
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_samplePerBlocks[i]);
|
|
Toshihiro Shimizu |
890ddd |
delete[] m_imp->m_recordedBlocks[i];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bytesCopied += m_imp->m_samplePerBlocks[i];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_samplePerBlocks.clear();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return st;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double TSoundInputDevice::getVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't have the mixer");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int index;
|
|
Toshihiro Shimizu |
890ddd |
if ((index = getCurrentRecordSource(mixer)) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int stereo;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int level;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, MIXER_READ(index), &level) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Can't read the volume value");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
int left = level & 0xff;
|
|
Toshihiro Shimizu |
890ddd |
int right = ((level & 0xff00) >> 8);
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return (left + right) / 20.0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return (level & 0xff) / 10.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::setVolume(double volume)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't have the mixer");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int caps;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_CAPS, &caps) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!(caps & SOUND_CAP_EXCL_INPUT)) {
|
|
Toshihiro Shimizu |
890ddd |
int rec;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &rec) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int i;
|
|
Toshihiro Shimizu |
890ddd |
int nosound = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < 32; ++i)
|
|
Toshihiro Shimizu |
890ddd |
if (rec & (1 << i))
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(nosound, mixer, i)) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Can't set the volume value");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int index;
|
|
Toshihiro Shimizu |
890ddd |
if ((index = getCurrentRecordSource(mixer)) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int stereo;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::NoMixer,
|
|
Toshihiro Shimizu |
890ddd |
"Can't obtain information by mixer");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int vol;
|
|
Toshihiro Shimizu |
890ddd |
if ((1 << index) & stereo) {
|
|
Toshihiro Shimizu |
890ddd |
volume *= 10.0;
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)volume + ((int)(volume * 256.0));
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
vol = (int)(volume * 10.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(vol, mixer, index)) {
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableVolume,
|
|
Toshihiro Shimizu |
890ddd |
"Can't write the volume value");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::isRecording()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_isRecording;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 sampleRate, int channelCount, int bitPerSample)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt;
|
|
Toshihiro Shimizu |
890ddd |
int status;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (bitPerSample <= 8) {
|
|
Toshihiro Shimizu |
890ddd |
bitPerSample = AFMT_U8;
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_signedSample = false;
|
|
Toshihiro Shimizu |
890ddd |
} else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) {
|
|
Toshihiro Shimizu |
890ddd |
bitPerSample = AFMT_S16_NE;
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_signedSample = true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_imp->m_dev, SNDCTL_DSP_SETFMT, &bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of bits");
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_bitPerSample = bitPerSample;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
status = ioctl(m_imp->m_dev, SNDCTL_DSP_CHANNELS, &channelCount);
|
|
Toshihiro Shimizu |
890ddd |
if (status == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified number of channel");
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_channelCount = channelCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_supportedRate.find((int)sampleRate) ==
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_supportedRate.end()) {
|
|
Toshihiro Shimizu |
890ddd |
std::set<int>::iterator it =</int>
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_supportedRate.lower_bound((int)sampleRate);
|
|
Toshihiro Shimizu |
890ddd |
if (it == m_imp->m_supportedRate.end()) {
|
|
Toshihiro Shimizu |
890ddd |
it = std::max_element(m_imp->m_supportedRate.begin(),
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_supportedRate.end());
|
|
Toshihiro Shimizu |
890ddd |
if (it != m_imp->m_supportedRate.end())
|
|
Toshihiro Shimizu |
890ddd |
sampleRate = *(m_imp->m_supportedRate.rbegin());
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnsupportedFormat,
|
|
Toshihiro Shimizu |
890ddd |
"There isn't a supported rate");
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
sampleRate = *it;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(m_imp->m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnablePrepare,
|
|
Toshihiro Shimizu |
890ddd |
"Failed setting the specified sample rate");
|
|
Toshihiro Shimizu |
890ddd |
fmt.m_sampleRate = sampleRate;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return fmt;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
const TSoundTrackFormat &format)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
return getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
format.m_sampleRate, format.m_channelCount, format.m_bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
//******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// funzioni per l'interazione con la libreria OSS
|
|
Toshihiro Shimizu |
890ddd |
//******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
//******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
string parseError(int error)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
switch (error) {
|
|
Toshihiro Shimizu |
890ddd |
case EBADF:
|
|
Toshihiro Shimizu |
890ddd |
return string("Bad file descriptor");
|
|
Toshihiro Shimizu |
890ddd |
case EFAULT:
|
|
Toshihiro Shimizu |
890ddd |
return string("Pointer to/from buffer data is invalid");
|
|
Toshihiro Shimizu |
890ddd |
case EINTR:
|
|
Toshihiro Shimizu |
890ddd |
return string("Signal interrupt the signal");
|
|
Toshihiro Shimizu |
890ddd |
case EINVAL:
|
|
Toshihiro Shimizu |
890ddd |
return string("Request/arg isn't valid for this device");
|
|
Toshihiro Shimizu |
890ddd |
case EIO:
|
|
Toshihiro Shimizu |
890ddd |
return string("Some phisical I/O error has occurred");
|
|
Toshihiro Shimizu |
890ddd |
case ENOTTY:
|
|
Toshihiro Shimizu |
890ddd |
return string("Fieldes isn't associated with a device that accepts control");
|
|
Toshihiro Shimizu |
890ddd |
case ENXIO:
|
|
Toshihiro Shimizu |
890ddd |
return string("Request/arg valid, but the requested cannot be performed on this subdevice");
|
|
Toshihiro Shimizu |
890ddd |
default:
|
|
Toshihiro Shimizu |
890ddd |
return string("Unknown error");
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::Source stringToSource(string dev)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (dev == "mic")
|
|
Toshihiro Shimizu |
890ddd |
return TSoundInputDevice::Mic;
|
|
Toshihiro Shimizu |
890ddd |
else if (dev == "line")
|
|
Toshihiro Shimizu |
890ddd |
return TSoundInputDevice::LineIn;
|
|
Toshihiro Shimizu |
890ddd |
else if (dev == "cd")
|
|
Toshihiro Shimizu |
890ddd |
return TSoundInputDevice::CdAudio;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
return TSoundInputDevice::DigitalIn;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
string sourceToString(TSoundInputDevice::Source dev)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
switch (dev) {
|
|
Toshihiro Shimizu |
890ddd |
case TSoundInputDevice::Mic:
|
|
Toshihiro Shimizu |
890ddd |
return string("mic");
|
|
Toshihiro Shimizu |
890ddd |
case TSoundInputDevice::LineIn:
|
|
Toshihiro Shimizu |
890ddd |
return string("line");
|
|
Toshihiro Shimizu |
890ddd |
case TSoundInputDevice::DigitalIn:
|
|
Toshihiro Shimizu |
890ddd |
return string("digital");
|
|
Toshihiro Shimizu |
890ddd |
default:
|
|
Toshihiro Shimizu |
890ddd |
return string("cd");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int openMixer()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer = open("/dev/mixer", O_RDWR);
|
|
Toshihiro Shimizu |
890ddd |
if (mixer == -1)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
return mixer;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int getCurrentRecordSource(int mixer)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int recsrc;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
|
|
Toshihiro Shimizu |
890ddd |
return -1;
|
|
Toshihiro Shimizu |
890ddd |
int index = -1;
|
|
Toshihiro Shimizu |
890ddd |
for (index = 0; index < 32; ++index)
|
|
Toshihiro Shimizu |
890ddd |
if (recsrc & 1 << index)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
return index;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool writeVolume(int volume, int mixer, int indexDev)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, MIXER_WRITE(indexDev), &volume) == -1)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool controlEnableRecord(int mixer)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int recmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
perror("Read recmask");
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (recmask & (1 << SOUND_MIXER_IGAIN)) {
|
|
Toshihiro Shimizu |
890ddd |
int volume;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, MIXER_READ(SOUND_MIXER_IGAIN), &volume) == -1)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int app = (volume & 0xff);
|
|
Toshihiro Shimizu |
890ddd |
if (app <= 30) {
|
|
Toshihiro Shimizu |
890ddd |
volume = 80 | 80 << 8;
|
|
Toshihiro Shimizu |
890ddd |
if (!writeVolume(volume, mixer, SOUND_MIXER_IGAIN))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int isInputDeviceSupported(TSoundInputDevice::Source dev, int &mixer)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int recmask;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
perror("Read recmask");
|
|
Toshihiro Shimizu |
890ddd |
return -1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int i;
|
|
Toshihiro Shimizu |
890ddd |
string devS = sourceToString(dev);
|
|
Toshihiro Shimizu |
890ddd |
const char *deviceName[] = SOUND_DEVICE_NAMES;
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < 32; ++i) {
|
|
Toshihiro Shimizu |
890ddd |
if (!(recmask & 1 << i))
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
if (strcmp(devS.c_str(), deviceName[i]) == 0)
|
|
Toshihiro Shimizu |
890ddd |
return i;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return -1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool selectInputDevice(TSoundInputDevice::Source dev)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int mixer;
|
|
Toshihiro Shimizu |
890ddd |
if ((mixer = openMixer()) < 0) {
|
|
Toshihiro Shimizu |
890ddd |
close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return false; //throw TException("Can't open the mixer device");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int index = isInputDeviceSupported(dev, mixer);
|
|
Toshihiro Shimizu |
890ddd |
if (index == -1)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
int recsrc;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
perror("Read recsrc");
|
|
Toshihiro Shimizu |
890ddd |
close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (!(recsrc & 1 << index)) {
|
|
Toshihiro Shimizu |
890ddd |
recsrc = 1 << index;
|
|
Toshihiro Shimizu |
890ddd |
if (ioctl(mixer, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) {
|
|
Toshihiro Shimizu |
890ddd |
perror("Write recsrc");
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!controlEnableRecord(mixer)) {
|
|
Toshihiro Shimizu |
890ddd |
close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return false; //throw TException("Can't enable recording");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
::close(mixer);
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|