#include "tsound_t.h" #include "texception.h" #include "tthread.h" #include #include #include #include #include // forward declaration namespace { bool isInterfaceSupported(int deviceType, int interfaceType); bool setDefaultInput(TSoundInputDevice::Source type); bool setDefaultOutput(); bool isChangeOutput(ULONG sampleRate); } //============================================================================== class TSoundOutputDeviceImp { public: ALport m_port; bool m_stopped; bool m_isPlaying; bool m_looped; TSoundTrackFormat m_currentFormat; std::queue m_queuedSoundTracks; std::set m_supportedRate; TThread::Executor m_executor; TThread::Mutex m_mutex; TSoundOutputDeviceImp() : m_stopped(false) , m_isPlaying(false) , m_looped(false) , m_port(NULL) , m_queuedSoundTracks() , m_supportedRate(){}; ~TSoundOutputDeviceImp(){}; bool doOpenDevice(const TSoundTrackFormat &format); void insertAllRate(); bool verifyRate(); }; //----------------------------------------------------------------------------- bool TSoundOutputDeviceImp::doOpenDevice(const TSoundTrackFormat &format) { ALconfig config; ALpv pvbuf[3]; m_currentFormat = format; // AL_MONITOR_CTL fa parte dei vecchi andrebbero trovati quelli nuovi pvbuf[0].param = AL_PORT_COUNT; pvbuf[1].param = AL_MONITOR_CTL; if (alGetParams(AL_DEFAULT_OUTPUT, pvbuf, 2) < 0) if (oserror() == AL_BAD_DEVICE_ACCESS) return false; // throw TException("Could not access audio hardware."); if (!isInterfaceSupported(AL_DEFAULT_OUTPUT, AL_SPEAKER_IF_TYPE)) return false; // throw TException("Speakers are not supported"); int dev = alGetResourceByName(AL_SYSTEM, (char *)"Headphone/Speaker", AL_DEVICE_TYPE); if (!dev) return false; // throw TException("invalid device speakers"); pvbuf[0].param = AL_DEFAULT_OUTPUT; pvbuf[0].value.i = dev; alSetParams(AL_SYSTEM, pvbuf, 1); ALfixed buf[2] = {alDoubleToFixed(0), alDoubleToFixed(0)}; config = alNewConfig(); // qui devo metterci gli altoparlanti e poi setto i valori per il default // output pvbuf[0].param = AL_RATE; pvbuf[0].value.ll = alDoubleToFixed((double)format.m_sampleRate); pvbuf[1].param = AL_GAIN; pvbuf[1].value.ptr = buf; pvbuf[1].sizeIn = 8; pvbuf[2].param = AL_INTERFACE; pvbuf[2].value.i = AL_SPEAKER_IF_TYPE; if (alSetParams(AL_DEFAULT_OUTPUT, pvbuf, 3) < 0) return false; // throw TException("Unable to set params for output device"); if (alSetChannels(config, format.m_channelCount) == -1) return false; // throw TException("Error to setting audio hardware."); int bytePerSample = format.m_bitPerSample >> 3; switch (bytePerSample) { case 3: bytePerSample++; break; default: break; } if (alSetWidth(config, bytePerSample) == -1) return false; // throw TException("Error to setting audio hardware."); if (alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP) == -1) return false; // throw TException("Error to setting audio hardware."); if (alSetQueueSize(config, (TINT32)format.m_sampleRate) == -1) return false; // throw TException("Error to setting audio hardware."); m_port = alOpenPort("AudioOutput", "w", config); if (!m_port) return false; // throw TException("Could not open audio port."); alFreeConfig(config); return true; } //----------------------------------------------------------------------------- void TSoundOutputDeviceImp::insertAllRate() { m_supportedRate.insert(8000); m_supportedRate.insert(11025); m_supportedRate.insert(16000); m_supportedRate.insert(22050); m_supportedRate.insert(32000); m_supportedRate.insert(44100); m_supportedRate.insert(48000); } //----------------------------------------------------------------------------- bool TSoundOutputDeviceImp::verifyRate() { // Sample Rate ALparamInfo pinfo; int ret = alGetParamInfo(AL_DEFAULT_OUTPUT, AL_RATE, &pinfo); if (ret != -1 && pinfo.elementType == AL_FIXED_ELEM) { int min = (int)alFixedToDouble(pinfo.min.ll); int max = (int)alFixedToDouble(pinfo.max.ll); std::set::iterator it; for (it = m_supportedRate.begin(); it != m_supportedRate.end(); ++it) if (*it < min || *it > max) m_supportedRate.erase(*it); if (m_supportedRate.end() == m_supportedRate.begin()) return false; } else if (ret == AL_BAD_PARAM) return false; else return false; return true; } //============================================================================== class PlayTask : public TThread::Runnable { public: TSoundOutputDeviceImp *m_devImp; TSoundTrackP m_sndtrack; PlayTask(TSoundOutputDeviceImp *devImp, const TSoundTrackP &st) : TThread::Runnable(), m_devImp(devImp), m_sndtrack(st){}; ~PlayTask(){}; void run(); }; void PlayTask::run() { int leftToPlay = m_sndtrack->getSampleCount(); int i = 0; if (!m_devImp->m_port || (m_devImp->m_currentFormat != m_sndtrack->getFormat()) || isChangeOutput(m_sndtrack->getSampleRate())) if (!m_devImp->doOpenDevice(m_sndtrack->getFormat())) return; while ((leftToPlay > 0) && m_devImp->m_isPlaying) { int fillable = alGetFillable(m_devImp->m_port); if (!fillable) continue; if (fillable < leftToPlay) { alWriteFrames(m_devImp->m_port, (void *)(m_sndtrack->getRawData() + i), fillable); // ricorda getSampleSize restituisce m_sampleSize che comprende gia' // la moltiplicazione per il numero dei canali i += fillable * m_sndtrack->getSampleSize(); leftToPlay -= fillable; } else { alWriteFrames(m_devImp->m_port, (void *)(m_sndtrack->getRawData() + i), leftToPlay); leftToPlay = 0; } } if (!m_devImp->m_stopped) { while (ALgetfilled(m_devImp->m_port) > 0) sginap(1); { TThread::ScopedLock sl(m_devImp->m_mutex); if (!m_devImp->m_looped) m_devImp->m_queuedSoundTracks.pop(); if (m_devImp->m_queuedSoundTracks.empty()) { m_devImp->m_isPlaying = false; m_devImp->m_stopped = true; m_devImp->m_looped = false; } else { m_devImp->m_executor.addTask( new PlayTask(m_devImp, m_devImp->m_queuedSoundTracks.front())); } } } else { alDiscardFrames(m_devImp->m_port, alGetFilled(m_devImp->m_port)); while (!m_devImp->m_queuedSoundTracks.empty()) m_devImp->m_queuedSoundTracks.pop(); } } //============================================================================== TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp) { if (!setDefaultOutput()) throw TSoundDeviceException(TSoundDeviceException::UnableSetDevice, "Speaker not supported"); try { supportsVolume(); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } m_imp->insertAllRate(); } //------------------------------------------------------------------------------ TSoundOutputDevice::~TSoundOutputDevice() { close(); delete m_imp; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::installed() { if (alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, 0, 0, 0, 0) <= 0) return false; return true; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::open(const TSoundTrackP &st) { if (!m_imp->doOpenDevice(st->getFormat())) throw TSoundDeviceException( TSoundDeviceException::UnableOpenDevice, "Problem to open the output device or set some params"); return true; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::close() { stop(); if (m_imp->m_port) alClosePort(m_imp->m_port); m_imp->m_port = NULL; return true; } //------------------------------------------------------------------------------ void TSoundOutputDevice::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing) { if (!st->getSampleCount()) return; { TThread::ScopedLock sl(m_imp->m_mutex); if (m_imp->m_looped) throw TSoundDeviceException( TSoundDeviceException::Busy, "Unable to queue another playback when the sound player is looping"); m_imp->m_isPlaying = true; m_imp->m_stopped = false; m_imp->m_looped = loop; } TSoundTrackFormat fmt; try { fmt = getPreferredFormat(st->getFormat()); if (fmt != st->getFormat()) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "Unsupported Format"); } } catch (TSoundDeviceException &e) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, e.getMessage()); } assert(s1 >= s0); TSoundTrackP subTrack = st->extract(s0, s1); // far partire il thread if (m_imp->m_queuedSoundTracks.empty()) { m_imp->m_queuedSoundTracks.push(subTrack); m_imp->m_executor.addTask(new PlayTask(m_imp, subTrack)); } else m_imp->m_queuedSoundTracks.push(subTrack); } //------------------------------------------------------------------------------ void TSoundOutputDevice::stop() { if (!m_imp->m_isPlaying) return; TThread::ScopedLock sl(m_imp->m_mutex); m_imp->m_isPlaying = false; m_imp->m_stopped = true; m_imp->m_looped = false; } //------------------------------------------------------------------------------ double TSoundOutputDevice::getVolume() { ALpv pv[1]; ALfixed value[2]; try { supportsVolume(); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } pv[0].param = AL_GAIN; pv[0].value.ptr = value; pv[0].sizeIn = 8; alGetParams(AL_DEFAULT_OUTPUT, pv, 1); double val = (((alFixedToDouble(value[0]) + alFixedToDouble(value[1])) / 2.) + 60.) / 8.05; return val; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::setVolume(double volume) { ALpv pv[1]; ALfixed value[2]; try { supportsVolume(); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } double val = -60. + 8.05 * volume; value[0] = alDoubleToFixed(val); value[1] = alDoubleToFixed(val); pv[0].param = AL_GAIN; pv[0].value.ptr = value; pv[0].sizeIn = 8; if (alSetParams(AL_DEFAULT_OUTPUT, pv, 1) < 0) return false; return true; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::supportsVolume() { ALparamInfo pinfo; int ret; ret = alGetParamInfo(AL_DEFAULT_OUTPUT, AL_GAIN, &pinfo); double min = alFixedToDouble(pinfo.min.ll); double max = alFixedToDouble(pinfo.max.ll); if ((ret != -1) && (min != max) && (max != 0.0)) return true; else if ((ret == AL_BAD_PARAM) || ((min == max) && (max == 0.0))) throw TSoundDeviceException(TSoundDeviceException::UnableVolume, "It is impossible to chamge setting of volume"); else throw TSoundDeviceException(TSoundDeviceException::NoMixer, "Output device is not accessible"); } //------------------------------------------------------------------------------ bool TSoundOutputDevice::isPlaying() const { return m_imp->m_isPlaying; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::isLooping() { TThread::ScopedLock sl(m_imp->m_mutex); return m_imp->m_looped; } //------------------------------------------------------------------------------ void TSoundOutputDevice::setLooping(bool loop) { TThread::ScopedLock sl(m_imp->m_mutex); m_imp->m_looped = loop; } //------------------------------------------------------------------------------ TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(ULONG sampleRate, int channelCount, int bitPerSample) { TSoundTrackFormat fmt; int ret; if (!m_imp->verifyRate()) throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "There isn't any support rate"); if (m_imp->m_supportedRate.find((int)sampleRate) == m_imp->m_supportedRate.end()) { std::set::iterator it = m_imp->m_supportedRate.lower_bound((int)sampleRate); if (it == m_imp->m_supportedRate.end()) { it = std::max_element(m_imp->m_supportedRate.begin(), m_imp->m_supportedRate.end()); if (it != m_imp->m_supportedRate.end()) sampleRate = *(m_imp->m_supportedRate.rbegin()); else throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "There isn't a supported rate"); } else sampleRate = *it; } int value; ALvalue vals[32]; if ((ret = alQueryValues(AL_DEFAULT_OUTPUT, AL_CHANNELS, vals, 32, 0, 0)) > 0) for (int i = 0; i < ret; ++i) value = vals[i].i; else if (oserror() == AL_BAD_PARAM) throw TSoundDeviceException( TSoundDeviceException::NoMixer, "It is impossible ask for the max numbers of channels supported"); else throw TSoundDeviceException( TSoundDeviceException::NoMixer, "It is impossibile information about ouput device"); if (value > 2) value = 2; if (channelCount > value) channelCount = value; else if (channelCount <= 0) channelCount = 1; if (bitPerSample <= 8) bitPerSample = 8; else if (bitPerSample <= 16) bitPerSample = 16; else bitPerSample = 24; fmt.m_bitPerSample = bitPerSample; fmt.m_channelCount = channelCount; fmt.m_sampleRate = sampleRate; fmt.m_signedSample = true; return fmt; } //------------------------------------------------------------------------------ TSoundTrackFormat TSoundOutputDevice::getPreferredFormat( const TSoundTrackFormat &format) { try { return getPreferredFormat(format.m_sampleRate, format.m_channelCount, format.m_bitPerSample); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } } //============================================================================== //============================================================================== // REGISTRAZIONE //============================================================================== //============================================================================== class TSoundInputDeviceImp { public: ALport m_port; bool m_stopped; bool m_isRecording; bool m_oneShotRecording; TINT32 m_recordedSampleCount; vector m_recordedBlocks; vector m_samplePerBlocks; TSoundTrackFormat m_currentFormat; TSoundTrackP m_st; std::set m_supportedRate; TThread::Executor m_executor; TSoundInputDeviceImp() : m_stopped(false) , m_isRecording(false) , m_port(NULL) , m_recordedBlocks() , m_samplePerBlocks() , m_recordedSampleCount(0) , m_oneShotRecording(false) , m_st(0) , m_supportedRate(){}; ~TSoundInputDeviceImp(){}; bool doOpenDevice(const TSoundTrackFormat &format, TSoundInputDevice::Source devType); void insertAllRate(); bool verifyRate(); }; bool TSoundInputDeviceImp::doOpenDevice(const TSoundTrackFormat &format, TSoundInputDevice::Source devType) { ALconfig config; ALpv pvbuf[2]; m_currentFormat = format; // AL_MONITOR_CTL fa parte dei vecchi andrebbero trovati quelli nuovi pvbuf[0].param = AL_PORT_COUNT; pvbuf[1].param = AL_MONITOR_CTL; if (alGetParams(AL_DEFAULT_INPUT, pvbuf, 2) < 0) if (oserror() == AL_BAD_DEVICE_ACCESS) return false; // throw TException("Could not access audio hardware."); config = alNewConfig(); if (!setDefaultInput(devType)) return false; // throw TException("Could not set the input device // specified"); pvbuf[0].param = AL_RATE; pvbuf[0].value.ll = alDoubleToFixed(format.m_sampleRate); ALfixed buf[2] = {alDoubleToFixed(0), alDoubleToFixed(0)}; pvbuf[1].param = AL_GAIN; pvbuf[1].value.ptr = buf; pvbuf[1].sizeIn = 8; if (alSetParams(AL_DEFAULT_INPUT, pvbuf, 2) < 0) return false; // throw TException("Problem to set params "); if (alSetChannels(config, format.m_channelCount) == -1) return false; // throw TException("Error to setting audio hardware."); int bytePerSample = format.m_bitPerSample >> 3; switch (bytePerSample) { case 3: bytePerSample++; break; default: break; } if (alSetWidth(config, bytePerSample) == -1) return false; // throw TException("Error to setting audio hardware."); if (alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP) == -1) return false; // throw TException("Error to setting audio hardware."); if (alSetQueueSize(config, (TINT32)format.m_sampleRate) == -1) return false; // throw TException("Error to setting audio hardware."); alSetDevice(config, AL_DEFAULT_INPUT); m_port = alOpenPort("AudioInput", "r", config); if (!m_port) return false; // throw TException("Could not open audio port."); alFreeConfig(config); return true; } //----------------------------------------------------------------------------- void TSoundInputDeviceImp::insertAllRate() { m_supportedRate.insert(8000); m_supportedRate.insert(11025); m_supportedRate.insert(16000); m_supportedRate.insert(22050); m_supportedRate.insert(32000); m_supportedRate.insert(44100); m_supportedRate.insert(48000); } //----------------------------------------------------------------------------- bool TSoundInputDeviceImp::verifyRate() { // Sample Rate ALparamInfo pinfo; int ret = alGetParamInfo(AL_DEFAULT_INPUT, AL_RATE, &pinfo); if (ret != -1 && pinfo.elementType == AL_FIXED_ELEM) { int min = (int)alFixedToDouble(pinfo.min.ll); int max = (int)alFixedToDouble(pinfo.max.ll); std::set::iterator it; for (it = m_supportedRate.begin(); it != m_supportedRate.end(); ++it) if (*it < min || *it > max) m_supportedRate.erase(*it); if (m_supportedRate.end() == m_supportedRate.begin()) return false; } else if (ret == AL_BAD_PARAM) return false; else return false; return true; } //============================================================================== class RecordTask : public TThread::Runnable { public: TSoundInputDeviceImp *m_devImp; int m_ByteToSample; RecordTask(TSoundInputDeviceImp *devImp, int numByte) : TThread::Runnable(), m_devImp(devImp), m_ByteToSample(numByte){}; ~RecordTask(){}; void run(); }; void RecordTask::run() { TINT32 byteRecordedSample = 0; int filled = alGetFilled(m_devImp->m_port); if (m_devImp->m_oneShotRecording) { char *rawData = m_devImp->m_recordedBlocks.front(); int sampleSize; if ((m_devImp->m_currentFormat.m_bitPerSample >> 3) == 3) sampleSize = 4; else sampleSize = (m_devImp->m_currentFormat.m_bitPerSample >> 3); sampleSize *= m_devImp->m_currentFormat.m_channelCount; while ((byteRecordedSample <= (m_ByteToSample - filled * sampleSize)) && m_devImp->m_isRecording) { alReadFrames(m_devImp->m_port, (void *)(rawData + byteRecordedSample), filled); byteRecordedSample += filled * sampleSize; filled = alGetFilled(m_devImp->m_port); } if (m_devImp->m_isRecording) { alReadFrames(m_devImp->m_port, (void *)(rawData + byteRecordedSample), (m_ByteToSample - byteRecordedSample) / sampleSize); while (alGetFillable(m_devImp->m_port) > 0) sginap(1); } } else { while (m_devImp->m_isRecording) { filled = alGetFilled(m_devImp->m_port); if (filled > 0) { char *dataBuffer = new char[filled * m_ByteToSample]; m_devImp->m_recordedBlocks.push_back(dataBuffer); m_devImp->m_samplePerBlocks.push_back(filled * m_ByteToSample); alReadFrames(m_devImp->m_port, (void *)dataBuffer, filled); m_devImp->m_recordedSampleCount += filled; } } while (alGetFillable(m_devImp->m_port) > 0) sginap(1); } alClosePort(m_devImp->m_port); m_devImp->m_port = 0; m_devImp->m_stopped = true; } //============================================================================== TSoundInputDevice::TSoundInputDevice() : m_imp(new TSoundInputDeviceImp) {} //------------------------------------------------------------------------------ TSoundInputDevice::~TSoundInputDevice() { if (m_imp->m_port) alClosePort(m_imp->m_port); delete m_imp; } //------------------------------------------------------------------------------ bool TSoundInputDevice::installed() { if (alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, 0, 0, 0, 0) <= 0) return false; return true; } //------------------------------------------------------------------------------ void TSoundInputDevice::record(const TSoundTrackFormat &format, TSoundInputDevice::Source type) { if (m_imp->m_isRecording == true) throw TSoundDeviceException(TSoundDeviceException::Busy, "Just another recoding is in progress"); m_imp->m_recordedBlocks.clear(); m_imp->m_samplePerBlocks.clear(); // registra creando una nuova traccia m_imp->m_oneShotRecording = false; if (!setDefaultInput(type)) throw TSoundDeviceException(TSoundDeviceException::UnableSetDevice, "Error to set the input device"); m_imp->insertAllRate(); TSoundTrackFormat fmt; try { fmt = getPreferredFormat(format); if (fmt != format) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "Unsupported Format"); } } catch (TSoundDeviceException &e) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, e.getMessage()); } if (!m_imp->m_port) m_imp->doOpenDevice(format, type); m_imp->m_currentFormat = format; m_imp->m_isRecording = true; m_imp->m_stopped = false; m_imp->m_recordedSampleCount = 0; int bytePerSample = format.m_bitPerSample >> 3; switch (bytePerSample) { case 3: bytePerSample++; break; default: break; } bytePerSample *= format.m_channelCount; // far partire il thread /*TRecordThread *recordThread = new TRecordThread(m_imp, bytePerSample); if (!recordThread) { m_imp->m_isRecording = false; m_imp->m_stopped = true; throw TSoundDeviceException( TSoundDeviceException::UnablePrepare, "Unable to create the recording thread"); } recordThread->start();*/ m_imp->m_executor.addTask(new RecordTask(m_imp, bytePerSample)); } //------------------------------------------------------------------------------ void TSoundInputDevice::record(const TSoundTrackP &st, TSoundInputDevice::Source type) { if (m_imp->m_isRecording == true) throw TSoundDeviceException(TSoundDeviceException::Busy, "Just another recoding is in progress"); m_imp->m_recordedBlocks.clear(); m_imp->m_samplePerBlocks.clear(); if (!setDefaultInput(type)) throw TSoundDeviceException(TSoundDeviceException::UnableSetDevice, "Error to set the input device"); m_imp->insertAllRate(); TSoundTrackFormat fmt; try { fmt = getPreferredFormat(st->getFormat()); if (fmt != st->getFormat()) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "Unsupported Format"); } } catch (TSoundDeviceException &e) { throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, e.getMessage()); } if (!m_imp->m_port) if (!m_imp->doOpenDevice(st->getFormat(), type)) throw TSoundDeviceException(TSoundDeviceException::UnableOpenDevice, "Unable to open input device"); // Sovrascive un'intera o parte di traccia gia' esistente m_imp->m_oneShotRecording = true; m_imp->m_currentFormat = st->getFormat(); m_imp->m_isRecording = true; m_imp->m_stopped = false; m_imp->m_recordedSampleCount = 0; m_imp->m_st = st; m_imp->m_recordedBlocks.push_back((char *)st->getRawData()); int totByteToSample = st->getSampleCount() * st->getSampleSize(); // far partire il thread /*TRecordThread *recordThread = new TRecordThread(m_imp, totByteToSample); if (!recordThread) { m_imp->m_isRecording = false; m_imp->m_stopped = true; throw TSoundDeviceException( TSoundDeviceException::UnablePrepare, "Unable to create the recording thread"); } recordThread->start();*/ m_imp->m_executor.addTask(new RecordTask(m_imp, totByteToSample)); } //------------------------------------------------------------------------------ TSoundTrackP TSoundInputDevice::stop() { TSoundTrackP st; if (!m_imp->m_isRecording) throw TSoundDeviceException(TSoundDeviceException::UnablePrepare, "No recording process is in execution"); m_imp->m_isRecording = false; alDiscardFrames(m_imp->m_port, alGetFilled(m_imp->m_port)); while (!m_imp->m_stopped) sginap(1); if (m_imp->m_oneShotRecording) st = m_imp->m_st; else { st = TSoundTrack::create(m_imp->m_currentFormat, m_imp->m_recordedSampleCount); TINT32 bytesCopied = 0; for (int i = 0; i < (int)m_imp->m_recordedBlocks.size(); ++i) { memcpy((void *)(st->getRawData() + bytesCopied), m_imp->m_recordedBlocks[i], m_imp->m_samplePerBlocks[i]); delete[] m_imp->m_recordedBlocks[i]; bytesCopied += m_imp->m_samplePerBlocks[i]; } m_imp->m_samplePerBlocks.clear(); } return st; } //------------------------------------------------------------------------------ double TSoundInputDevice::getVolume() { ALpv pv[1]; ALfixed value[2]; try { supportsVolume(); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } pv[0].param = AL_GAIN; pv[0].value.ptr = value; pv[0].sizeIn = 8; alGetParams(AL_DEFAULT_INPUT, pv, 1); double val = (((alFixedToDouble(value[0]) + alFixedToDouble(value[1])) / 2.) + 60.) / 8.05; return val; } //------------------------------------------------------------------------------ bool TSoundInputDevice::setVolume(double volume) { ALpv pv[1]; ALfixed value[2]; try { supportsVolume(); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } double val = -60. + 8.05 * volume; value[0] = alDoubleToFixed(val); value[1] = alDoubleToFixed(val); pv[0].param = AL_GAIN; pv[0].value.ptr = value; pv[0].sizeIn = 8; alSetParams(AL_DEFAULT_INPUT, pv, 1); return true; } //------------------------------------------------------------------------------ bool TSoundInputDevice::supportsVolume() { ALparamInfo pinfo; int ret; ret = alGetParamInfo(AL_DEFAULT_INPUT, AL_GAIN, &pinfo); double min = alFixedToDouble(pinfo.min.ll); double max = alFixedToDouble(pinfo.max.ll); if ((ret != -1) && (min != max) && (max != 0.0)) return true; else if ((ret == AL_BAD_PARAM) || ((min == max) && (max == 0.0))) throw TSoundDeviceException(TSoundDeviceException::UnableVolume, "It is impossible to chamge setting of volume"); else throw TSoundDeviceException(TSoundDeviceException::NoMixer, "Output device is not accessible"); } //------------------------------------------------------------------------------ TSoundTrackFormat TSoundInputDevice::getPreferredFormat(ULONG sampleRate, int channelCount, int bitPerSample) { TSoundTrackFormat fmt; int ret; if (!m_imp->verifyRate()) throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "There isn't any support rate"); if (m_imp->m_supportedRate.find((int)sampleRate) == m_imp->m_supportedRate.end()) { std::set::iterator it = m_imp->m_supportedRate.lower_bound((int)sampleRate); if (it == m_imp->m_supportedRate.end()) { it = std::max_element(m_imp->m_supportedRate.begin(), m_imp->m_supportedRate.end()); if (it != m_imp->m_supportedRate.end()) sampleRate = *(m_imp->m_supportedRate.rbegin()); else throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat, "There isn't a supported rate"); } else sampleRate = *it; } int value; ALvalue vals[32]; if ((ret = alQueryValues(AL_DEFAULT_INPUT, AL_CHANNELS, vals, 32, 0, 0)) > 0) for (int i = 0; i < ret; ++i) value = vals[i].i; else if (oserror() == AL_BAD_PARAM) throw TSoundDeviceException( TSoundDeviceException::NoMixer, "It is impossible ask for the max nembers of channels supported"); else throw TSoundDeviceException( TSoundDeviceException::NoMixer, "It is impossibile information about ouput device"); if (value > 2) value = 2; if (channelCount > value) channelCount = value; else if (channelCount <= 0) channelCount = 1; if (bitPerSample <= 8) bitPerSample = 8; else if (bitPerSample <= 16) bitPerSample = 16; else bitPerSample = 24; fmt.m_bitPerSample = bitPerSample; fmt.m_channelCount = channelCount; fmt.m_sampleRate = sampleRate; fmt.m_signedSample = true; return fmt; } //------------------------------------------------------------------------------ TSoundTrackFormat TSoundInputDevice::getPreferredFormat( const TSoundTrackFormat &format) { try { return getPreferredFormat(format.m_sampleRate, format.m_channelCount, format.m_bitPerSample); } catch (TSoundDeviceException &e) { throw TSoundDeviceException(e.getType(), e.getMessage()); } } //------------------------------------------------------------------------------ bool TSoundInputDevice::isRecording() { return m_imp->m_isRecording; } //****************************************************************************** //****************************************************************************** // funzioni per l'interazione con // la // libreria // audio //****************************************************************************** //****************************************************************************** namespace { bool isInterfaceSupported(int deviceType, int interfaceType) { ALvalue vals[16]; int devNum; if ((devNum = alQueryValues(AL_SYSTEM, deviceType, vals, 16, 0, 0)) > 0) { int i; for (i = 0; i < devNum; ++i) { ALpv quals[2]; quals[0].param = AL_TYPE; quals[0].value.i = interfaceType; if (alQueryValues(vals[i].i, AL_INTERFACE, 0, 0, quals, 1) > 0) return true; } } return false; } //------------------------------------------------------------------------------ bool setDefaultInput(TSoundInputDevice::Source type) { string label; switch (type) { case TSoundInputDevice::LineIn: label = "Line In"; break; case TSoundInputDevice::DigitalIn: label = "AES Input"; break; default: label = "Microphone"; } int dev = alGetResourceByName(AL_SYSTEM, (char *)label.c_str(), AL_DEVICE_TYPE); if (!dev) return false; // throw TException("Error to set input device"); int itf; if (itf = alGetResourceByName(AL_SYSTEM, (char *)label.c_str(), AL_INTERFACE_TYPE)) { ALpv p; p.param = AL_INTERFACE; p.value.i = itf; if (alSetParams(dev, &p, 1) < 0 || p.sizeOut < 0) return false; // throw TException("Error to set input device"); } ALpv param; param.param = AL_DEFAULT_INPUT; param.value.i = dev; if (alSetParams(AL_SYSTEM, ¶m, 1) < 0) return false; // throw TException("Error to set input device"); return true; } //------------------------------------------------------------------------------ bool setDefaultOutput() { ALpv pvbuf[1]; if (!isInterfaceSupported(AL_DEFAULT_OUTPUT, AL_SPEAKER_IF_TYPE)) return false; // throw TException("Speakers are not supported"); int dev = alGetResourceByName(AL_SYSTEM, (char *)"Headphone/Speaker", AL_DEVICE_TYPE); if (!dev) return false; // throw TException("invalid device speakers"); pvbuf[0].param = AL_DEFAULT_OUTPUT; pvbuf[0].value.i = dev; alSetParams(AL_SYSTEM, pvbuf, 1); // qui devo metterci gli altoparlanti e poi setto i valori per il default // output pvbuf[0].param = AL_INTERFACE; pvbuf[0].value.i = AL_SPEAKER_IF_TYPE; if (alSetParams(AL_DEFAULT_OUTPUT, pvbuf, 1) < 0) return false; // throw TException("Unable to set output device params"); return true; } //------------------------------------------------------------------------------ // return the indexes of all input device of a particular type list getInputDevice(int deviceType) { ALvalue vals[16]; ALpv quals[1]; list devList; int devNum; quals[0].param = AL_TYPE; quals[0].value.i = deviceType; if ((devNum = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, vals, 16, quals, 1)) > 0) { int i; for (i = 0; i < devNum; ++i) { int itf; ALvalue val[16]; if ((itf = alQueryValues(i, AL_INTERFACE, val, 16, 0, 0)) > 0) { int j; for (j = 0; j < itf; ++j) devList.push_back(vals[j].i); } } } return devList; } //------------------------------------------------------------------------------ // return the indexes of all input device of a particular type and interface list getInputDevice(int deviceType, int itfType) { ALvalue vals[16]; ALpv quals[1]; list devList; int devNum; quals[0].param = AL_TYPE; quals[0].value.i = deviceType; if ((devNum = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, vals, 16, quals, 1)) > 0) { int i; for (i = 0; i < devNum; ++i) { int itf; ALvalue val[16]; quals[0].param = AL_TYPE; quals[0].value.i = itfType; if ((itf = alQueryValues(i, AL_INTERFACE, val, 16, quals, 1)) > 0) { int j; for (j = 0; j < itf; ++j) devList.push_back(vals[j].i); } } } return devList; } //------------------------------------------------------------------------------ string getResourceLabel(int resourceID) { ALpv par[1]; char l[32]; par[0].param = AL_LABEL; par[0].value.ptr = l; par[0].sizeIn = 32; alGetParams(resourceID, par, 1); return string(l); } //------------------------------------------------------------------------------ // verify the samplerate of the select device is changed from another // application bool isChangeOutput(ULONG sampleRate) { ALpv par[2]; char l[32]; par[0].param = AL_LABEL; par[0].value.ptr = l; par[0].sizeIn = 32; par[1].param = AL_RATE; alGetParams(AL_DEFAULT_OUTPUT, par, 2); if ((strcmp(l, "Analog Out") != 0) || (alFixedToDouble(par[1].value.ll) != sampleRate)) return true; else return false; } }