[DEV correct audio output

This commit is contained in:
Edouard DUPIN 2015-06-26 22:07:50 +02:00
parent 7aad6c26c4
commit 36b0231a11
7 changed files with 343 additions and 99 deletions

View File

@ -8,11 +8,85 @@
package org.musicdsp.orchestra;
import android.media.AudioTrack;
// Replace by :
import android.media.AudioRecord;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.util.Log;
public class InterfaceInput {
public InterfaceInput() {
Log.d("InterfaceInput", "new: Input");
public class InterfaceInput extends Thread implements Constants {
private int uid = -1;
private Orchestra ORCHESTRA;
public static final int SAMPLE_FREQ_44100 = 44100;
private boolean m_stopAudioThreads = false;
private AudioTrack m_musicTrack = null;
public InterfaceInput(int id, Orchestra instance, int idDevice, int freq, int nbChannel, int format) {
Log.d("InterfaceInput", "new: output");
uid = id;
ORCHESTRA = instance;
m_stopAudioThreads = false;
}
public int getUId() {
return uid;
}
public void run() {
Log.e("InterfaceInput", "RUN (start)");
int sampleFreq = SAMPLE_FREQ_44100; //AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int nbChannels = 2;
// we keep the minimum buffer size, otherwite the delay is too big ...
int bufferSize = AudioTrack.getMinBufferSize(sampleFreq, channelConfig, audioFormat);
// Create a streaming AudioTrack for music playback
short[] streamBuffer = new short[bufferSize];
m_musicTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
SAMPLE_FREQ_44100,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
m_musicTrack.play();
m_stopAudioThreads = false;
//m_musicTrack.setPositionNotificationPeriod(2048);
// TODO : ....
while (!m_stopAudioThreads) {
// Fill buffer with PCM data from C++
ORCHESTRA.playback(uid, streamBuffer, BUFFER_SIZE);
// Stream PCM data into the music AudioTrack
m_musicTrack.write(streamBuffer, 0, BUFFER_SIZE);
}
m_musicTrack.flush();
m_musicTrack.stop();
m_musicTrack = null;
streamBuffer = null;
Log.e("InterfaceInput", "RUN (stop)");
}
public void Pause() {
if(m_musicTrack == null) {
return;
}
m_musicTrack.pause();
}
public void Resume() {
if(m_musicTrack == null) {
return;
}
m_musicTrack.play();
}
public void AutoStop() {
if(m_musicTrack == null) {
return;
}
m_stopAudioThreads=true;
}
}

View File

@ -14,7 +14,6 @@ import android.media.AudioRecord;
import android.util.Log;
public class InterfaceOutput extends Thread implements Constants {
private int uid = -1;
private Orchestra ORCHESTRA;
@ -28,9 +27,12 @@ public class InterfaceOutput extends Thread implements Constants {
ORCHESTRA = instance;
m_stopAudioThreads = false;
}
public int getUId() {
return uid;
}
public void run() {
Log.e("audioEWOL", "RUN (start)");
Log.e("InterfaceOutput", "RUN (start)");
int sampleFreq = SAMPLE_FREQ_44100; //AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
@ -51,7 +53,7 @@ public class InterfaceOutput extends Thread implements Constants {
while (!m_stopAudioThreads) {
// Fill buffer with PCM data from C++
ORCHESTRA.playback(uid, streamBuffer, BUFFER_SIZE);
ORCHESTRA.playback(uid, streamBuffer, BUFFER_SIZE/nbChannels);
// Stream PCM data into the music AudioTrack
m_musicTrack.write(streamBuffer, 0, BUFFER_SIZE);
}
@ -60,7 +62,7 @@ public class InterfaceOutput extends Thread implements Constants {
m_musicTrack.stop();
m_musicTrack = null;
streamBuffer = null;
Log.e("audioEWOL", "RUN (stop)");
Log.e("InterfaceOutput", "RUN (stop)");
}
public void Pause() {
if(m_musicTrack == null) {

View File

@ -24,7 +24,6 @@ import org.musicdsp.orchestra.InterfaceInput;
public class Manager implements ManagerCallback, Constants {
private Orchestra orchestraHandle;
private int uid = 0;
private InterfaceOutput test;
private Vector<InterfaceOutput> outputList;
private Vector<InterfaceInput> inputList;
@ -32,6 +31,7 @@ public class Manager implements ManagerCallback, Constants {
// set the java evironement in the C sources :
orchestraHandle = new Orchestra(this);
outputList = new Vector<InterfaceOutput>();
inputList = new Vector<InterfaceInput>();
}
public int getDeviceCount() {
@ -54,52 +54,165 @@ public class Manager implements ManagerCallback, Constants {
}
}
public boolean openDevice(int idDevice, int freq, int nbChannel, int format) {
public int openDeviceOutput(int idDevice, int freq, int nbChannel, int format) {
InterfaceOutput iface = new InterfaceOutput(uid, orchestraHandle, idDevice, freq, nbChannel, format);
uid++;
Log.e("Manager", "Open device : " + idDevice);
Log.e("Manager", "Open device Output: " + idDevice + " with UID=" + (uid-1));
if (iface != null) {
//outputList.add(iface);
test = iface;
return true;
outputList.add(iface);
Log.e("Manager", "Added element count=" + outputList.size());
return uid-1;
}
return false;
return -1;
}
public boolean closeDevice(int idDevice) {
Log.e("Manager", "Close device : " + idDevice);
if (idDevice == 0) {
test = null;
public int openDeviceInput(int idDevice, int freq, int nbChannel, int format) {
InterfaceInput iface = new InterfaceInput(uid, orchestraHandle, idDevice, freq, nbChannel, format);
uid++;
Log.e("Manager", "Open device Input: " + idDevice + " with UID=" + (uid-1));
if (iface != null) {
inputList.add(iface);
return uid-1;
}
return false;
return -1;
}
public boolean start(int idDevice) {
Log.e("Manager", "start device : " + idDevice);
if (idDevice == 0) {
if (test != null) {
test.start();
public boolean closeDevice(int uniqueID) {
Log.e("Manager", "Close device : " + uniqueID);
if (uniqueID<0) {
Log.e("Manager", "Can not Close device with UID: " + uniqueID);
return false;
}
// find the Element with his ID:
if (inputList != null) {
for (int iii=0; iii<inputList.size(); iii++) {
if (inputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (inputList.get(iii).getUId() == uniqueID) {
// find it ...
inputList.remove(iii);
return true;
}
}
}
if (outputList != null) {
for (int iii=0; iii<outputList.size(); iii++) {
if (outputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (outputList.get(iii).getUId() == uniqueID) {
// find it ...
outputList.remove(iii);
return true;
}
}
}
Log.e("Manager", "Can not start device with UID: " + uniqueID + " Element does not exist ...");
return false;
}
public boolean stop(int idDevice) {
Log.e("Manager", "stop device : " + idDevice);
if (idDevice == 0) {
if (test != null) {
// request audio stop
test.AutoStop();
public boolean start(int uniqueID) {
Log.e("Manager", "start device : " + uniqueID);
if (uniqueID<0) {
Log.e("Manager", "Can not start device with UID: " + uniqueID);
return false;
}
// find the Element with his ID:
if (inputList != null) {
for (int iii=0; iii<inputList.size(); iii++) {
if (inputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (inputList.get(iii).getUId() == uniqueID) {
// find it ...
inputList.get(iii).start();
return true;
}
}
}
if (outputList != null) {
for (int iii=0; iii<outputList.size(); iii++) {
if (outputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (outputList.get(iii).getUId() == uniqueID) {
// find it ...
outputList.get(iii).start();
return true;
}
}
}
Log.e("Manager", "Can not start device with UID: " + uniqueID + " Element does not exist ...");
return false;
}
public boolean stop(int uniqueID) {
Log.e("Manager", "stop device : " + uniqueID);
if (uniqueID<0) {
Log.e("Manager", "Can not stop device with UID: " + uniqueID);
return false;
}
// find the Element with his ID:
if (inputList != null) {
for (int iii=0; iii<inputList.size(); iii++) {
if (inputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (inputList.get(iii).getUId() == uniqueID) {
// find it ...
inputList.get(iii).AutoStop();
try {
test.join();
inputList.get(iii).join();
} catch(InterruptedException e) { }
test = null;
return true;
}
}
}
if (outputList != null) {
for (int iii=0; iii<outputList.size(); iii++) {
if (outputList.get(iii) == null) {
Log.e("Manager", "Null input element: " + iii);
continue;
}
if (outputList.get(iii).getUId() == uniqueID) {
// find it ...
outputList.get(iii).AutoStop();
try {
outputList.get(iii).join();
} catch(InterruptedException e) { }
return true;
}
}
}
Log.e("Manager", "Can not stop device with UID: " + uniqueID + " Element does not exist ...");
return false;
}
public void onCreate() {
Log.w("Manager", "onCreate ...");
}
public void onStart() {
Log.w("Manager", "onStart ...");
}
public void onRestart() {
Log.w("Manager", "onRestart ...");
}
public void onResume() {
Log.w("Manager", "onResume ...");
}
public void onPause() {
Log.w("Manager", "onPause ...");
}
public void onStop() {
Log.w("Manager", "onStop ...");
}
public void onDestroy() {
Log.w("Manager", "onDestroy ...");
}
}

View File

@ -11,8 +11,9 @@ package org.musicdsp.orchestra;
public interface ManagerCallback {
public int getDeviceCount();
public String getDeviceProperty(int idDevice);
public boolean openDevice(int idDevice, int sampleRate, int nbChannel, int format);
public boolean closeDevice(int idDevice);
public boolean start(int idDevice);
public boolean stop(int idDevice);
public int openDeviceInput(int idDevice, int sampleRate, int nbChannel, int format);
public int openDeviceOutput(int idDevice, int sampleRate, int nbChannel, int format);
public boolean closeDevice(int uniqueID);
public boolean start(int uniqueID);
public boolean stop(int uniqueID);
}

View File

@ -58,37 +58,44 @@ enum audio::orchestra::error audio::orchestra::api::Android::startStream() {
enum audio::orchestra::error audio::orchestra::api::Android::stopStream() {
ATA_INFO("Stop stream");
#if 0
ewol::Context& tmpContext = ewol::getContext();
tmpContext.audioCloseDevice(0);
#endif
// Can not close the stream now...
return audio::orchestra::api::android::stopStream(m_uid);
}
enum audio::orchestra::error audio::orchestra::api::Android::abortStream() {
ATA_INFO("Abort Stream");
#if 0
ewol::Context& tmpContext = ewol::getContext();
tmpContext.audioCloseDevice(0);
#endif
// Can not close the stream now...
return audio::orchestra::error_none;
}
void audio::orchestra::api::Android::playback(int16_t* _dst, int32_t _nbChunk) {
// clear output buffer:
if (_dst != nullptr) {
memset(_dst, 0, _nbChunk*audio::getFormatBytes(m_deviceFormat[modeToIdTable(m_mode)])*m_nDeviceChannels[modeToIdTable(m_mode)]);
}
int32_t doStopStream = 0;
audio::Time streamTime = getStreamTime();
std::vector<enum audio::orchestra::status> status;
ATA_INFO("Need playback data " << int32_t(_nbChunk));
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " userbuffer size = " << m_userBuffer[audio::orchestra::mode_output].size() << "pointer=" << int64_t(&m_userBuffer[audio::orchestra::mode_output][0]));
doStopStream = m_callback(nullptr,
audio::Time(),
&m_userBuffer[audio::orchestra::mode_output][0],
&m_userBuffer[m_mode][0],
streamTime,
uint32_t(_nbChunk),
status);
convertBuffer((char*)_dst, (char*)&m_userBuffer[audio::orchestra::mode_output][0], m_convertInfo[audio::orchestra::mode_output]);
} else {
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " pointer=" << int64_t(_dst));
doStopStream = m_callback(nullptr,
audio::Time(),
_dst,
streamTime,
uint32_t(_nbChunk),
status);
}
if (doStopStream == 2) {
abortStream();
return;
@ -111,10 +118,11 @@ bool audio::orchestra::api::Android::probeDeviceOpen(uint32_t _device,
ATA_ERROR("Can not start a device input or duplex for Android ...");
return false;
}
m_mode = _mode;
m_userFormat = _format;
m_nUserChannels[modeToIdTable(_mode)] = _channels;
m_nUserChannels[modeToIdTable(m_mode)] = _channels;
m_uid = audio::orchestra::api::android::open(_device, _mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, std11::static_pointer_cast<audio::orchestra::api::Android>(shared_from_this()));
m_uid = audio::orchestra::api::android::open(_device, m_mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, std11::static_pointer_cast<audio::orchestra::api::Android>(shared_from_this()));
if (m_uid < 0) {
ret = false;
} else {
@ -122,36 +130,36 @@ bool audio::orchestra::api::Android::probeDeviceOpen(uint32_t _device,
}
m_bufferSize = 256;
m_sampleRate = _sampleRate;
m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ...
m_doByteSwap[modeToIdTable(m_mode)] = false; // for endienness ...
// TODO : For now, we write it in hard ==> to bu update later ...
m_deviceFormat[modeToIdTable(_mode)] = audio::format_int16;
m_nDeviceChannels[modeToIdTable(_mode)] = 2;
m_deviceInterleaved[modeToIdTable(_mode)] = true;
m_deviceFormat[modeToIdTable(m_mode)] = audio::format_int16;
m_nDeviceChannels[modeToIdTable(m_mode)] = 2;
m_deviceInterleaved[modeToIdTable(m_mode)] = true;
m_doConvertBuffer[modeToIdTable(_mode)] = false;
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
m_doConvertBuffer[modeToIdTable(m_mode)] = false;
if (m_userFormat != m_deviceFormat[modeToIdTable(m_mode)]) {
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
}
if (m_nUserChannels[modeToIdTable(_mode)] < m_nDeviceChannels[modeToIdTable(_mode)]) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
if (m_nUserChannels[modeToIdTable(m_mode)] < m_nDeviceChannels[modeToIdTable(m_mode)]) {
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
}
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
m_doConvertBuffer[modeToIdTable(_mode)] = true;
if ( m_deviceInterleaved[modeToIdTable(m_mode)] == false
&& m_nUserChannels[modeToIdTable(m_mode)] > 1) {
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
}
if (m_doConvertBuffer[modeToIdTable(_mode)] == true) {
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
// Allocate necessary internal buffers.
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes);
if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(m_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
m_userBuffer[modeToIdTable(m_mode)].resize(bufferBytes);
if (m_userBuffer[modeToIdTable(m_mode)].size() == 0) {
ATA_ERROR("audio::orchestra::api::Android::probeDeviceOpen: error allocating user buffer memory.");
}
setConvertInfo(_mode, _firstChannel);
setConvertInfo(m_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)]);
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(m_mode)] << " user format : " << m_userFormat);
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(m_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(m_mode)]);
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(m_mode)]);
if (ret == false) {
ATA_ERROR("Can not open device.");
}

View File

@ -26,7 +26,8 @@ class AndroidOrchestraContext {
jobject m_javaObjectOrchestraCallback;
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceCount;
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceProperty;
jmethodID m_javaMethodOrchestraActivityAudioOpenDevice;
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceInput;
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceOutput;
jmethodID m_javaMethodOrchestraActivityAudioCloseDevice;
jmethodID m_javaMethodOrchestraActivityAudioStart;
jmethodID m_javaMethodOrchestraActivityAudioStop;
@ -81,7 +82,8 @@ class AndroidOrchestraContext {
m_javaMethodOrchestraActivityAudioGetDeviceCount(0),
m_javaMethodOrchestraActivityAudioGetDeviceProperty(0),
m_javaMethodOrchestraActivityAudioOpenDevice(0),
m_javaMethodOrchestraActivityAudioOpenDeviceInput(0),
m_javaMethodOrchestraActivityAudioOpenDeviceOutput(0),
m_javaMethodOrchestraActivityAudioCloseDevice(0),
m_javaMethodOrchestraActivityAudioStart(0),
m_javaMethodOrchestraActivityAudioStop(0),
@ -133,13 +135,22 @@ class AndroidOrchestraContext {
ATA_ERROR("system can not start without function : getDeviceProperty");
functionCallbackIsMissing = true;
}
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDevice,
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDeviceInput,
m_javaClassOrchestraCallback,
"openDevice",
"(IIII)Z");
"openDeviceInput",
"(IIII)I");
if (ret == false) {
jvm_basics::checkExceptionJavaVM(_env);
ATA_ERROR("system can not start without function : openDevice");
ATA_ERROR("system can not start without function : openDeviceInput");
functionCallbackIsMissing = true;
}
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDeviceOutput,
m_javaClassOrchestraCallback,
"openDeviceOutput",
"(IIII)I");
if (ret == false) {
jvm_basics::checkExceptionJavaVM(_env);
ATA_ERROR("system can not start without function : openDeviceOutput");
functionCallbackIsMissing = true;
}
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioCloseDevice,
@ -260,11 +271,6 @@ class AndroidOrchestraContext {
}
}
info.isDefault = doc.getBooleanValue("default", false);
/*
+ " sample-rate:[8000,16000,24000,32000,48000,96000],\n"
+ " channels=[front-left,front-right],\n"
+ " format:[int16]\n"
*/
//return retString;
return info;
}
@ -288,13 +294,18 @@ class AndroidOrchestraContext {
return -1;
}
//Call java ...
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioOpenDevice, _idDevice, _sampleRate, _channels, /*_format*/ 1);
jint ret = false;
if (_mode == audio::orchestra::mode_output) {
ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioOpenDeviceOutput, _idDevice, _sampleRate, _channels, /*_format*/ 1);
} else {
ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioOpenDeviceInput, _idDevice, _sampleRate, _channels, /*_format*/ 1);
}
// manage execption :
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
java_detach_current_thread(status);
if (bool(ret) == true) {
if (int32_t(ret) >= 0) {
m_instanceList.push_back(_instance);
return 0;
return int32_t(ret);
}
return -1;
}

View File

@ -98,19 +98,54 @@ def tool_generate_add_java_section_in_class(target, module, package_name):
"import org.musicdsp.orchestra.Manager;"
])
module.pkg_add("GENERATE_SECTION__DECLARE", [
"private Manager MANAGER;"
"private Manager m_audioManagerHandle;"
])
module.pkg_add("GENERATE_SECTION__CONSTRUCTOR", [
"// load audio maneger if it does not work, it is not critical ...",
"try {",
" MANAGER = new Manager();",
" m_audioManagerHandle = new Manager();",
"} catch (RuntimeException e) {",
" Log.e(\"" + package_name + "\", \"Can not load Audio interface (maybe not really needed) :\" + e);",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_CREATE", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onCreate();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_START", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onStart();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_RESTART", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onRestart();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_RESUME", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onResume();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_PAUSE", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onPause();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_STOP", [
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onStop();",
"}"
])
module.pkg_add("GENERATE_SECTION__ON_DESTROY", [
"// Destroy the AdView.",
"if (m_audioManagerHandle != null) {",
" m_audioManagerHandle.onDestroy();",
"}"
])