diff --git a/android/org/musicdsp/orchestra/InterfaceInput.java b/android/org/musicdsp/orchestra/InterfaceInput.java index 7cd19b4..71d7729 100644 --- a/android/org/musicdsp/orchestra/InterfaceInput.java +++ b/android/org/musicdsp/orchestra/InterfaceInput.java @@ -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; } } - diff --git a/android/org/musicdsp/orchestra/InterfaceOutput.java b/android/org/musicdsp/orchestra/InterfaceOutput.java index 850b2f9..b656148 100644 --- a/android/org/musicdsp/orchestra/InterfaceOutput.java +++ b/android/org/musicdsp/orchestra/InterfaceOutput.java @@ -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) { diff --git a/android/org/musicdsp/orchestra/Manager.java b/android/org/musicdsp/orchestra/Manager.java index aced369..02e2beb 100644 --- a/android/org/musicdsp/orchestra/Manager.java +++ b/android/org/musicdsp/orchestra/Manager.java @@ -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 outputList; private Vector 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(); + inputList = new Vector(); } 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(); - return true; + 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 status; - ATA_INFO("Need playback data " << int32_t(_nbChunk)); - doStopStream = m_callback(nullptr, - audio::Time(), - &m_userBuffer[audio::orchestra::mode_output][0], - streamTime, - uint32_t(_nbChunk), - status); - convertBuffer((char*)_dst, (char*)&m_userBuffer[audio::orchestra::mode_output][0], m_convertInfo[audio::orchestra::mode_output]); + 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[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(shared_from_this())); + m_uid = audio::orchestra::api::android::open(_device, m_mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, std11::static_pointer_cast(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."); } diff --git a/audio/orchestra/api/AndroidNativeInterface.cpp b/audio/orchestra/api/AndroidNativeInterface.cpp index eae4191..71bf653 100644 --- a/audio/orchestra/api/AndroidNativeInterface.cpp +++ b/audio/orchestra/api/AndroidNativeInterface.cpp @@ -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; } diff --git a/lutin_audio-orchestra.py b/lutin_audio-orchestra.py index 06d72b5..3eabaae 100644 --- a/lutin_audio-orchestra.py +++ b/lutin_audio-orchestra.py @@ -98,17 +98,52 @@ 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();", + "}" + ])