audio-orchestra/airtaudio/api/Android.cpp

211 lines
7.5 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @fork from RTAudio
*/
#ifdef __ANDROID_JAVA__
#include <ewol/context/Context.h>
#include <unistd.h>
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <limits.h>
#undef __class__
#define __class__ "api::Android"
airtaudio::Api* airtaudio::api::Android::Create() {
ATA_INFO("Create Android device ... ");
return new airtaudio::api::Android();
}
airtaudio::api::Android::Android() {
ATA_INFO("new Android");
// On android, we set a static device ...
ATA_INFO("get context");
ewol::Context& tmpContext = ewol::getContext();
ATA_INFO("done p=" << (int64_t)&tmpContext);
int32_t deviceCount = tmpContext.audioGetDeviceCount();
ATA_ERROR("Get count devices : " << deviceCount);
for (int32_t iii=0; iii<deviceCount; ++iii) {
std::string property = tmpContext.audioGetDeviceProperty(iii);
ATA_ERROR("Get devices property : " << property);
std::vector<std::string> listProperty = etk::split(property, ':');
airtaudio::DeviceInfo tmp;
tmp.name = listProperty[0];
std::vector<std::string> listFreq = etk::split(listProperty[2], ',');
for(size_t fff=0; fff<listFreq.size(); ++fff) {
tmp.sampleRates.push_back(etk::string_to_int32_t(listFreq[fff]));
}
tmp.outputChannels = 0;
tmp.inputChannels = 0;
tmp.duplexChannels = 0;
if (listProperty[1] == "out") {
tmp.isDefaultOutput = true;
tmp.isDefaultInput = false;
tmp.outputChannels = etk::string_to_int32_t(listProperty[3]);
} else if (listProperty[1] == "in") {
tmp.isDefaultOutput = false;
tmp.isDefaultInput = true;
tmp.inputChannels = etk::string_to_int32_t(listProperty[3]);
} else {
/* duplex */
tmp.isDefaultOutput = true;
tmp.isDefaultInput = true;
tmp.duplexChannels = etk::string_to_int32_t(listProperty[3]);
}
tmp.nativeFormats = audio::getListFormatFromString(listProperty[4]);
m_devices.push_back(tmp);
}
ATA_INFO("Create Android interface (end)");
}
airtaudio::api::Android::~Android() {
ATA_INFO("Destroy Android interface");
}
uint32_t airtaudio::api::Android::getDeviceCount() {
//ATA_INFO("Get device count:"<< m_devices.size());
return m_devices.size();
}
airtaudio::DeviceInfo airtaudio::api::Android::getDeviceInfo(uint32_t _device) {
//ATA_INFO("Get device info ...");
return m_devices[_device];
}
enum airtaudio::error airtaudio::api::Android::closeStream() {
ATA_INFO("Clese Stream");
// Can not close the stream now...
return airtaudio::error_none;
}
enum airtaudio::error airtaudio::api::Android::startStream() {
ATA_INFO("Start Stream");
// TODO : Check return ...
airtaudio::Api::startStream();
// Can not close the stream now...
return airtaudio::error_none;
}
enum airtaudio::error airtaudio::api::Android::stopStream() {
ATA_INFO("Stop stream");
ewol::Context& tmpContext = ewol::getContext();
tmpContext.audioCloseDevice(0);
// Can not close the stream now...
return airtaudio::error_none;
}
enum airtaudio::error airtaudio::api::Android::abortStream() {
ATA_INFO("Abort Stream");
ewol::Context& tmpContext = ewol::getContext();
tmpContext.audioCloseDevice(0);
// Can not close the stream now...
return airtaudio::error_none;
}
void airtaudio::api::Android::callBackEvent(void* _data,
int32_t _frameRate) {
int32_t doStopStream = 0;
std11::chrono::system_clock::time_point streamTime = getStreamTime();
std::vector<enum airtaudio::status> status;
if (m_doConvertBuffer[airtaudio::mode_output] == true) {
doStopStream = m_callback(nullptr,
std11::chrono::system_clock::time_point(),
m_userBuffer[airtaudio::mode_output],
streamTime,
_frameRate,
status);
convertBuffer((char*)_data, (char*)m_userBuffer[airtaudio::mode_output], m_convertInfo[airtaudio::mode_output]);
} else {
doStopStream = m_callback(_data,
streamTime,
nullptr,
std11::chrono::system_clock::time_point(),
_frameRate,
status);
}
if (doStopStream == 2) {
abortStream();
return;
}
airtaudio::Api::tickStreamTime();
}
void airtaudio::api::Android::androidCallBackEvent(void* _data,
int32_t _frameRate,
void* _userData) {
if (_userData == nullptr) {
ATA_INFO("callback event ... nullptr pointer");
return;
}
airtaudio::api::Android* myClass = static_cast<airtaudio::api::Android*>(_userData);
myClass->callBackEvent(_data, _frameRate/2);
}
bool airtaudio::api::Android::probeDeviceOpen(uint32_t _device,
airtaudio::mode _mode,
uint32_t _channels,
uint32_t _firstChannel,
uint32_t _sampleRate,
audio::format _format,
uint32_t *_bufferSize,
const airtaudio::StreamOptions& _options) {
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
if (_mode != airtaudio::mode_output) {
ATA_ERROR("Can not start a device input or duplex for Android ...");
return false;
}
m_userFormat = _format;
m_nUserChannels[modeToIdTable(_mode)] = _channels;
ewol::Context& tmpContext = ewol::getContext();
bool ret = false;
if (_format == SINT8) {
ret = tmpContext.audioOpenDevice(_device, _sampleRate, _channels, 0, androidCallBackEvent, this);
} else {
ret = tmpContext.audioOpenDevice(_device, _sampleRate, _channels, 1, androidCallBackEvent, this);
}
m_bufferSize = 256;
m_sampleRate = _sampleRate;
m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ...
// TODO : For now, we write it in hard ==> to bu update later ...
m_deviceFormat[modeToIdTable(_mode)] = SINT16;
m_nDeviceChannels[modeToIdTable(_mode)] = 2;
m_deviceInterleaved[modeToIdTable(_mode)] = true;
m_doConvertBuffer[modeToIdTable(_mode)] = false;
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
}
if (m_nUserChannels[modeToIdTable(_mode)] < m_nDeviceChannels[modeToIdTable(_mode)]) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
}
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
}
if (m_doConvertBuffer[modeToIdTable(_mode)] == true) {
// Allocate necessary internal buffers.
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) {
ATA_ERROR("airtaudio::api::Android::probeDeviceOpen: error allocating user buffer memory.");
}
setConvertInfo(_mode, _firstChannel);
}
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(_mode)] << " user format : " << m_userFormat);
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(_mode)]);
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(_mode)]);
if (ret == false) {
ATA_ERROR("Can not open device.");
}
return ret;
}
#endif