/** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) * @fork from RTAudio */ //#include #include #include #include #include #include #include #undef __class__ #define __class__ "api" // Static variable definitions. const std::vector& airtaudio::genericSampleRate() { static std::vector list; if (list.size() == 0) { list.push_back(4000); list.push_back(5512); list.push_back(8000); list.push_back(9600); list.push_back(11025); list.push_back(16000); list.push_back(22050); list.push_back(32000); list.push_back(44100); list.push_back(48000); list.push_back(64000); list.push_back(88200); list.push_back(96000); list.push_back(128000); list.push_back(176400); list.push_back(192000); } return list; }; airtaudio::Api::Api() : m_callback(nullptr), m_deviceBuffer(nullptr) { m_device[0] = 11111; m_device[1] = 11111; m_state = airtaudio::state_closed; m_mode = airtaudio::mode_unknow; } airtaudio::Api::~Api() { } enum airtaudio::error airtaudio::Api::startStream() { ATA_VERBOSE("Start Stream"); m_startTime = std11::chrono::system_clock::now(); m_duration = std11::chrono::microseconds(0); return airtaudio::error_none; } enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters *oParams, airtaudio::StreamParameters *iParams, enum audio::format format, uint32_t sampleRate, uint32_t *bufferFrames, airtaudio::AirTAudioCallback callback, airtaudio::StreamOptions *options) { if (m_state != airtaudio::state_closed) { ATA_ERROR("a stream is already open!"); return airtaudio::error_invalidUse; } if (oParams && oParams->nChannels < 1) { ATA_ERROR("a non-nullptr output StreamParameters structure cannot have an nChannels value less than one."); return airtaudio::error_invalidUse; } if (iParams && iParams->nChannels < 1) { ATA_ERROR("a non-nullptr input StreamParameters structure cannot have an nChannels value less than one."); return airtaudio::error_invalidUse; } if ( oParams == nullptr && iParams == nullptr) { ATA_ERROR("input and output StreamParameters structures are both nullptr!"); return airtaudio::error_invalidUse; } if (audio::getFormatBytes(format) == 0) { ATA_ERROR("'format' parameter value is undefined."); return airtaudio::error_invalidUse; } uint32_t nDevices = getDeviceCount(); uint32_t oChannels = 0; if (oParams) { oChannels = oParams->nChannels; if ( oParams->deviceId >= nDevices && oParams->deviceName == "") { ATA_ERROR("output device parameter value is invalid."); return airtaudio::error_invalidUse; } } uint32_t iChannels = 0; if (iParams) { iChannels = iParams->nChannels; if ( iParams->deviceId >= nDevices && iParams->deviceName == "") { ATA_ERROR("input device parameter value is invalid."); return airtaudio::error_invalidUse; } } clearStreamInfo(); bool result; if (oChannels > 0) { if (oParams->deviceId == -1) { result = probeDeviceOpenName(oParams->deviceName, airtaudio::mode_output, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options); } else { result = probeDeviceOpen(oParams->deviceId, airtaudio::mode_output, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options); } if (result == false) { ATA_ERROR("system ERROR"); return airtaudio::error_systemError; } } if (iChannels > 0) { if (iParams->deviceId == -1) { result = probeDeviceOpenName(iParams->deviceName, airtaudio::mode_input, iChannels, iParams->firstChannel, sampleRate, format, bufferFrames, options); } else { result = probeDeviceOpen(iParams->deviceId, airtaudio::mode_input, iChannels, iParams->firstChannel, sampleRate, format, bufferFrames, options); } if (result == false) { if (oChannels > 0) { closeStream(); } ATA_ERROR("system error"); return airtaudio::error_systemError; } } m_callback = callback; if (options != nullptr) { options->numberOfBuffers = m_nBuffers; } m_state = airtaudio::state_stopped; return airtaudio::error_none; } uint32_t airtaudio::Api::getDefaultInputDevice() { // Should be implemented in subclasses if possible. return 0; } uint32_t airtaudio::Api::getDefaultOutputDevice() { // Should be implemented in subclasses if possible. return 0; } enum airtaudio::error airtaudio::Api::closeStream() { ATA_VERBOSE("Close Stream"); // MUST be implemented in subclasses! return airtaudio::error_none; } bool airtaudio::Api::probeDeviceOpen(uint32_t /*device*/, airtaudio::mode /*mode*/, uint32_t /*channels*/, uint32_t /*firstChannel*/, uint32_t /*sampleRate*/, audio::format /*format*/, uint32_t * /*bufferSize*/, airtaudio::StreamOptions * /*options*/) { // MUST be implemented in subclasses! return false; } void airtaudio::Api::tickStreamTime() { //ATA_WARNING("tick : size=" << m_bufferSize << " rate=" << m_sampleRate << " time=" << std11::chrono::nanoseconds((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate)).count()); //ATA_WARNING(" one element=" << std11::chrono::nanoseconds((int64_t(1000000000)) / int64_t(m_sampleRate)).count()); m_duration += std11::chrono::nanoseconds((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate)); } long airtaudio::Api::getStreamLatency() { if (verifyStream() != airtaudio::error_none) { return 0; } long totalLatency = 0; if ( m_mode == airtaudio::mode_output || m_mode == airtaudio::mode_duplex) { totalLatency = m_latency[0]; } if ( m_mode == airtaudio::mode_input || m_mode == airtaudio::mode_duplex) { totalLatency += m_latency[1]; } return totalLatency; } std11::chrono::system_clock::time_point airtaudio::Api::getStreamTime() { if (verifyStream() != airtaudio::error_none) { return std11::chrono::system_clock::time_point(); } return m_startTime + m_duration; } uint32_t airtaudio::Api::getStreamSampleRate() { if (verifyStream() != airtaudio::error_none) { return 0; } return m_sampleRate; } enum airtaudio::error airtaudio::Api::verifyStream() { if (m_state == airtaudio::state_closed) { ATA_ERROR("a stream is not open!"); return airtaudio::error_invalidUse; } return airtaudio::error_none; } void airtaudio::Api::clearStreamInfo() { m_mode = airtaudio::mode_unknow; m_state = airtaudio::state_closed; m_sampleRate = 0; m_bufferSize = 0; m_nBuffers = 0; m_userFormat = audio::format_unknow; m_startTime = std11::chrono::system_clock::time_point(); m_duration = std11::chrono::nanoseconds(0); m_deviceBuffer = nullptr; m_callback = nullptr; for (int32_t iii=0; iii<2; ++iii) { m_device[iii] = 11111; m_doConvertBuffer[iii] = false; m_deviceInterleaved[iii] = true; m_doByteSwap[iii] = false; m_nUserChannels[iii] = 0; m_nDeviceChannels[iii] = 0; m_channelOffset[iii] = 0; m_deviceFormat[iii] = audio::format_unknow; m_latency[iii] = 0; m_userBuffer[iii].clear(); m_convertInfo[iii].channels = 0; m_convertInfo[iii].inJump = 0; m_convertInfo[iii].outJump = 0; m_convertInfo[iii].inFormat = audio::format_unknow; m_convertInfo[iii].outFormat = audio::format_unknow; m_convertInfo[iii].inOffset.clear(); m_convertInfo[iii].outOffset.clear(); } } void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChannel) { int32_t idTable = airtaudio::modeToIdTable(_mode); if (_mode == airtaudio::mode_input) { // convert device to user buffer m_convertInfo[idTable].inJump = m_nDeviceChannels[1]; m_convertInfo[idTable].outJump = m_nUserChannels[1]; m_convertInfo[idTable].inFormat = m_deviceFormat[1]; m_convertInfo[idTable].outFormat = m_userFormat; } else { // convert user to device buffer m_convertInfo[idTable].inJump = m_nUserChannels[0]; m_convertInfo[idTable].outJump = m_nDeviceChannels[0]; m_convertInfo[idTable].inFormat = m_userFormat; m_convertInfo[idTable].outFormat = m_deviceFormat[0]; } if (m_convertInfo[idTable].inJump < m_convertInfo[idTable].outJump) { m_convertInfo[idTable].channels = m_convertInfo[idTable].inJump; } else { m_convertInfo[idTable].channels = m_convertInfo[idTable].outJump; } // Set up the interleave/deinterleave offsets. if (m_deviceInterleaved[idTable] == false) { if (_mode == airtaudio::mode_input) { for (int32_t kkk=0; kkk 0) { if (m_deviceInterleaved[idTable]) { if (_mode == airtaudio::mode_output) { for (int32_t kkk=0; kkk(_outBuffer); uint8_t *in = reinterpret_cast(_inBuffer); for (size_t iii=0; iii(_outBuffer); uint16_t *in = reinterpret_cast(_inBuffer); for (size_t iii=0; iii(_outBuffer); uint32_t *in = reinterpret_cast(_inBuffer); for (size_t iii=0; iii(_outBuffer); uint64_t *in = reinterpret_cast(_inBuffer); for (size_t iii=0; iii