Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
b7eed03e35 |
50
.travis.yml
50
.travis.yml
@@ -1,50 +0,0 @@
|
|||||||
language:
|
|
||||||
- cpp
|
|
||||||
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- dev
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
packages:
|
|
||||||
- g++-4.9
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install --user lutin
|
|
||||||
|
|
||||||
env:
|
|
||||||
- CONF=debug BOARD=Linux BUILDER=clang GCOV=
|
|
||||||
- CONF=release BOARD=Linux BUILDER=clang GCOV=
|
|
||||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=
|
|
||||||
- CONF=release BOARD=Linux BUILDER=gcc GCOV=
|
|
||||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=--gcov
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- cd ..
|
|
||||||
- wget http://atria-soft.com/ci/coverage_send.py
|
|
||||||
- wget http://atria-soft.com/ci/test_send.py
|
|
||||||
- wget http://atria-soft.com/ci/warning_send.py
|
|
||||||
- git clone https://github.com/atria-soft/etk.git
|
|
||||||
- git clone https://github.com/musicdsp/audio.git
|
|
||||||
- pwd
|
|
||||||
- ls -l
|
|
||||||
- if [ "$BUILDER" == "gcc" ]; then COMPILATOR_OPTION="--compilator-version=4.9"; else COMPILATOR_OPTION=""; fi
|
|
||||||
|
|
||||||
script:
|
|
||||||
- lutin -w -j4 -C -P -c $BUILDER $COMPILATOR_OPTION -m $CONF $GCOV -p audio-orchestra
|
|
||||||
# - ./out/Linux_x86_64/$CONF/staging/$BUILDER/audio-orchestra/usr/bin/audio-orchestra -l6
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
- yui.heero@gmail.com
|
|
||||||
|
|
@@ -1,4 +0,0 @@
|
|||||||
# audio-orchestra
|
|
||||||
(MIT) audio: backend to acces hardware access (Fork of the original RTAudio lib)
|
|
||||||
|
|
||||||
[](https://travis-ci.org/musicdsp/audio-orchestra)
|
|
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
|
|
||||||
public interface OrchestraConstants {
|
|
||||||
public static final int BUFFER_SIZE = 512;
|
|
||||||
}
|
|
@@ -1,119 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
import android.media.AudioRecord;
|
|
||||||
import android.media.AudioFormat;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.media.AudioRecord;
|
|
||||||
import android.media.MediaRecorder;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class OrchestraInterfaceInput implements Runnable, OrchestraConstants {
|
|
||||||
private Thread m_thread = null;
|
|
||||||
private int m_uid = -1;
|
|
||||||
private OrchestraNative m_orchestraNativeHandle;
|
|
||||||
private boolean m_stop = false;
|
|
||||||
private boolean m_suspend = false;
|
|
||||||
private AudioRecord m_audio = null;
|
|
||||||
private int m_sampleRate = 48000;
|
|
||||||
private int m_nbChannel = 2;
|
|
||||||
private int m_format = 1;
|
|
||||||
private int m_bufferSize = BUFFER_SIZE;
|
|
||||||
|
|
||||||
public OrchestraInterfaceInput(int _id, OrchestraNative _instance, int _idDevice, int _sampleRate, int _nbChannel, int _format) {
|
|
||||||
Log.d("InterfaceInput", "new: Input");
|
|
||||||
m_uid = _id;
|
|
||||||
m_orchestraNativeHandle = _instance;
|
|
||||||
m_stop = false;
|
|
||||||
m_suspend = false;
|
|
||||||
m_sampleRate = _sampleRate;
|
|
||||||
m_nbChannel = _nbChannel;
|
|
||||||
m_format = _format;
|
|
||||||
m_bufferSize = BUFFER_SIZE * m_nbChannel;
|
|
||||||
}
|
|
||||||
public int getUId() {
|
|
||||||
return m_uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
Log.e("InterfaceInput", "RUN (start)");
|
|
||||||
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
|
||||||
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
|
||||||
// we keep the minimum buffer size, otherwite the delay is too big ...
|
|
||||||
// TODO : int bufferSize = AudioRecord.getMinBufferSize(m_sampleRate, channelConfig, audioFormat);
|
|
||||||
int config = 0;
|
|
||||||
if (m_nbChannel == 1) {
|
|
||||||
config = AudioFormat.CHANNEL_IN_MONO;
|
|
||||||
} else {
|
|
||||||
config = AudioFormat.CHANNEL_IN_STEREO;
|
|
||||||
}
|
|
||||||
// Create a streaming AudioTrack for music playback
|
|
||||||
short[] streamBuffer = new short[m_bufferSize];
|
|
||||||
m_audio = new AudioRecord(MediaRecorder.AudioSource.MIC,
|
|
||||||
m_sampleRate,
|
|
||||||
config,
|
|
||||||
audioFormat,
|
|
||||||
m_bufferSize);
|
|
||||||
m_audio.startRecording();
|
|
||||||
|
|
||||||
while ( m_stop == false
|
|
||||||
&& m_suspend == false) {
|
|
||||||
// Stream PCM data into the local buffer
|
|
||||||
m_audio.read(streamBuffer, 0, m_bufferSize);
|
|
||||||
// Send it to C++
|
|
||||||
m_orchestraNativeHandle.record(m_uid, streamBuffer, m_bufferSize/m_nbChannel);
|
|
||||||
}
|
|
||||||
m_audio.stop();
|
|
||||||
m_audio = null;
|
|
||||||
streamBuffer = null;
|
|
||||||
Log.e("InterfaceInput", "RUN (stop)");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void autoStart() {
|
|
||||||
m_stop=false;
|
|
||||||
if (m_suspend == false) {
|
|
||||||
Log.e("InterfaceInput", "Create thread");
|
|
||||||
m_thread = new Thread(this);
|
|
||||||
Log.e("InterfaceInput", "start thread");
|
|
||||||
m_thread.start();
|
|
||||||
Log.e("InterfaceInput", "start thread (done)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void autoStop() {
|
|
||||||
if(m_audio == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_stop=true;
|
|
||||||
m_thread = null;
|
|
||||||
/*
|
|
||||||
try {
|
|
||||||
super.join();
|
|
||||||
} catch(InterruptedException e) { }
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
public void activityResume() {
|
|
||||||
m_suspend = false;
|
|
||||||
if (m_stop == false) {
|
|
||||||
Log.i("InterfaceInput", "Resume audio stream : " + m_uid);
|
|
||||||
m_thread = new Thread(this);
|
|
||||||
m_thread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void activityPause() {
|
|
||||||
if(m_audio == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_suspend = true;
|
|
||||||
Log.i("InterfaceInput", "Pause audio stream : " + m_uid);
|
|
||||||
m_thread = null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,108 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
|
|
||||||
import android.media.AudioTrack;
|
|
||||||
import android.media.AudioFormat;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.media.AudioRecord;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
public class OrchestraInterfaceOutput extends Thread implements OrchestraConstants {
|
|
||||||
private int m_uid = -1;
|
|
||||||
private OrchestraNative m_orchestraNativeHandle;
|
|
||||||
private boolean m_stop = false;
|
|
||||||
private boolean m_suspend = false;
|
|
||||||
private AudioTrack m_audio = null;
|
|
||||||
private int m_sampleRate = 48000;
|
|
||||||
private int m_nbChannel = 2;
|
|
||||||
private int m_format = 1;
|
|
||||||
private int m_bufferSize = BUFFER_SIZE;
|
|
||||||
|
|
||||||
public OrchestraInterfaceOutput(int _id, OrchestraNative _instance, int _idDevice, int _sampleRate, int _nbChannel, int _format) {
|
|
||||||
Log.d("InterfaceOutput", "new: output");
|
|
||||||
m_uid = _id;
|
|
||||||
m_orchestraNativeHandle = _instance;
|
|
||||||
m_stop = true;
|
|
||||||
m_sampleRate = _sampleRate;
|
|
||||||
m_nbChannel = _nbChannel;
|
|
||||||
m_format = _format;
|
|
||||||
m_bufferSize = BUFFER_SIZE * m_nbChannel;
|
|
||||||
}
|
|
||||||
public int getUId() {
|
|
||||||
return m_uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
Log.e("InterfaceOutput", "RUN (start)");
|
|
||||||
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
|
||||||
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
|
||||||
// we keep the minimum buffer size, otherwite the delay is too big ...
|
|
||||||
//int bufferSize = AudioTrack.getMinBufferSize(m_sampleRate, channelConfig, audioFormat);
|
|
||||||
int config = 0;
|
|
||||||
if (m_nbChannel == 1) {
|
|
||||||
config = AudioFormat.CHANNEL_OUT_MONO;
|
|
||||||
} else if (m_nbChannel == 4) {
|
|
||||||
config = AudioFormat.CHANNEL_OUT_QUAD;
|
|
||||||
} else {
|
|
||||||
config = AudioFormat.CHANNEL_OUT_STEREO;
|
|
||||||
}
|
|
||||||
// Create a streaming AudioTrack for music playback
|
|
||||||
short[] streamBuffer = new short[m_bufferSize];
|
|
||||||
m_audio = new AudioTrack(AudioManager.STREAM_MUSIC,
|
|
||||||
m_sampleRate,
|
|
||||||
config,
|
|
||||||
audioFormat,
|
|
||||||
m_bufferSize,
|
|
||||||
AudioTrack.MODE_STREAM);
|
|
||||||
m_audio.play();
|
|
||||||
//m_audio.setPositionNotificationPeriod(2048);
|
|
||||||
|
|
||||||
while (m_stop == false) {
|
|
||||||
// Fill buffer with PCM data from C++
|
|
||||||
m_orchestraNativeHandle.playback(m_uid, streamBuffer, m_bufferSize/m_nbChannel);
|
|
||||||
// Stream PCM data into the music AudioTrack
|
|
||||||
m_audio.write(streamBuffer, 0, m_bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_audio.flush();
|
|
||||||
m_audio.stop();
|
|
||||||
m_audio = null;
|
|
||||||
streamBuffer = null;
|
|
||||||
Log.e("InterfaceOutput", "RUN (stop)");
|
|
||||||
}
|
|
||||||
public void autoStart() {
|
|
||||||
m_stop=false;
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
public void autoStop() {
|
|
||||||
if(m_audio == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_stop=true;
|
|
||||||
try {
|
|
||||||
super.join();
|
|
||||||
} catch(InterruptedException e) { }
|
|
||||||
}
|
|
||||||
public void activityResume() {
|
|
||||||
if (m_audio != null) {
|
|
||||||
Log.i("InterfaceOutput", "Resume audio stream : " + m_uid);
|
|
||||||
m_audio.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void activityPause() {
|
|
||||||
if(m_audio == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_audio != null) {
|
|
||||||
Log.i("InterfaceOutput", "Pause audio stream : " + m_uid);
|
|
||||||
m_audio.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,262 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
//import org.musicdsp.orchestra.Constants;
|
|
||||||
//import org.musicdsp.orchestra.ManagerCallback;
|
|
||||||
//import org.musicdsp.orchestra.Orchestra;
|
|
||||||
//import org.musicdsp.orchestra.InterfaceOutput;
|
|
||||||
//import org.musicdsp.orchestra.InterfaceInput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Class :
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class OrchestraManager implements OrchestraManagerCallback, OrchestraConstants {
|
|
||||||
private OrchestraNative m_orchestraHandle;
|
|
||||||
private int m_uid = 0;
|
|
||||||
private Vector<OrchestraInterfaceOutput> m_outputList;
|
|
||||||
private Vector<OrchestraInterfaceInput> m_inputList;
|
|
||||||
|
|
||||||
public OrchestraManager() {
|
|
||||||
// set the java evironement in the C sources :
|
|
||||||
m_orchestraHandle = new OrchestraNative(this);
|
|
||||||
m_outputList = new Vector<OrchestraInterfaceOutput>();
|
|
||||||
m_inputList = new Vector<OrchestraInterfaceInput>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDeviceCount() {
|
|
||||||
Log.e("Manager", "Get device List");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceProperty(int _idDevice) {
|
|
||||||
if (_idDevice == 0) {
|
|
||||||
return "{\n"
|
|
||||||
+ " name:'speaker',\n"
|
|
||||||
+ " type:'output',\n"
|
|
||||||
+ " sample-rate:[8000,16000,24000,32000,48000,96000],\n"
|
|
||||||
+ " channels:['front-left','front-right'],\n"
|
|
||||||
+ " format:['int16'],\n"
|
|
||||||
+ " default:true\n"
|
|
||||||
+ "}";
|
|
||||||
} else if (_idDevice == 1) {
|
|
||||||
return "{\n"
|
|
||||||
+ " name:'microphone',\n"
|
|
||||||
+ " type:'input',\n"
|
|
||||||
+ " sample-rate:[8000,16000,24000,32000,48000,96000],\n"
|
|
||||||
+ " channels:['front-left','front-right'],\n"
|
|
||||||
+ " format:['int16'],\n"
|
|
||||||
+ " default:true\n"
|
|
||||||
+ "}";
|
|
||||||
} else {
|
|
||||||
return "{}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int openDeviceOutput(int _idDevice, int _freq, int _nbChannel, int _format) {
|
|
||||||
OrchestraInterfaceOutput iface = new OrchestraInterfaceOutput(m_uid, m_orchestraHandle, _idDevice, _freq, _nbChannel, _format);
|
|
||||||
m_uid++;
|
|
||||||
Log.e("Manager", "Open device Output: " + _idDevice + " with m_uid=" + (m_uid-1));
|
|
||||||
if (iface != null) {
|
|
||||||
m_outputList.add(iface);
|
|
||||||
Log.e("Manager", "Added element count=" + m_outputList.size());
|
|
||||||
return m_uid-1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int openDeviceInput(int _idDevice, int _freq, int _nbChannel, int _format) {
|
|
||||||
OrchestraInterfaceInput iface = new OrchestraInterfaceInput(m_uid, m_orchestraHandle, _idDevice, _freq, _nbChannel, _format);
|
|
||||||
m_uid++;
|
|
||||||
Log.e("Manager", "Open device Input: " + _idDevice + " with m_uid=" + (m_uid-1));
|
|
||||||
if (iface != null) {
|
|
||||||
m_inputList.add(iface);
|
|
||||||
return m_uid-1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean closeDevice(int _uniqueID) {
|
|
||||||
Log.e("Manager", "Close device : " + _uniqueID);
|
|
||||||
if (_uniqueID<0) {
|
|
||||||
Log.e("Manager", "Can not Close device with m_uid: " + _uniqueID);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// find the Element with his ID:
|
|
||||||
if (m_inputList != null) {
|
|
||||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
|
||||||
if (m_inputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_inputList.remove(iii);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_outputList != null) {
|
|
||||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
|
||||||
if (m_outputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_outputList.remove(iii);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.e("Manager", "Can not start device with m_uid: " + _uniqueID + " Element does not exist ...");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean start(int _uniqueID) {
|
|
||||||
Log.e("Manager", "start device : " + _uniqueID);
|
|
||||||
if (_uniqueID<0) {
|
|
||||||
Log.e("Manager", "Can not start device with m_uid: " + _uniqueID);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// find the Element with his ID:
|
|
||||||
if (m_inputList != null) {
|
|
||||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
|
||||||
if (m_inputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_inputList.get(iii).autoStart();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_outputList != null) {
|
|
||||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
|
||||||
if (m_outputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_outputList.get(iii).autoStart();
|
|
||||||
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 (m_inputList != null) {
|
|
||||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
|
||||||
if (m_inputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_inputList.get(iii).autoStop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_outputList != null) {
|
|
||||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
|
||||||
if (m_outputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
|
||||||
// find it ...
|
|
||||||
m_outputList.get(iii).autoStop();
|
|
||||||
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 ...");
|
|
||||||
// nothing to do ...
|
|
||||||
}
|
|
||||||
public void onStart() {
|
|
||||||
Log.w("Manager", "onStart ...");
|
|
||||||
// nothing to do ...
|
|
||||||
}
|
|
||||||
public void onRestart() {
|
|
||||||
Log.w("Manager", "onRestart ...");
|
|
||||||
// nothing to do ...
|
|
||||||
}
|
|
||||||
public void onResume() {
|
|
||||||
Log.w("Manager", "onResume ...");
|
|
||||||
// find the Element with his ID:
|
|
||||||
if (m_inputList != null) {
|
|
||||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
|
||||||
if (m_inputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_inputList.get(iii).activityResume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_outputList != null) {
|
|
||||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
|
||||||
if (m_outputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_outputList.get(iii).activityResume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void onPause() {
|
|
||||||
Log.w("Manager", "onPause ...");
|
|
||||||
// find the Element with his ID:
|
|
||||||
if (m_inputList != null) {
|
|
||||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
|
||||||
if (m_inputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_inputList.get(iii).activityPause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_outputList != null) {
|
|
||||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
|
||||||
if (m_outputList.get(iii) == null) {
|
|
||||||
Log.e("Manager", "Null input element: " + iii);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_outputList.get(iii).activityPause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void onStop() {
|
|
||||||
Log.w("Manager", "onStop ...");
|
|
||||||
}
|
|
||||||
public void onDestroy() {
|
|
||||||
Log.w("Manager", "onDestroy ...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
|
|
||||||
public interface OrchestraManagerCallback {
|
|
||||||
public int getDeviceCount();
|
|
||||||
public String getDeviceProperty(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);
|
|
||||||
}
|
|
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
|
||||||
*
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.musicdsp.orchestra;
|
|
||||||
|
|
||||||
import java.lang.UnsatisfiedLinkError;
|
|
||||||
import java.lang.RuntimeException;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class OrchestraNative {
|
|
||||||
public <T extends OrchestraManagerCallback> OrchestraNative(T _managerInstance) {
|
|
||||||
try {
|
|
||||||
NNsetJavaManager(_managerInstance);
|
|
||||||
} catch (java.lang.UnsatisfiedLinkError e) {
|
|
||||||
Log.e("Orchestra", "JNI binding not present ...");
|
|
||||||
throw new RuntimeException("Orchestra binding not present ...");
|
|
||||||
}
|
|
||||||
Log.d("Orchestra", "new ...");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setManagerRemove() {
|
|
||||||
NNsetJavaManagerRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playback(int _flowId, short[] _bufferData, int _nbChunk) {
|
|
||||||
NNPlayback(_flowId, _bufferData, _nbChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void record(int _flowId, short[] _bufferData, int _nbChunk) {
|
|
||||||
NNRecord(_flowId, _bufferData, _nbChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
private native <T extends OrchestraManagerCallback> void NNsetJavaManager(T _managerInstance);
|
|
||||||
private native void NNsetJavaManagerRemove();
|
|
||||||
private native void NNPlayback(int _flowId, short[] _bufferData, int _nbChunk);
|
|
||||||
private native void NNRecord(int _flowId, short[] _bufferData, int _nbChunk);
|
|
||||||
}
|
|
||||||
|
|
@@ -13,6 +13,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "api"
|
||||||
|
|
||||||
// Static variable definitions.
|
// Static variable definitions.
|
||||||
const std::vector<uint32_t>& audio::orchestra::genericSampleRate() {
|
const std::vector<uint32_t>& audio::orchestra::genericSampleRate() {
|
||||||
static std::vector<uint32_t> list;
|
static std::vector<uint32_t> list;
|
||||||
@@ -33,7 +36,6 @@ const std::vector<uint32_t>& audio::orchestra::genericSampleRate() {
|
|||||||
list.push_back(128000);
|
list.push_back(128000);
|
||||||
list.push_back(176400);
|
list.push_back(176400);
|
||||||
list.push_back(192000);
|
list.push_back(192000);
|
||||||
list.push_back(256000);
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
};
|
};
|
||||||
@@ -44,7 +46,7 @@ audio::orchestra::Api::Api() :
|
|||||||
m_deviceBuffer(nullptr) {
|
m_deviceBuffer(nullptr) {
|
||||||
m_device[0] = 11111;
|
m_device[0] = 11111;
|
||||||
m_device[1] = 11111;
|
m_device[1] = 11111;
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ audio::orchestra::Api::~Api() {
|
|||||||
enum audio::orchestra::error audio::orchestra::Api::startStream() {
|
enum audio::orchestra::error audio::orchestra::Api::startStream() {
|
||||||
ATA_VERBOSE("Start Stream");
|
ATA_VERBOSE("Start Stream");
|
||||||
m_startTime = audio::Time::now();
|
m_startTime = audio::Time::now();
|
||||||
m_duration = std::chrono::microseconds(0);
|
m_duration = std11::chrono::microseconds(0);
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra:
|
|||||||
uint32_t* _bufferFrames,
|
uint32_t* _bufferFrames,
|
||||||
audio::orchestra::AirTAudioCallback _callback,
|
audio::orchestra::AirTAudioCallback _callback,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("a stream is already open!");
|
ATA_ERROR("a stream is already open!");
|
||||||
return audio::orchestra::error_invalidUse;
|
return audio::orchestra::error_invalidUse;
|
||||||
}
|
}
|
||||||
@@ -112,23 +114,23 @@ enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra:
|
|||||||
bool result;
|
bool result;
|
||||||
if (oChannels > 0) {
|
if (oChannels > 0) {
|
||||||
if (_oParams->deviceId == -1) {
|
if (_oParams->deviceId == -1) {
|
||||||
result = openName(_oParams->deviceName,
|
result = probeDeviceOpenName(_oParams->deviceName,
|
||||||
audio::orchestra::mode_output,
|
audio::orchestra::mode_output,
|
||||||
oChannels,
|
oChannels,
|
||||||
_oParams->firstChannel,
|
_oParams->firstChannel,
|
||||||
_sampleRate,
|
_sampleRate,
|
||||||
_format,
|
_format,
|
||||||
_bufferFrames,
|
_bufferFrames,
|
||||||
_options);
|
_options);
|
||||||
} else {
|
} else {
|
||||||
result = open(_oParams->deviceId,
|
result = probeDeviceOpen(_oParams->deviceId,
|
||||||
audio::orchestra::mode_output,
|
audio::orchestra::mode_output,
|
||||||
oChannels,
|
oChannels,
|
||||||
_oParams->firstChannel,
|
_oParams->firstChannel,
|
||||||
_sampleRate,
|
_sampleRate,
|
||||||
_format,
|
_format,
|
||||||
_bufferFrames,
|
_bufferFrames,
|
||||||
_options);
|
_options);
|
||||||
}
|
}
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
ATA_ERROR("system ERROR");
|
ATA_ERROR("system ERROR");
|
||||||
@@ -137,23 +139,23 @@ enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra:
|
|||||||
}
|
}
|
||||||
if (iChannels > 0) {
|
if (iChannels > 0) {
|
||||||
if (_iParams->deviceId == -1) {
|
if (_iParams->deviceId == -1) {
|
||||||
result = openName(_iParams->deviceName,
|
result = probeDeviceOpenName(_iParams->deviceName,
|
||||||
audio::orchestra::mode_input,
|
audio::orchestra::mode_input,
|
||||||
iChannels,
|
iChannels,
|
||||||
_iParams->firstChannel,
|
_iParams->firstChannel,
|
||||||
_sampleRate,
|
_sampleRate,
|
||||||
_format,
|
_format,
|
||||||
_bufferFrames,
|
_bufferFrames,
|
||||||
_options);
|
_options);
|
||||||
} else {
|
} else {
|
||||||
result = open(_iParams->deviceId,
|
result = probeDeviceOpen(_iParams->deviceId,
|
||||||
audio::orchestra::mode_input,
|
audio::orchestra::mode_input,
|
||||||
iChannels,
|
iChannels,
|
||||||
_iParams->firstChannel,
|
_iParams->firstChannel,
|
||||||
_sampleRate,
|
_sampleRate,
|
||||||
_format,
|
_format,
|
||||||
_bufferFrames,
|
_bufferFrames,
|
||||||
_options);
|
_options);
|
||||||
}
|
}
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
if (oChannels > 0) {
|
if (oChannels > 0) {
|
||||||
@@ -165,7 +167,7 @@ enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra:
|
|||||||
}
|
}
|
||||||
m_callback = _callback;
|
m_callback = _callback;
|
||||||
//_options.numberOfBuffers = m_nBuffers;
|
//_options.numberOfBuffers = m_nBuffers;
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +187,14 @@ enum audio::orchestra::error audio::orchestra::Api::closeStream() {
|
|||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::Api::open(uint32_t /*device*/,
|
bool audio::orchestra::Api::probeDeviceOpen(uint32_t /*device*/,
|
||||||
audio::orchestra::mode /*mode*/,
|
audio::orchestra::mode /*mode*/,
|
||||||
uint32_t /*channels*/,
|
uint32_t /*channels*/,
|
||||||
uint32_t /*firstChannel*/,
|
uint32_t /*firstChannel*/,
|
||||||
uint32_t /*sampleRate*/,
|
uint32_t /*sampleRate*/,
|
||||||
audio::format /*format*/,
|
audio::format /*format*/,
|
||||||
uint32_t * /*bufferSize*/,
|
uint32_t * /*bufferSize*/,
|
||||||
const audio::orchestra::StreamOptions& /*options*/) {
|
const audio::orchestra::StreamOptions& /*options*/) {
|
||||||
// MUST be implemented in subclasses!
|
// MUST be implemented in subclasses!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -234,7 +236,7 @@ uint32_t audio::orchestra::Api::getStreamSampleRate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::Api::verifyStream() {
|
enum audio::orchestra::error audio::orchestra::Api::verifyStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("a stream is not open!");
|
ATA_ERROR("a stream is not open!");
|
||||||
return audio::orchestra::error_invalidUse;
|
return audio::orchestra::error_invalidUse;
|
||||||
}
|
}
|
||||||
@@ -243,7 +245,7 @@ enum audio::orchestra::error audio::orchestra::Api::verifyStream() {
|
|||||||
|
|
||||||
void audio::orchestra::Api::clearStreamInfo() {
|
void audio::orchestra::Api::clearStreamInfo() {
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
m_sampleRate = 0;
|
m_sampleRate = 0;
|
||||||
m_bufferSize = 0;
|
m_bufferSize = 0;
|
||||||
m_nBuffers = 0;
|
m_nBuffers = 0;
|
||||||
|
@@ -4,7 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_API_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_API_H__
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
@@ -13,11 +15,11 @@
|
|||||||
#include <audio/orchestra/mode.h>
|
#include <audio/orchestra/mode.h>
|
||||||
#include <audio/Time.h>
|
#include <audio/Time.h>
|
||||||
#include <audio/Duration.h>
|
#include <audio/Duration.h>
|
||||||
#include <ememory/memory.h>
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
const std::vector<uint32_t>& genericSampleRate();
|
const std::vector<uint32_t>& genericSampleRate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief airtaudio callback function prototype.
|
* @brief airtaudio callback function prototype.
|
||||||
* @param _inputBuffer For input (or duplex) streams, this buffer will hold _nbChunk of input audio chunk (nullptr if no data).
|
* @param _inputBuffer For input (or duplex) streams, this buffer will hold _nbChunk of input audio chunk (nullptr if no data).
|
||||||
@@ -27,7 +29,7 @@ namespace audio {
|
|||||||
* @param _nbChunk The number of chunk of input or output chunk in the buffer (same size).
|
* @param _nbChunk The number of chunk of input or output chunk in the buffer (same size).
|
||||||
* @param _status List of error that occured in the laps of time.
|
* @param _status List of error that occured in the laps of time.
|
||||||
*/
|
*/
|
||||||
typedef std::function<int32_t (const void* _inputBuffer,
|
typedef std11::function<int32_t (const void* _inputBuffer,
|
||||||
const audio::Time& _timeInput,
|
const audio::Time& _timeInput,
|
||||||
void* _outputBuffer,
|
void* _outputBuffer,
|
||||||
const audio::Time& _timeOutput,
|
const audio::Time& _timeOutput,
|
||||||
@@ -45,7 +47,7 @@ namespace audio {
|
|||||||
std::vector<int> outOffset;
|
std::vector<int> outOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Api : public ememory::EnableSharedFromThis<Api>{
|
class Api {
|
||||||
protected:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
public:
|
public:
|
||||||
@@ -54,7 +56,7 @@ namespace audio {
|
|||||||
void setName(const std::string& _name) {
|
void setName(const std::string& _name) {
|
||||||
m_name = _name;
|
m_name = _name;
|
||||||
}
|
}
|
||||||
virtual const std::string& getCurrentApi() = 0;
|
virtual audio::orchestra::type getCurrentApi() = 0;
|
||||||
virtual uint32_t getDeviceCount() = 0;
|
virtual uint32_t getDeviceCount() = 0;
|
||||||
virtual audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) = 0;
|
virtual audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) = 0;
|
||||||
// TODO : Check API ...
|
// TODO : Check API ...
|
||||||
@@ -64,12 +66,12 @@ namespace audio {
|
|||||||
virtual uint32_t getDefaultInputDevice();
|
virtual uint32_t getDefaultInputDevice();
|
||||||
virtual uint32_t getDefaultOutputDevice();
|
virtual uint32_t getDefaultOutputDevice();
|
||||||
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters* _outputParameters,
|
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||||
audio::orchestra::StreamParameters* _inputParameters,
|
audio::orchestra::StreamParameters* _inputParameters,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
uint32_t* _nbChunk,
|
uint32_t* _nbChunk,
|
||||||
audio::orchestra::AirTAudioCallback _callback,
|
audio::orchestra::AirTAudioCallback _callback,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
virtual enum audio::orchestra::error closeStream();
|
virtual enum audio::orchestra::error closeStream();
|
||||||
virtual enum audio::orchestra::error startStream();
|
virtual enum audio::orchestra::error startStream();
|
||||||
virtual enum audio::orchestra::error stopStream() = 0;
|
virtual enum audio::orchestra::error stopStream() = 0;
|
||||||
@@ -78,14 +80,14 @@ namespace audio {
|
|||||||
uint32_t getStreamSampleRate();
|
uint32_t getStreamSampleRate();
|
||||||
virtual audio::Time getStreamTime();
|
virtual audio::Time getStreamTime();
|
||||||
bool isStreamOpen() const {
|
bool isStreamOpen() const {
|
||||||
return m_state != audio::orchestra::state::closed;
|
return m_state != audio::orchestra::state_closed;
|
||||||
}
|
}
|
||||||
bool isStreamRunning() const {
|
bool isStreamRunning() const {
|
||||||
return m_state == audio::orchestra::state::running;
|
return m_state == audio::orchestra::state_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable std::mutex m_mutex;
|
mutable std11::mutex m_mutex;
|
||||||
audio::orchestra::AirTAudioCallback m_callback;
|
audio::orchestra::AirTAudioCallback m_callback;
|
||||||
uint32_t m_device[2]; // Playback and record, respectively.
|
uint32_t m_device[2]; // Playback and record, respectively.
|
||||||
enum audio::orchestra::mode m_mode; // audio::orchestra::mode_output, audio::orchestra::mode_input, or audio::orchestra::mode_duplex.
|
enum audio::orchestra::mode m_mode; // audio::orchestra::mode_output, audio::orchestra::mode_input, or audio::orchestra::mode_duplex.
|
||||||
@@ -117,21 +119,21 @@ namespace audio {
|
|||||||
* "warning" message is reported and false is returned. A
|
* "warning" message is reported and false is returned. A
|
||||||
* successful probe is indicated by a return value of true.
|
* successful probe is indicated by a return value of true.
|
||||||
*/
|
*/
|
||||||
virtual bool open(uint32_t _device,
|
virtual bool probeDeviceOpen(uint32_t _device,
|
||||||
enum audio::orchestra::mode _mode,
|
enum audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
enum audio::format _format,
|
enum audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
virtual bool openName(const std::string& _deviceName,
|
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) { return false; }
|
const audio::orchestra::StreamOptions& _options) { return false; }
|
||||||
/**
|
/**
|
||||||
* @brief Increment the stream time.
|
* @brief Increment the stream time.
|
||||||
@@ -166,10 +168,15 @@ namespace audio {
|
|||||||
uint32_t _firstChannel);
|
uint32_t _firstChannel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool isMasterOf(ememory::SharedPtr<audio::orchestra::Api> _api) {
|
virtual bool isMasterOf(audio::orchestra::Api* _api) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Debug operator To display the curent element in a Human redeable information
|
||||||
|
*/
|
||||||
|
std::ostream& operator <<(std::ostream& _os, const audio::orchestra::type& _obj);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -11,51 +11,36 @@
|
|||||||
#include <etk/stdTools.h>
|
#include <etk/stdTools.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "DeviceInfo"
|
||||||
|
|
||||||
void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const {
|
void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const {
|
||||||
std::string space;
|
std::string space;
|
||||||
for (int32_t iii=0; iii<_tabNumber; ++iii) {
|
for (int32_t iii=0; iii<_tabNumber; ++iii) {
|
||||||
space += " ";
|
space += " ";
|
||||||
}
|
}
|
||||||
if (isCorrect == false) {
|
ATA_INFO(space + "probe=" << probed);
|
||||||
ATA_PRINT(space + "NOT CORRECT INFORAMATIONS");
|
ATA_INFO(space + "name=" << name);
|
||||||
return;
|
ATA_INFO(space + "outputChannels=" << outputChannels);
|
||||||
}
|
ATA_INFO(space + "inputChannels=" << inputChannels);
|
||||||
ATA_PRINT(space + "mode=" << (input==true?"input":"output"));
|
ATA_INFO(space + "duplexChannels=" << duplexChannels);
|
||||||
ATA_PRINT(space + "name=" << name);
|
ATA_INFO(space + "isDefaultOutput=" << (isDefaultOutput==true?"true":"false"));
|
||||||
if (desc.size() != 0) {
|
ATA_INFO(space + "isDefaultInput=" << (isDefaultInput==true?"true":"false"));
|
||||||
ATA_PRINT(space + "desc=" << desc);
|
ATA_INFO(space + "rates=" << sampleRates);
|
||||||
}
|
ATA_INFO(space + "native Format: " << nativeFormats);
|
||||||
ATA_PRINT(space + "channel" << (channels.size()>1?"s":"") << "=" << channels.size() << " : " << channels);
|
|
||||||
ATA_PRINT(space + "rate" << (sampleRates.size()>1?"s":"") << "=" << sampleRates);
|
|
||||||
ATA_PRINT(space + "native Format" << (nativeFormats.size()>1?"s":"") << ": " << nativeFormats);
|
|
||||||
ATA_PRINT(space + "default=" << (isDefault==true?"true":"false"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void audio::orchestra::DeviceInfo::clear() {
|
|
||||||
isCorrect = false;
|
|
||||||
input = false;
|
|
||||||
name = "";
|
|
||||||
desc = "";
|
|
||||||
channels.clear();
|
|
||||||
sampleRates.clear();
|
|
||||||
nativeFormats.clear();
|
|
||||||
isDefault = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj) {
|
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj) {
|
||||||
_os << "{";
|
_os << "{";
|
||||||
if (_obj.isCorrect == false) {
|
_os << "probe=" << _obj.probed << ", ";
|
||||||
_os << "NOT CORRECT INFORAMATIONS";
|
_os << "name=" << _obj.name << ", ";
|
||||||
} else {
|
_os << "outputChannels=" << _obj.outputChannels << ", ";
|
||||||
_os << "name=" << _obj.name << ", ";
|
_os << "inputChannels=" << _obj.inputChannels << ", ";
|
||||||
if (_obj.desc.size() != 0) {
|
_os << "duplexChannels=" << _obj.duplexChannels << ", ";
|
||||||
_os << "description=" << _obj.desc << ", ";
|
_os << "isDefaultOutput=" << _obj.isDefaultOutput << ", ";
|
||||||
}
|
_os << "isDefaultInput=" << _obj.isDefaultInput << ", ";
|
||||||
_os << "channels=" << _obj.channels << ", ";
|
_os << "rates=" << _obj.sampleRates << ", ";
|
||||||
_os << "default=" << _obj.isDefault << ", ";
|
_os << "native Format: " << _obj.nativeFormats;
|
||||||
_os << "rates=" << _obj.sampleRates << ", ";
|
|
||||||
_os << "native Format: " << _obj.nativeFormats;
|
|
||||||
}
|
|
||||||
_os << "}";
|
_os << "}";
|
||||||
return _os;
|
return _os;
|
||||||
}
|
}
|
||||||
|
@@ -4,10 +4,12 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_DEVICE_INFO_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_DEVICE_INFO_H__
|
||||||
|
|
||||||
#include <audio/format.h>
|
#include <audio/format.h>
|
||||||
#include <audio/channel.h>
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -16,34 +18,29 @@ namespace audio {
|
|||||||
*/
|
*/
|
||||||
class DeviceInfo {
|
class DeviceInfo {
|
||||||
public:
|
public:
|
||||||
bool isCorrect; //!< the information is correct (the system can return information incorect).
|
bool probed; //!< true if the device capabilities were successfully probed.
|
||||||
bool input; //!< true if the device in an input; false: output.
|
|
||||||
std::string name; //!< Character string device identifier.
|
std::string name; //!< Character string device identifier.
|
||||||
std::string desc; //!< description of the device
|
uint32_t outputChannels; //!< Maximum output channels supported by device.
|
||||||
std::vector<audio::channel> channels; //!< Channels interfaces.
|
uint32_t inputChannels; //!< Maximum input channels supported by device.
|
||||||
|
uint32_t duplexChannels; //!< Maximum simultaneous input/output channels supported by device.
|
||||||
|
bool isDefaultOutput; //!< true if this is the default output device.
|
||||||
|
bool isDefaultInput; //!< true if this is the default input device.
|
||||||
std::vector<uint32_t> sampleRates; //!< Supported sample rates (queried from list of standard rates).
|
std::vector<uint32_t> sampleRates; //!< Supported sample rates (queried from list of standard rates).
|
||||||
std::vector<audio::format> nativeFormats; //!< Bit mask of supported data formats.
|
std::vector<audio::format> nativeFormats; //!< Bit mask of supported data formats.
|
||||||
bool isDefault; //! is default input/output
|
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
DeviceInfo() :
|
DeviceInfo() :
|
||||||
isCorrect(false),
|
probed(false),
|
||||||
input(false),
|
outputChannels(0),
|
||||||
name(),
|
inputChannels(0),
|
||||||
desc(),
|
duplexChannels(0),
|
||||||
channels(),
|
isDefaultOutput(false),
|
||||||
sampleRates(),
|
isDefaultInput(false),
|
||||||
nativeFormats(),
|
nativeFormats() {}
|
||||||
isDefault(false) {}
|
|
||||||
/**
|
|
||||||
* @brief Display the current information of the device (on console)
|
|
||||||
*/
|
|
||||||
void display(int32_t _tabNumber = 1) const;
|
void display(int32_t _tabNumber = 1) const;
|
||||||
/**
|
|
||||||
* @brief Clear all internal data
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj);
|
std::ostream& operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -4,10 +4,13 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_FLAGS_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_FLAGS_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
class Flags {
|
class Flags {
|
||||||
@@ -20,3 +23,5 @@ namespace audio {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -9,18 +9,12 @@
|
|||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <audio/orchestra/api/Alsa.h>
|
|
||||||
#include <audio/orchestra/api/Android.h>
|
|
||||||
#include <audio/orchestra/api/Asio.h>
|
|
||||||
#include <audio/orchestra/api/Core.h>
|
|
||||||
#include <audio/orchestra/api/CoreIos.h>
|
|
||||||
#include <audio/orchestra/api/Ds.h>
|
|
||||||
#include <audio/orchestra/api/Dummy.h>
|
|
||||||
#include <audio/orchestra/api/Jack.h>
|
|
||||||
#include <audio/orchestra/api/Pulse.h>
|
|
||||||
|
|
||||||
std::vector<std::string> audio::orchestra::Interface::getListApi() {
|
#undef __class__
|
||||||
std::vector<std::string> apis;
|
#define __class__ "Interface"
|
||||||
|
|
||||||
|
std::vector<enum audio::orchestra::type> audio::orchestra::Interface::getCompiledApi() {
|
||||||
|
std::vector<enum audio::orchestra::type> apis;
|
||||||
// The order here will control the order of RtAudio's API search in
|
// The order here will control the order of RtAudio's API search in
|
||||||
// the constructor.
|
// the constructor.
|
||||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||||
@@ -31,14 +25,15 @@ std::vector<std::string> audio::orchestra::Interface::getListApi() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void audio::orchestra::Interface::openApi(const std::string& _api) {
|
void audio::orchestra::Interface::openRtApi(enum audio::orchestra::type _api) {
|
||||||
m_api.reset();
|
delete m_rtapi;
|
||||||
|
m_rtapi = nullptr;
|
||||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||||
ATA_INFO("try open " << m_apiAvaillable[iii].first);
|
ATA_INFO("try open " << m_apiAvaillable[iii].first);
|
||||||
if (_api == m_apiAvaillable[iii].first) {
|
if (_api == m_apiAvaillable[iii].first) {
|
||||||
ATA_INFO(" ==> call it");
|
ATA_INFO(" ==> call it");
|
||||||
m_api = m_apiAvaillable[iii].second();
|
m_rtapi = m_apiAvaillable[iii].second();
|
||||||
if (m_api != nullptr) {
|
if (m_rtapi != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,101 +44,103 @@ void audio::orchestra::Interface::openApi(const std::string& _api) {
|
|||||||
|
|
||||||
|
|
||||||
audio::orchestra::Interface::Interface() :
|
audio::orchestra::Interface::Interface() :
|
||||||
m_api(nullptr) {
|
m_rtapi(nullptr) {
|
||||||
ATA_DEBUG("Add interface:");
|
ATA_DEBUG("Add interface:");
|
||||||
#if defined(ORCHESTRA_BUILD_JACK)
|
#if defined(ORCHESTRA_BUILD_JACK)
|
||||||
addInterface(audio::orchestra::typeJack, audio::orchestra::api::Jack::create);
|
ATA_DEBUG(" JACK");
|
||||||
|
addInterface(audio::orchestra::type_jack, audio::orchestra::api::Jack::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_ALSA)
|
#if defined(ORCHESTRA_BUILD_ALSA)
|
||||||
addInterface(audio::orchestra::typeAlsa, audio::orchestra::api::Alsa::create);
|
ATA_DEBUG(" ALSA");
|
||||||
|
addInterface(audio::orchestra::type_alsa, audio::orchestra::api::Alsa::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||||
addInterface(audio::orchestra::typePulse, audio::orchestra::api::Pulse::create);
|
ATA_DEBUG(" PULSE");
|
||||||
|
addInterface(audio::orchestra::type_pulse, audio::orchestra::api::Pulse::create);
|
||||||
|
#endif
|
||||||
|
#if defined(ORCHESTRA_BUILD_OSS)
|
||||||
|
ATA_DEBUG(" OSS");
|
||||||
|
addInterface(audio::orchestra::type_oss, audio::orchestra::api::Oss::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_ASIO)
|
#if defined(ORCHESTRA_BUILD_ASIO)
|
||||||
addInterface(audio::orchestra::typeAsio, audio::orchestra::api::Asio::create);
|
ATA_DEBUG(" ASIO");
|
||||||
|
addInterface(audio::orchestra::type_asio, audio::orchestra::api::Asio::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_DS)
|
#if defined(ORCHESTRA_BUILD_DS)
|
||||||
addInterface(audio::orchestra::typeDs, audio::orchestra::api::Ds::create);
|
ATA_DEBUG(" DS");
|
||||||
|
addInterface(audio::orchestra::type_ds, audio::orchestra::api::Ds::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
#if defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
||||||
addInterface(audio::orchestra::typeCoreOSX, audio::orchestra::api::Core::create);
|
ATA_DEBUG(" CORE OSX");
|
||||||
|
addInterface(audio::orchestra::type_coreOSX, audio::orchestra::api::Core::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_IOS_CORE)
|
#if defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||||
addInterface(audio::orchestra::typeCoreIOS, audio::orchestra::api::CoreIos::create);
|
ATA_DEBUG(" CORE IOS");
|
||||||
|
addInterface(audio::orchestra::type_coreIOS, audio::orchestra::api::CoreIos::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_JAVA)
|
#if defined(ORCHESTRA_BUILD_JAVA)
|
||||||
addInterface(audio::orchestra::typeJava, audio::orchestra::api::Android::create);
|
ATA_DEBUG(" JAVA");
|
||||||
|
addInterface(audio::orchestra::type_java, audio::orchestra::api::Android::create);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ORCHESTRA_BUILD_DUMMY)
|
#if defined(ORCHESTRA_BUILD_DUMMY)
|
||||||
addInterface(audio::orchestra::typeDummy, audio::orchestra::api::Dummy::create);
|
ATA_DEBUG(" DUMMY");
|
||||||
|
addInterface(audio::orchestra::type_dummy, audio::orchestra::api::Dummy::create);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::orchestra::Interface::addInterface(const std::string& _api, ememory::SharedPtr<Api> (*_callbackCreate)()) {
|
void audio::orchestra::Interface::addInterface(enum audio::orchestra::type _api, Api* (*_callbackCreate)()) {
|
||||||
m_apiAvaillable.push_back(std::pair<std::string, ememory::SharedPtr<Api> (*)()>(_api, _callbackCreate));
|
m_apiAvaillable.push_back(std::pair<enum audio::orchestra::type, Api* (*)()>(_api, _callbackCreate));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::Interface::clear() {
|
enum audio::orchestra::error audio::orchestra::Interface::instanciate(enum audio::orchestra::type _api) {
|
||||||
ATA_INFO("Clear API ...");
|
|
||||||
if (m_api == nullptr) {
|
|
||||||
ATA_WARNING("Interface NOT started!");
|
|
||||||
return audio::orchestra::error_none;
|
|
||||||
}
|
|
||||||
m_api.reset();
|
|
||||||
return audio::orchestra::error_none;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::Interface::instanciate(const std::string& _api) {
|
|
||||||
ATA_INFO("Instanciate API ...");
|
ATA_INFO("Instanciate API ...");
|
||||||
if (m_api != nullptr) {
|
if (m_rtapi != nullptr) {
|
||||||
ATA_WARNING("Interface already started!");
|
ATA_WARNING("Interface already started ...!");
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
if (_api != audio::orchestra::typeUndefined) {
|
if (_api != audio::orchestra::type_undefined) {
|
||||||
ATA_INFO("API specified : " << _api);
|
ATA_INFO("API specified : " << _api);
|
||||||
// Attempt to open the specified API.
|
// Attempt to open the specified API.
|
||||||
openApi(_api);
|
openRtApi(_api);
|
||||||
if (m_api != nullptr) {
|
if (m_rtapi != nullptr) {
|
||||||
if (m_api->getDeviceCount() != 0) {
|
if (m_rtapi->getDeviceCount() != 0) {
|
||||||
ATA_INFO(" ==> api open");
|
ATA_INFO(" ==> api open");
|
||||||
}
|
}
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
// No compiled support for specified API value. Issue a debug
|
// No compiled support for specified API value. Issue a debug
|
||||||
// warning and continue as if no API was specified.
|
// warning and continue as if no API was specified.
|
||||||
ATA_ERROR("API NOT Supported '" << _api << "' not in " << getListApi());
|
ATA_ERROR("RtAudio: no compiled support for specified API argument!");
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
ATA_INFO("Auto choice API :");
|
ATA_INFO("Auto choice API :");
|
||||||
// Iterate through the compiled APIs and return as soon as we find
|
// Iterate through the compiled APIs and return as soon as we find
|
||||||
// one with at least one device or we reach the end of the list.
|
// one with at least one device or we reach the end of the list.
|
||||||
std::vector<std::string> apis = getListApi();
|
std::vector<enum audio::orchestra::type> apis = getCompiledApi();
|
||||||
ATA_INFO(" find : " << apis.size() << " apis.");
|
ATA_INFO(" find : " << apis.size() << " apis.");
|
||||||
for (size_t iii=0; iii<apis.size(); ++iii) {
|
for (size_t iii=0; iii<apis.size(); ++iii) {
|
||||||
ATA_INFO("try open ...");
|
ATA_INFO("try open ...");
|
||||||
openApi(apis[iii]);
|
openRtApi(apis[iii]);
|
||||||
if(m_api == nullptr) {
|
if(m_rtapi == nullptr) {
|
||||||
ATA_ERROR(" ==> can not create ...");
|
ATA_ERROR(" ==> can not create ...");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (m_api->getDeviceCount() != 0) {
|
if (m_rtapi->getDeviceCount() != 0) {
|
||||||
ATA_INFO(" ==> api open");
|
ATA_INFO(" ==> api open");
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
ATA_INFO(" ==> Interface exist, but have no devices: " << m_api->getDeviceCount());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_api != nullptr) {
|
if (m_rtapi != nullptr) {
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
ATA_ERROR("API NOT Supported '" << _api << "' not in " << getListApi());
|
ATA_ERROR("RtAudio: no compiled API support found ... critical error!!");
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::Interface::~Interface() {
|
audio::orchestra::Interface::~Interface() {
|
||||||
ATA_INFO("Remove interface");
|
ATA_INFO("Remove interface");
|
||||||
m_api.reset();
|
delete m_rtapi;
|
||||||
|
m_rtapi = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orchestra::StreamParameters* _outputParameters,
|
enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||||
@@ -153,10 +150,10 @@ enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orch
|
|||||||
uint32_t* _bufferFrames,
|
uint32_t* _bufferFrames,
|
||||||
audio::orchestra::AirTAudioCallback _callback,
|
audio::orchestra::AirTAudioCallback _callback,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::error_inputNull;
|
return audio::orchestra::error_inputNull;
|
||||||
}
|
}
|
||||||
return m_api->openStream(_outputParameters,
|
return m_rtapi->openStream(_outputParameters,
|
||||||
_inputParameters,
|
_inputParameters,
|
||||||
_format,
|
_format,
|
||||||
_sampleRate,
|
_sampleRate,
|
||||||
@@ -166,22 +163,22 @@ enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orch
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::Interface::isMasterOf(audio::orchestra::Interface& _interface) {
|
bool audio::orchestra::Interface::isMasterOf(audio::orchestra::Interface& _interface) {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
ATA_ERROR("Current Master API is nullptr ...");
|
ATA_ERROR("Current Master API is nullptr ...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_interface.m_api == nullptr) {
|
if (_interface.m_rtapi == nullptr) {
|
||||||
ATA_ERROR("Current Slave API is nullptr ...");
|
ATA_ERROR("Current Slave API is nullptr ...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_api->getCurrentApi() != _interface.m_api->getCurrentApi()) {
|
if (m_rtapi->getCurrentApi() != _interface.m_rtapi->getCurrentApi()) {
|
||||||
ATA_ERROR("Can not link 2 Interface with not the same Low level type (?)");//" << _interface.m_adac->getCurrentApi() << " != " << m_adac->getCurrentApi() << ")");
|
ATA_ERROR("Can not link 2 Interface with not the same Low level type (?)");//" << _interface.m_adac->getCurrentApi() << " != " << m_adac->getCurrentApi() << ")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_api->getCurrentApi() != audio::orchestra::typeAlsa) {
|
if (m_rtapi->getCurrentApi() != audio::orchestra::type_alsa) {
|
||||||
ATA_ERROR("Link 2 device together work only if the interafec is ?");// << audio::orchestra::type::alsa << " not for " << m_api->getCurrentApi());
|
ATA_ERROR("Link 2 device together work only if the interafec is ?");// << audio::orchestra::type_alsa << " not for " << m_rtapi->getCurrentApi());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_api->isMasterOf(_interface.m_api);
|
return m_rtapi->isMasterOf(_interface.m_rtapi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,13 +4,25 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_INTERFACE_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_INTERFACE_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <audio/orchestra/base.h>
|
#include <audio/orchestra/base.h>
|
||||||
#include <audio/orchestra/CallbackInfo.h>
|
#include <audio/orchestra/CallbackInfo.h>
|
||||||
#include <audio/orchestra/Api.h>
|
#include <audio/orchestra/Api.h>
|
||||||
|
#include <audio/orchestra/api/Alsa.h>
|
||||||
|
#include <audio/orchestra/api/Android.h>
|
||||||
|
#include <audio/orchestra/api/Asio.h>
|
||||||
|
#include <audio/orchestra/api/Core.h>
|
||||||
|
#include <audio/orchestra/api/CoreIos.h>
|
||||||
|
#include <audio/orchestra/api/Ds.h>
|
||||||
|
#include <audio/orchestra/api/Dummy.h>
|
||||||
|
#include <audio/orchestra/api/Jack.h>
|
||||||
|
#include <audio/orchestra/api/Oss.h>
|
||||||
|
#include <audio/orchestra/api/Pulse.h>
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -26,27 +38,25 @@ namespace audio {
|
|||||||
*/
|
*/
|
||||||
class Interface {
|
class Interface {
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::pair<std::string, ememory::SharedPtr<Api> (*)()> > m_apiAvaillable;
|
std::vector<std::pair<enum audio::orchestra::type, Api* (*)()> > m_apiAvaillable;
|
||||||
protected:
|
protected:
|
||||||
ememory::SharedPtr<audio::orchestra::Api> m_api;
|
audio::orchestra::Api *m_rtapi;
|
||||||
public:
|
public:
|
||||||
void setName(const std::string& _name) {
|
void setName(const std::string& _name) {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_api->setName(_name);
|
m_rtapi->setName(_name);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the list of all availlable API in the system.
|
* @brief A static function to determine the available compiled audio APIs.
|
||||||
* @return the list of all APIs
|
*
|
||||||
|
* The values returned in the std::vector can be compared against
|
||||||
|
* the enumerated list values. Note that there can be more than one
|
||||||
|
* API compiled for certain operating systems.
|
||||||
*/
|
*/
|
||||||
std::vector<std::string> getListApi();
|
std::vector<enum audio::orchestra::type> getCompiledApi();
|
||||||
/**
|
|
||||||
* @brief Add an interface of the Possible List.
|
|
||||||
* @param[in] _api Type of the interface.
|
|
||||||
* @param[in] _callbackCreate API creation callback.
|
|
||||||
*/
|
|
||||||
void addInterface(const std::string& _api, ememory::SharedPtr<Api> (*_callbackCreate)());
|
|
||||||
/**
|
/**
|
||||||
* @brief The class constructor.
|
* @brief The class constructor.
|
||||||
* @note the creating of the basic instance is done by Instanciate
|
* @note the creating of the basic instance is done by Instanciate
|
||||||
@@ -60,21 +70,23 @@ namespace audio {
|
|||||||
*/
|
*/
|
||||||
virtual ~Interface();
|
virtual ~Interface();
|
||||||
/**
|
/**
|
||||||
* @brief Clear the current Interface
|
* @brief Add an interface of the Possible List.
|
||||||
|
* @param[in] _api Type of the interface.
|
||||||
|
* @param[in] _callbackCreate API creation callback.
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error clear();
|
void addInterface(enum audio::orchestra::type _api, Api* (*_callbackCreate)());
|
||||||
/**
|
/**
|
||||||
* @brief Create an interface instance
|
* @brief Create an interface instance
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error instanciate(const std::string& _api = audio::orchestra::typeUndefined);
|
enum audio::orchestra::error instanciate(enum audio::orchestra::type _api = audio::orchestra::type_undefined);
|
||||||
/**
|
/**
|
||||||
* @return the audio API specifier for the current instance of airtaudio.
|
* @return the audio API specifier for the current instance of airtaudio.
|
||||||
*/
|
*/
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::typeUndefined;
|
return audio::orchestra::type_undefined;
|
||||||
}
|
}
|
||||||
return m_api->getCurrentApi();
|
return m_rtapi->getCurrentApi();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief A public function that queries for the number of audio devices available.
|
* @brief A public function that queries for the number of audio devices available.
|
||||||
@@ -84,10 +96,10 @@ namespace audio {
|
|||||||
* a system error occurs during processing, a warning will be issued.
|
* a system error occurs during processing, a warning will be issued.
|
||||||
*/
|
*/
|
||||||
uint32_t getDeviceCount() {
|
uint32_t getDeviceCount() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_api->getDeviceCount();
|
return m_rtapi->getDeviceCount();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Any device integer between 0 and getDeviceCount() - 1 is valid.
|
* @brief Any device integer between 0 and getDeviceCount() - 1 is valid.
|
||||||
@@ -101,17 +113,17 @@ namespace audio {
|
|||||||
* @return An audio::orchestra::DeviceInfo structure for a specified device number.
|
* @return An audio::orchestra::DeviceInfo structure for a specified device number.
|
||||||
*/
|
*/
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) {
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::DeviceInfo();
|
return audio::orchestra::DeviceInfo();
|
||||||
}
|
}
|
||||||
return m_api->getDeviceInfo(_device);
|
return m_rtapi->getDeviceInfo(_device);
|
||||||
}
|
}
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(const std::string& _deviceName) {
|
audio::orchestra::DeviceInfo getDeviceInfo(const std::string& _deviceName) {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::DeviceInfo();
|
return audio::orchestra::DeviceInfo();
|
||||||
}
|
}
|
||||||
audio::orchestra::DeviceInfo info;
|
audio::orchestra::DeviceInfo info;
|
||||||
m_api->getNamedDeviceInfo(_deviceName, info);
|
m_rtapi->getNamedDeviceInfo(_deviceName, info);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -124,10 +136,10 @@ namespace audio {
|
|||||||
* before attempting to open a stream.
|
* before attempting to open a stream.
|
||||||
*/
|
*/
|
||||||
uint32_t getDefaultOutputDevice() {
|
uint32_t getDefaultOutputDevice() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_api->getDefaultOutputDevice();
|
return m_rtapi->getDefaultOutputDevice();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief A function that returns the index of the default input device.
|
* @brief A function that returns the index of the default input device.
|
||||||
@@ -139,10 +151,10 @@ namespace audio {
|
|||||||
* before attempting to open a stream.
|
* before attempting to open a stream.
|
||||||
*/
|
*/
|
||||||
uint32_t getDefaultInputDevice() {
|
uint32_t getDefaultInputDevice() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_api->getDefaultInputDevice();
|
return m_rtapi->getDefaultInputDevice();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief A public function for opening a stream with the specified parameters.
|
* @brief A public function for opening a stream with the specified parameters.
|
||||||
@@ -197,10 +209,10 @@ namespace audio {
|
|||||||
* returns (no exception is thrown).
|
* returns (no exception is thrown).
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error closeStream() {
|
enum audio::orchestra::error closeStream() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::error_inputNull;
|
return audio::orchestra::error_inputNull;
|
||||||
}
|
}
|
||||||
return m_api->closeStream();
|
return m_rtapi->closeStream();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief A function that starts a stream.
|
* @brief A function that starts a stream.
|
||||||
@@ -211,10 +223,10 @@ namespace audio {
|
|||||||
* running.
|
* running.
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error startStream() {
|
enum audio::orchestra::error startStream() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::error_inputNull;
|
return audio::orchestra::error_inputNull;
|
||||||
}
|
}
|
||||||
return m_api->startStream();
|
return m_rtapi->startStream();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Stop a stream, allowing any samples remaining in the output queue to be played.
|
* @brief Stop a stream, allowing any samples remaining in the output queue to be played.
|
||||||
@@ -225,10 +237,10 @@ namespace audio {
|
|||||||
* stopped.
|
* stopped.
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error stopStream() {
|
enum audio::orchestra::error stopStream() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::error_inputNull;
|
return audio::orchestra::error_inputNull;
|
||||||
}
|
}
|
||||||
return m_api->stopStream();
|
return m_rtapi->stopStream();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Stop a stream, discarding any samples remaining in the input/output queue.
|
* @brief Stop a stream, discarding any samples remaining in the input/output queue.
|
||||||
@@ -238,38 +250,38 @@ namespace audio {
|
|||||||
* stopped.
|
* stopped.
|
||||||
*/
|
*/
|
||||||
enum audio::orchestra::error abortStream() {
|
enum audio::orchestra::error abortStream() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::orchestra::error_inputNull;
|
return audio::orchestra::error_inputNull;
|
||||||
}
|
}
|
||||||
return m_api->abortStream();
|
return m_rtapi->abortStream();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return true if a stream is open and false if not.
|
* @return true if a stream is open and false if not.
|
||||||
*/
|
*/
|
||||||
bool isStreamOpen() const {
|
bool isStreamOpen() const {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_api->isStreamOpen();
|
return m_rtapi->isStreamOpen();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return true if the stream is running and false if it is stopped or not open.
|
* @return true if the stream is running and false if it is stopped or not open.
|
||||||
*/
|
*/
|
||||||
bool isStreamRunning() const {
|
bool isStreamRunning() const {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_api->isStreamRunning();
|
return m_rtapi->isStreamRunning();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
|
* @brief If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
|
||||||
* @return the number of elapsed seconds since the stream was started.
|
* @return the number of elapsed seconds since the stream was started.
|
||||||
*/
|
*/
|
||||||
audio::Time getStreamTime() {
|
audio::Time getStreamTime() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return audio::Time();
|
return audio::Time();
|
||||||
}
|
}
|
||||||
return m_api->getStreamTime();
|
return m_rtapi->getStreamTime();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief The stream latency refers to delay in audio input and/or output
|
* @brief The stream latency refers to delay in audio input and/or output
|
||||||
@@ -281,10 +293,10 @@ namespace audio {
|
|||||||
* @return The internal stream latency in sample frames.
|
* @return The internal stream latency in sample frames.
|
||||||
*/
|
*/
|
||||||
long getStreamLatency() {
|
long getStreamLatency() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_api->getStreamLatency();
|
return m_rtapi->getStreamLatency();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief On some systems, the sample rate used may be slightly different
|
* @brief On some systems, the sample rate used may be slightly different
|
||||||
@@ -293,15 +305,16 @@ namespace audio {
|
|||||||
* @return Returns actual sample rate in use by the stream.
|
* @return Returns actual sample rate in use by the stream.
|
||||||
*/
|
*/
|
||||||
uint32_t getStreamSampleRate() {
|
uint32_t getStreamSampleRate() {
|
||||||
if (m_api == nullptr) {
|
if (m_rtapi == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_api->getStreamSampleRate();
|
return m_rtapi->getStreamSampleRate();
|
||||||
}
|
}
|
||||||
bool isMasterOf(audio::orchestra::Interface& _interface);
|
bool isMasterOf(audio::orchestra::Interface& _interface);
|
||||||
protected:
|
protected:
|
||||||
void openApi(const std::string& _api);
|
void openRtApi(enum audio::orchestra::type _api);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -4,15 +4,18 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_STREAM_OPTION_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_STREAM_OPTION_H__
|
||||||
|
|
||||||
#include <audio/orchestra/Flags.h>
|
#include <audio/orchestra/Flags.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
enum timestampMode {
|
enum timestampMode {
|
||||||
timestampMode_Hardware, //!< enable harware timestamp
|
timestampMode_Hardware, //!< enable harware timestamp
|
||||||
timestampMode_trigered, //!< get harware triger time stamp and increment with duration
|
timestampMode_trigered, //!< get harware triger time stamp and ingrement with duration
|
||||||
timestampMode_soft, //!< Simulate all timestamp.
|
timestampMode_soft, //!< Simulate all timestamp.
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::timestampMode _obj);
|
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::timestampMode _obj);
|
||||||
@@ -32,3 +35,5 @@ namespace audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -4,7 +4,10 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_STREAM_PARAMETER_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_STREAM_PARAMETER_H__
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -28,3 +31,5 @@ namespace audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef ORCHESTRA_BUILD_ALSA
|
#if !defined(__AUDIO_ORCHESTRA_API_ALSA_H__) && defined(ORCHESTRA_BUILD_ALSA)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_ALSA_H__
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -14,12 +14,12 @@ namespace audio {
|
|||||||
class AlsaPrivate;
|
class AlsaPrivate;
|
||||||
class Alsa: public audio::orchestra::Api {
|
class Alsa: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Alsa();
|
Alsa();
|
||||||
virtual ~Alsa();
|
virtual ~Alsa();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeAlsa;
|
return audio::orchestra::type_alsa;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
private:
|
private:
|
||||||
@@ -27,8 +27,7 @@ namespace audio {
|
|||||||
audio::orchestra::DeviceInfo& _info,
|
audio::orchestra::DeviceInfo& _info,
|
||||||
int32_t _cardId=-1, // Alsa card ID
|
int32_t _cardId=-1, // Alsa card ID
|
||||||
int32_t _subdevice=-1, // alsa subdevice ID
|
int32_t _subdevice=-1, // alsa subdevice ID
|
||||||
int32_t _localDeviceId=-1,// local ID of device find
|
int32_t _localDeviceId=-1); // local ID of device fined
|
||||||
bool _input=false);
|
|
||||||
public:
|
public:
|
||||||
bool getNamedDeviceInfo(const std::string& _deviceName, audio::orchestra::DeviceInfo& _info) {
|
bool getNamedDeviceInfo(const std::string& _deviceName, audio::orchestra::DeviceInfo& _info) {
|
||||||
return getNamedDeviceInfoLocal(_deviceName, _info);
|
return getNamedDeviceInfoLocal(_deviceName, _info);
|
||||||
@@ -43,36 +42,33 @@ namespace audio {
|
|||||||
// which is not a member of RtAudio. External use of this function
|
// which is not a member of RtAudio. External use of this function
|
||||||
// will most likely produce highly undesireable results!
|
// will most likely produce highly undesireable results!
|
||||||
void callbackEvent();
|
void callbackEvent();
|
||||||
void callbackEventOneCycleRead();
|
void callbackEventOneCycle();
|
||||||
void callbackEventOneCycleWrite();
|
|
||||||
void callbackEventOneCycleMMAPRead();
|
|
||||||
void callbackEventOneCycleMMAPWrite();
|
|
||||||
private:
|
private:
|
||||||
static void alsaCallbackEvent(void* _userData);
|
static void alsaCallbackEvent(void* _userData);
|
||||||
private:
|
private:
|
||||||
ememory::SharedPtr<AlsaPrivate> m_private;
|
std11::shared_ptr<AlsaPrivate> m_private;
|
||||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||||
void saveDeviceInfo();
|
void saveDeviceInfo();
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
enum audio::orchestra::mode _mode,
|
enum audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
enum audio::format _format,
|
enum audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
|
|
||||||
bool openName(const std::string& _deviceName,
|
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
virtual audio::Time getStreamTime();
|
virtual audio::Time getStreamTime();
|
||||||
public:
|
public:
|
||||||
bool isMasterOf(ememory::SharedPtr<audio::orchestra::Api> _api);
|
bool isMasterOf(audio::orchestra::Api* _api);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,23 +7,60 @@
|
|||||||
|
|
||||||
#ifdef ORCHESTRA_BUILD_JAVA
|
#ifdef ORCHESTRA_BUILD_JAVA
|
||||||
|
|
||||||
//#include <ewol/context/Context.h>
|
#include <ewol/context/Context.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
#include <audio/orchestra/api/AndroidNativeInterface.h>
|
|
||||||
#include <audio/orchestra/api/Android.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Android::create() {
|
#undef __class__
|
||||||
|
#define __class__ "api::Android"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::Android::create() {
|
||||||
ATA_INFO("Create Android device ... ");
|
ATA_INFO("Create Android device ... ");
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Android>(new audio::orchestra::api::Android());
|
return new audio::orchestra::api::Android();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
audio::orchestra::api::Android::Android() :
|
audio::orchestra::api::Android::Android() {
|
||||||
m_uid(-1) {
|
ATA_INFO("new Android");
|
||||||
ATA_INFO("Create Android interface");
|
// 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, ':');
|
||||||
|
audio::orchestra::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)");
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::api::Android::~Android() {
|
audio::orchestra::api::Android::~Android() {
|
||||||
@@ -32,16 +69,16 @@ audio::orchestra::api::Android::~Android() {
|
|||||||
|
|
||||||
uint32_t audio::orchestra::api::Android::getDeviceCount() {
|
uint32_t audio::orchestra::api::Android::getDeviceCount() {
|
||||||
//ATA_INFO("Get device count:"<< m_devices.size());
|
//ATA_INFO("Get device count:"<< m_devices.size());
|
||||||
return audio::orchestra::api::android::getDeviceCount();
|
return m_devices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::DeviceInfo audio::orchestra::api::Android::getDeviceInfo(uint32_t _device) {
|
audio::orchestra::DeviceInfo audio::orchestra::api::Android::getDeviceInfo(uint32_t _device) {
|
||||||
//ATA_INFO("Get device info ...");
|
//ATA_INFO("Get device info ...");
|
||||||
return audio::orchestra::api::android::getDeviceInfo(_device);
|
return m_devices[_device];
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Android::closeStream() {
|
enum audio::orchestra::error audio::orchestra::api::Android::closeStream() {
|
||||||
ATA_INFO("Close Stream");
|
ATA_INFO("Clese Stream");
|
||||||
// Can not close the stream now...
|
// Can not close the stream now...
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
@@ -51,48 +88,45 @@ enum audio::orchestra::error audio::orchestra::api::Android::startStream() {
|
|||||||
// TODO : Check return ...
|
// TODO : Check return ...
|
||||||
audio::orchestra::Api::startStream();
|
audio::orchestra::Api::startStream();
|
||||||
// Can not close the stream now...
|
// Can not close the stream now...
|
||||||
return audio::orchestra::api::android::startStream(m_uid);
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Android::stopStream() {
|
enum audio::orchestra::error audio::orchestra::api::Android::stopStream() {
|
||||||
ATA_INFO("Stop stream");
|
ATA_INFO("Stop stream");
|
||||||
// Can not close the stream now...
|
ewol::Context& tmpContext = ewol::getContext();
|
||||||
return audio::orchestra::api::android::stopStream(m_uid);
|
tmpContext.audioCloseDevice(0);
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Android::abortStream() {
|
|
||||||
ATA_INFO("Abort Stream");
|
|
||||||
// Can not close the stream now...
|
// Can not close the stream now...
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::error audio::orchestra::api::Android::abortStream() {
|
||||||
|
ATA_INFO("Abort Stream");
|
||||||
|
ewol::Context& tmpContext = ewol::getContext();
|
||||||
|
tmpContext.audioCloseDevice(0);
|
||||||
|
// Can not close the stream now...
|
||||||
|
return audio::orchestra::error_none;
|
||||||
|
}
|
||||||
|
|
||||||
void audio::orchestra::api::Android::playback(int16_t* _dst, int32_t _nbChunk) {
|
void audio::orchestra::api::Android::callBackEvent(void* _data,
|
||||||
// clear output buffer:
|
int32_t _frameRate) {
|
||||||
if (_dst != nullptr) {
|
|
||||||
memset(_dst, 0, _nbChunk*audio::getFormatBytes(m_deviceFormat[modeToIdTable(m_mode)])*m_nDeviceChannels[modeToIdTable(m_mode)]);
|
|
||||||
}
|
|
||||||
int32_t doStopStream = 0;
|
int32_t doStopStream = 0;
|
||||||
audio::Time streamTime = getStreamTime();
|
audio::Time streamTime = getStreamTime();
|
||||||
std::vector<enum audio::orchestra::status> status;
|
std::vector<enum audio::orchestra::status> status;
|
||||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
if (m_doConvertBuffer[audio::orchestra::mode_output] == 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,
|
doStopStream = m_callback(nullptr,
|
||||||
audio::Time(),
|
audio::Time(),
|
||||||
&m_userBuffer[m_mode][0],
|
m_userBuffer[audio::orchestra::mode_output],
|
||||||
streamTime,
|
streamTime,
|
||||||
uint32_t(_nbChunk),
|
_frameRate,
|
||||||
status);
|
status);
|
||||||
convertBuffer((char*)_dst, (char*)&m_userBuffer[audio::orchestra::mode_output][0], m_convertInfo[audio::orchestra::mode_output]);
|
convertBuffer((char*)_data, (char*)m_userBuffer[audio::orchestra::mode_output], m_convertInfo[audio::orchestra::mode_output]);
|
||||||
} else {
|
} else {
|
||||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " pointer=" << int64_t(_dst));
|
doStopStream = m_callback(_data,
|
||||||
doStopStream = m_callback(nullptr,
|
|
||||||
audio::Time(),
|
|
||||||
_dst,
|
|
||||||
streamTime,
|
streamTime,
|
||||||
uint32_t(_nbChunk),
|
nullptr,
|
||||||
|
audio::Time(),
|
||||||
|
_frameRate,
|
||||||
status);
|
status);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (doStopStream == 2) {
|
if (doStopStream == 2) {
|
||||||
abortStream();
|
abortStream();
|
||||||
@@ -101,88 +135,71 @@ void audio::orchestra::api::Android::playback(int16_t* _dst, int32_t _nbChunk) {
|
|||||||
audio::orchestra::Api::tickStreamTime();
|
audio::orchestra::Api::tickStreamTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::orchestra::api::Android::record(int16_t* _dst, int32_t _nbChunk) {
|
void audio::orchestra::api::Android::androidCallBackEvent(void* _data,
|
||||||
int32_t doStopStream = 0;
|
int32_t _frameRate,
|
||||||
audio::Time streamTime = getStreamTime();
|
void* _userData) {
|
||||||
std::vector<enum audio::orchestra::status> status;
|
if (_userData == nullptr) {
|
||||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
ATA_INFO("callback event ... nullptr pointer");
|
||||||
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]));
|
|
||||||
convertBuffer((char*)&m_userBuffer[audio::orchestra::mode_input][0], (char*)_dst, m_convertInfo[audio::orchestra::mode_input]);
|
|
||||||
doStopStream = m_callback(&m_userBuffer[m_mode][0],
|
|
||||||
streamTime,
|
|
||||||
nullptr,
|
|
||||||
audio::Time(),
|
|
||||||
uint32_t(_nbChunk),
|
|
||||||
status);
|
|
||||||
} else {
|
|
||||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " pointer=" << int64_t(_dst));
|
|
||||||
doStopStream = m_callback(_dst,
|
|
||||||
streamTime,
|
|
||||||
nullptr,
|
|
||||||
audio::Time(),
|
|
||||||
uint32_t(_nbChunk),
|
|
||||||
status);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (doStopStream == 2) {
|
|
||||||
abortStream();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
audio::orchestra::Api::tickStreamTime();
|
audio::orchestra::api::Android* myClass = static_cast<audio::orchestra::api::Android*>(_userData);
|
||||||
|
myClass->callBackEvent(_data, _frameRate/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Android::open(uint32_t _device,
|
bool audio::orchestra::api::Android::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
bool ret = false;
|
|
||||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||||
m_mode = _mode;
|
if (_mode != audio::orchestra::mode_output) {
|
||||||
|
ATA_ERROR("Can not start a device input or duplex for Android ...");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
m_userFormat = _format;
|
m_userFormat = _format;
|
||||||
m_nUserChannels[modeToIdTable(m_mode)] = _channels;
|
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||||
|
ewol::Context& tmpContext = ewol::getContext();
|
||||||
m_uid = audio::orchestra::api::android::open(_device, m_mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, ememory::staticPointerCast<audio::orchestra::api::Android>(sharedFromThis()));
|
bool ret = false;
|
||||||
if (m_uid < 0) {
|
if (_format == SINT8) {
|
||||||
ret = false;
|
ret = tmpContext.audioOpenDevice(_device, _sampleRate, _channels, 0, androidCallBackEvent, this);
|
||||||
} else {
|
} else {
|
||||||
ret = true;
|
ret = tmpContext.audioOpenDevice(_device, _sampleRate, _channels, 1, androidCallBackEvent, this);
|
||||||
}
|
}
|
||||||
m_bufferSize = 256;
|
m_bufferSize = 256;
|
||||||
m_sampleRate = _sampleRate;
|
m_sampleRate = _sampleRate;
|
||||||
m_doByteSwap[modeToIdTable(m_mode)] = false; // for endienness ...
|
m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ...
|
||||||
|
|
||||||
// TODO : For now, we write it in hard ==> to bu update later ...
|
// TODO : For now, we write it in hard ==> to bu update later ...
|
||||||
m_deviceFormat[modeToIdTable(m_mode)] = audio::format_int16;
|
m_deviceFormat[modeToIdTable(_mode)] = SINT16;
|
||||||
m_nDeviceChannels[modeToIdTable(m_mode)] = 2;
|
m_nDeviceChannels[modeToIdTable(_mode)] = 2;
|
||||||
m_deviceInterleaved[modeToIdTable(m_mode)] = true;
|
m_deviceInterleaved[modeToIdTable(_mode)] = true;
|
||||||
|
|
||||||
m_doConvertBuffer[modeToIdTable(m_mode)] = false;
|
m_doConvertBuffer[modeToIdTable(_mode)] = false;
|
||||||
if (m_userFormat != m_deviceFormat[modeToIdTable(m_mode)]) {
|
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
|
||||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||||
}
|
}
|
||||||
if (m_nUserChannels[modeToIdTable(m_mode)] < m_nDeviceChannels[modeToIdTable(m_mode)]) {
|
if (m_nUserChannels[modeToIdTable(_mode)] < m_nDeviceChannels[modeToIdTable(_mode)]) {
|
||||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||||
}
|
}
|
||||||
if ( m_deviceInterleaved[modeToIdTable(m_mode)] == false
|
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
|
||||||
&& m_nUserChannels[modeToIdTable(m_mode)] > 1) {
|
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
|
||||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||||
}
|
}
|
||||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
if (m_doConvertBuffer[modeToIdTable(_mode)] == true) {
|
||||||
// Allocate necessary internal buffers.
|
// Allocate necessary internal buffers.
|
||||||
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(m_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||||
m_userBuffer[modeToIdTable(m_mode)].resize(bufferBytes);
|
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_userBuffer[modeToIdTable(m_mode)].size() == 0) {
|
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) {
|
||||||
ATA_ERROR("error allocating user buffer memory.");
|
ATA_ERROR("audio::orchestra::api::Android::probeDeviceOpen: error allocating user buffer memory.");
|
||||||
}
|
}
|
||||||
setConvertInfo(m_mode, _firstChannel);
|
setConvertInfo(_mode, _firstChannel);
|
||||||
}
|
}
|
||||||
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(m_mode)] << " user format : " << m_userFormat);
|
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(_mode)] << " user format : " << m_userFormat);
|
||||||
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(m_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(m_mode)]);
|
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(_mode)]);
|
||||||
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(m_mode)]);
|
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(_mode)]);
|
||||||
if (ret == false) {
|
if (ret == false) {
|
||||||
ATA_ERROR("Can not open device.");
|
ATA_ERROR("Can not open device.");
|
||||||
}
|
}
|
||||||
|
@@ -2,24 +2,23 @@
|
|||||||
* @author Edouard DUPIN
|
* @author Edouard DUPIN
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef ORCHESTRA_BUILD_JAVA
|
#if !defined(__AUDIO_ORCHESTRA_API_ANDROID_H__) && defined(ORCHESTRA_BUILD_JAVA)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_ANDROID_H__
|
||||||
#include <audio/orchestra/Interface.h>
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
namespace api {
|
namespace api {
|
||||||
class Android: public audio::orchestra::Api {
|
class Android: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Android();
|
Android();
|
||||||
virtual ~Android();
|
virtual ~Android();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeJava;
|
return audio::orchestra::type_java;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -32,26 +31,23 @@ namespace audio {
|
|||||||
// which is not a member of RtAudio. External use of this function
|
// which is not a member of RtAudio. External use of this function
|
||||||
// will most likely produce highly undesireable results!
|
// will most likely produce highly undesireable results!
|
||||||
void callbackEvent();
|
void callbackEvent();
|
||||||
private:
|
|
||||||
int32_t m_uid;
|
|
||||||
public:
|
|
||||||
int32_t getUId() {
|
|
||||||
return m_uid;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||||
void saveDeviceInfo();
|
void saveDeviceInfo();
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
public:
|
private:
|
||||||
void playback(int16_t* _dst, int32_t _nbChunk);
|
void callBackEvent(void* _data,
|
||||||
void record(int16_t* _dst, int32_t _nbChunk);
|
int32_t _frameRate);
|
||||||
|
static void androidCallBackEvent(void* _data,
|
||||||
|
int32_t _frameRate,
|
||||||
|
void* _userData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,540 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <audio/orchestra/debug.h>
|
|
||||||
#include <audio/orchestra/error.h>
|
|
||||||
#include <audio/orchestra/api/AndroidNativeInterface.h>
|
|
||||||
#include <audio/orchestra/api/Android.h>
|
|
||||||
/* include auto generated file */
|
|
||||||
#include <org_musicdsp_orchestra_OrchestraConstants.h>
|
|
||||||
#include <jvm-basics/jvm-basics.h>
|
|
||||||
#include <ememory/memory.h>
|
|
||||||
#include <ejson/ejson.h>
|
|
||||||
|
|
||||||
class AndroidOrchestraContext {
|
|
||||||
public:
|
|
||||||
// get a resources from the java environement :
|
|
||||||
JNIEnv* m_JavaVirtualMachinePointer; //!< the JVM
|
|
||||||
jclass m_javaClassOrchestra; //!< main activity class (android ...)
|
|
||||||
jclass m_javaClassOrchestraCallback;
|
|
||||||
jobject m_javaObjectOrchestraCallback;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceCount;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceProperty;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceInput;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceOutput;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioCloseDevice;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioStart;
|
|
||||||
jmethodID m_javaMethodOrchestraActivityAudioStop;
|
|
||||||
jclass m_javaDefaultClassString; //!< default string class
|
|
||||||
private:
|
|
||||||
bool safeInitMethodID(jmethodID& _mid, jclass& _cls, const char* _name, const char* _sign) {
|
|
||||||
_mid = m_JavaVirtualMachinePointer->GetMethodID(_cls, _name, _sign);
|
|
||||||
if(_mid == nullptr) {
|
|
||||||
ATA_ERROR("C->java : Can't find the method " << _name);
|
|
||||||
/* remove access on the virtual machine : */
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool java_attach_current_thread(int *_rstatus) {
|
|
||||||
ATA_DEBUG("C->java : call java");
|
|
||||||
if (jvm_basics::getJavaVM() == nullptr) {
|
|
||||||
ATA_ERROR("C->java : JVM not initialised");
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*_rstatus = jvm_basics::getJavaVM()->GetEnv((void **) &m_JavaVirtualMachinePointer, JNI_VERSION_1_6);
|
|
||||||
if (*_rstatus == JNI_EDETACHED) {
|
|
||||||
JavaVMAttachArgs lJavaVMAttachArgs;
|
|
||||||
lJavaVMAttachArgs.version = JNI_VERSION_1_6;
|
|
||||||
lJavaVMAttachArgs.name = "EwolNativeThread";
|
|
||||||
lJavaVMAttachArgs.group = nullptr;
|
|
||||||
int status = jvm_basics::getJavaVM()->AttachCurrentThread(&m_JavaVirtualMachinePointer, &lJavaVMAttachArgs);
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
if (status != JNI_OK) {
|
|
||||||
ATA_ERROR("C->java : AttachCurrentThread failed : " << status);
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void java_detach_current_thread(int _status) {
|
|
||||||
if(_status == JNI_EDETACHED) {
|
|
||||||
jvm_basics::getJavaVM()->DetachCurrentThread();
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AndroidOrchestraContext(JNIEnv* _env, jclass _classBase, jobject _objCallback) :
|
|
||||||
m_JavaVirtualMachinePointer(nullptr),
|
|
||||||
m_javaClassOrchestra(0),
|
|
||||||
m_javaClassOrchestraCallback(0),
|
|
||||||
m_javaObjectOrchestraCallback(0),
|
|
||||||
|
|
||||||
m_javaMethodOrchestraActivityAudioGetDeviceCount(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioGetDeviceProperty(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioOpenDeviceInput(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioOpenDeviceOutput(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioCloseDevice(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioStart(0),
|
|
||||||
m_javaMethodOrchestraActivityAudioStop(0),
|
|
||||||
m_javaDefaultClassString(0) {
|
|
||||||
ATA_DEBUG("*******************************************");
|
|
||||||
ATA_DEBUG("** set JVM Pointer (orchestra) **");
|
|
||||||
ATA_DEBUG("*******************************************");
|
|
||||||
m_JavaVirtualMachinePointer = _env;
|
|
||||||
// get default needed all time elements :
|
|
||||||
if (m_JavaVirtualMachinePointer == nullptr) {
|
|
||||||
ATA_ERROR("C->java: NULLPTR jvm interface");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ATA_DEBUG("C->java: try load org/musicdsp/orchestra/OrchestraNative class");
|
|
||||||
m_javaClassOrchestra = m_JavaVirtualMachinePointer->FindClass("org/musicdsp/orchestra/OrchestraNative" );
|
|
||||||
if (m_javaClassOrchestra == 0) {
|
|
||||||
ATA_ERROR("C->java : Can't find org/musicdsp/orchestra/OrchestraNative class");
|
|
||||||
// remove access on the virtual machine :
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* The object field extends Activity and implement OrchestraCallback */
|
|
||||||
m_javaClassOrchestraCallback = m_JavaVirtualMachinePointer->GetObjectClass(_objCallback);
|
|
||||||
if(m_javaClassOrchestraCallback == nullptr) {
|
|
||||||
ATA_ERROR("C->java : Can't find org/musicdsp/orchestra/OrchestraManagerCallback class");
|
|
||||||
// remove access on the virtual machine :
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool functionCallbackIsMissing = false;
|
|
||||||
bool ret= false;
|
|
||||||
|
|
||||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioGetDeviceCount,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"getDeviceCount",
|
|
||||||
"()I");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
ATA_ERROR("system can not start without function : getDeviceCount");
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioGetDeviceProperty,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"getDeviceProperty",
|
|
||||||
"(I)Ljava/lang/String;");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
ATA_ERROR("system can not start without function : getDeviceProperty");
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDeviceInput,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"openDeviceInput",
|
|
||||||
"(IIII)I");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
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,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"closeDevice",
|
|
||||||
"(I)Z");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
ATA_ERROR("system can not start without function : closeDevice");
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioStart,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"start",
|
|
||||||
"(I)Z");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
ATA_ERROR("system can not start without function : start");
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioStop,
|
|
||||||
m_javaClassOrchestraCallback,
|
|
||||||
"stop",
|
|
||||||
"(I)Z");
|
|
||||||
if (ret == false) {
|
|
||||||
jvm_basics::checkExceptionJavaVM(_env);
|
|
||||||
ATA_ERROR("system can not start without function : stop");
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
m_javaObjectOrchestraCallback = _env->NewGlobalRef(_objCallback);
|
|
||||||
if (m_javaObjectOrchestraCallback == nullptr) {
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_javaDefaultClassString = m_JavaVirtualMachinePointer->FindClass("java/lang/String" );
|
|
||||||
if (m_javaDefaultClassString == 0) {
|
|
||||||
ATA_ERROR("C->java : Can't find java/lang/String" );
|
|
||||||
// remove access on the virtual machine :
|
|
||||||
m_JavaVirtualMachinePointer = nullptr;
|
|
||||||
functionCallbackIsMissing = true;
|
|
||||||
}
|
|
||||||
if (functionCallbackIsMissing == true) {
|
|
||||||
ATA_CRITICAL(" mission one function ==> system can not work withut it...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~AndroidOrchestraContext() {
|
|
||||||
// TODO ...
|
|
||||||
}
|
|
||||||
|
|
||||||
void unInit(JNIEnv* _env) {
|
|
||||||
_env->DeleteGlobalRef(m_javaObjectOrchestraCallback);
|
|
||||||
m_javaObjectOrchestraCallback = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getDeviceCount() {
|
|
||||||
// Request the clipBoard :
|
|
||||||
ATA_WARNING("C->java : audio get device count");
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ATA_DEBUG("Call CallIntMethod ...");
|
|
||||||
//Call java ...
|
|
||||||
jint ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioGetDeviceCount);
|
|
||||||
// manage execption :
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
java_detach_current_thread(status);
|
|
||||||
ATA_WARNING(" find " << (uint32_t)ret << " IO");
|
|
||||||
return (uint32_t)ret;
|
|
||||||
}
|
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _idDevice) {
|
|
||||||
audio::orchestra::DeviceInfo info;
|
|
||||||
// Request the clipBoard :
|
|
||||||
ATA_WARNING("C->java : audio get device info " << _idDevice);
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
//Call java ...
|
|
||||||
jstring returnString = (jstring) m_JavaVirtualMachinePointer->CallObjectMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioGetDeviceProperty, _idDevice);
|
|
||||||
const char *js = m_JavaVirtualMachinePointer->GetStringUTFChars(returnString, nullptr);
|
|
||||||
std::string retString(js);
|
|
||||||
m_JavaVirtualMachinePointer->ReleaseStringUTFChars(returnString, js);
|
|
||||||
//m_JavaVirtualMachinePointer->DeleteLocalRef(returnString);
|
|
||||||
// manage execption :
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
java_detach_current_thread(status);
|
|
||||||
ATA_WARNING("get device information : " << retString);
|
|
||||||
ejson::Document doc;
|
|
||||||
if (doc.parse(retString) == false) {
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
info.name = doc.getStringValue("name", "no-name");
|
|
||||||
if (doc.getStringValue("type", "output") == "output") {
|
|
||||||
info.input = false;
|
|
||||||
} else {
|
|
||||||
info.input = true;
|
|
||||||
}
|
|
||||||
ememory::SharedPtr<const ejson::Array> list = doc.getArray("sample-rate");
|
|
||||||
if (list != nullptr) {
|
|
||||||
for (size_t iii=0; iii<list->size(); ++iii) {
|
|
||||||
info.sampleRates.push_back(int32_t(list->getNumberValue(iii, 48000)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list = doc.getArray("channels");
|
|
||||||
if (list != nullptr) {
|
|
||||||
for (size_t iii=0; iii<list->size(); ++iii) {
|
|
||||||
info.channels.push_back(audio::getChannelFromString(list->getStringValue(iii, "???")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list = doc.getArray("format");
|
|
||||||
if (list != nullptr) {
|
|
||||||
for (size_t iii=0; iii<list->size(); ++iii) {
|
|
||||||
info.nativeFormats.push_back(audio::getFormatFromString(list->getStringValue(iii, "???")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info.isDefault = doc.getBooleanValue("default", false);
|
|
||||||
info.isCorrect = true;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::vector<ememory::WeakPtr<audio::orchestra::api::Android> > m_instanceList; // list of connected handle ...
|
|
||||||
//AndroidAudioCallback m_audioCallBack;
|
|
||||||
//void* m_audioCallBackUserData;
|
|
||||||
public:
|
|
||||||
int32_t open(uint32_t _idDevice,
|
|
||||||
audio::orchestra::mode _mode,
|
|
||||||
uint32_t _channels,
|
|
||||||
uint32_t _firstChannel,
|
|
||||||
uint32_t _sampleRate,
|
|
||||||
audio::format _format,
|
|
||||||
uint32_t *_bufferSize,
|
|
||||||
const audio::orchestra::StreamOptions& _options,
|
|
||||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance) {
|
|
||||||
ATA_DEBUG("C->java : audio open device");
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
//Call java ...
|
|
||||||
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 (int32_t(ret) >= 0) {
|
|
||||||
m_instanceList.push_back(_instance);
|
|
||||||
return int32_t(ret);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
enum audio::orchestra::error closeStream(int32_t _id) {
|
|
||||||
ATA_DEBUG("C->java : audio close device");
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
//Call java ...
|
|
||||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioCloseDevice, _id);
|
|
||||||
// manage execption :
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
java_detach_current_thread(status);
|
|
||||||
if (bool(ret) == false) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return audio::orchestra::error_none;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error startStream(int32_t _id) {
|
|
||||||
ATA_DEBUG("C->java : audio start device");
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
//Call java ...
|
|
||||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioStart, _id);
|
|
||||||
// manage execption :
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
java_detach_current_thread(status);
|
|
||||||
if (bool(ret) == false) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return audio::orchestra::error_none;
|
|
||||||
}
|
|
||||||
enum audio::orchestra::error stopStream(int32_t _id) {
|
|
||||||
|
|
||||||
ATA_DEBUG("C->java : audio close device");
|
|
||||||
int status;
|
|
||||||
if(!java_attach_current_thread(&status)) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
//Call java ...
|
|
||||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioStop, _id);
|
|
||||||
// manage execption :
|
|
||||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
|
||||||
java_detach_current_thread(status);
|
|
||||||
if (bool(ret) == false) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return audio::orchestra::error_none;
|
|
||||||
}
|
|
||||||
enum audio::orchestra::error abortStream(int32_t _id) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
void playback(int32_t _id, int16_t* _dst, int32_t _nbChunk) {
|
|
||||||
auto it = m_instanceList.begin();
|
|
||||||
while (it != m_instanceList.end()) {
|
|
||||||
auto elem = it->lock();
|
|
||||||
if (elem == nullptr) {
|
|
||||||
it = m_instanceList.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (elem->getUId() == _id) {
|
|
||||||
elem->playback(_dst, _nbChunk);
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void record(int32_t _id, int16_t* _dst, int32_t _nbChunk) {
|
|
||||||
auto it = m_instanceList.begin();
|
|
||||||
while (it != m_instanceList.end()) {
|
|
||||||
auto elem = it->lock();
|
|
||||||
if (elem == nullptr) {
|
|
||||||
it = m_instanceList.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (elem->getUId() == _id) {
|
|
||||||
elem->record(_dst, _nbChunk);
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static ememory::SharedPtr<AndroidOrchestraContext> s_localContext;
|
|
||||||
static int32_t s_nbContextRequested(0);
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t audio::orchestra::api::android::getDeviceCount() {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
ATA_ERROR("Have no Orchertra API instanciate in JAVA ...");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return s_localContext->getDeviceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
audio::orchestra::DeviceInfo audio::orchestra::api::android::getDeviceInfo(uint32_t _device) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return audio::orchestra::DeviceInfo();
|
|
||||||
}
|
|
||||||
return s_localContext->getDeviceInfo(_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t audio::orchestra::api::android::open(uint32_t _device,
|
|
||||||
audio::orchestra::mode _mode,
|
|
||||||
uint32_t _channels,
|
|
||||||
uint32_t _firstChannel,
|
|
||||||
uint32_t _sampleRate,
|
|
||||||
audio::format _format,
|
|
||||||
uint32_t *_bufferSize,
|
|
||||||
const audio::orchestra::StreamOptions& _options,
|
|
||||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return s_localContext->open(_device, _mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, _instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::android::closeStream(int32_t _id) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return s_localContext->closeStream(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::android::startStream(int32_t _id) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return s_localContext->startStream(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::android::stopStream(int32_t _id) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return s_localContext->stopStream(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::android::abortStream(int32_t _id) {
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
return audio::orchestra::error_fail;
|
|
||||||
}
|
|
||||||
return s_localContext->abortStream(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNsetJavaManager(JNIEnv* _env,
|
|
||||||
jclass _classBase,
|
|
||||||
jobject _objCallback) {
|
|
||||||
std::unique_lock<std::mutex> lock(jvm_basics::getMutexJavaVM());
|
|
||||||
ATA_INFO("*******************************************");
|
|
||||||
ATA_INFO("** Creating Orchestra context **");
|
|
||||||
ATA_INFO("*******************************************");
|
|
||||||
if (s_localContext != nullptr) {
|
|
||||||
s_nbContextRequested++;
|
|
||||||
}
|
|
||||||
s_localContext = ememory::makeShared<AndroidOrchestraContext>(_env, _classBase, _objCallback);
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
ATA_ERROR("Can not allocate the orchestra main context instance");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_nbContextRequested++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNsetJavaManagerRemove(JNIEnv* _env, jclass _cls) {
|
|
||||||
std::unique_lock<std::mutex> lock(jvm_basics::getMutexJavaVM());
|
|
||||||
ATA_INFO("*******************************************");
|
|
||||||
ATA_INFO("** remove Orchestra Pointer **");
|
|
||||||
ATA_INFO("*******************************************");
|
|
||||||
if (s_nbContextRequested == 0) {
|
|
||||||
ATA_ERROR("Request remove orchestra interface from Android, but no more interface availlable");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_nbContextRequested--;
|
|
||||||
if (s_nbContextRequested == 0) {
|
|
||||||
s_localContext.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNPlayback(JNIEnv* _env,
|
|
||||||
void* _reserved,
|
|
||||||
jint _id,
|
|
||||||
jshortArray _location,
|
|
||||||
jint _nbChunk) {
|
|
||||||
std::unique_lock<std::mutex> lock(jvm_basics::getMutexJavaVM());
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
ATA_ERROR("Call audio with no more Low level interface");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// get the short* pointer from the Java array
|
|
||||||
jboolean isCopy;
|
|
||||||
jshort* dst = _env->GetShortArrayElements(_location, &isCopy);
|
|
||||||
if (dst != nullptr) {
|
|
||||||
//ATA_INFO("Need audioData " << int32_t(_nbChunk));
|
|
||||||
s_localContext->playback(int32_t(_id), static_cast<short*>(dst), int32_t(_nbChunk));
|
|
||||||
}
|
|
||||||
// TODO : Understand why it did not work corectly ...
|
|
||||||
//if (isCopy == JNI_TRUE) {
|
|
||||||
// release the short* pointer
|
|
||||||
_env->ReleaseShortArrayElements(_location, dst, 0);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNRecord(JNIEnv* _env,
|
|
||||||
void* _reserved,
|
|
||||||
jint _id,
|
|
||||||
jshortArray _location,
|
|
||||||
jint _nbChunk) {
|
|
||||||
std::unique_lock<std::mutex> lock(jvm_basics::getMutexJavaVM());
|
|
||||||
if (s_localContext == nullptr) {
|
|
||||||
ATA_ERROR("Call audio with no more Low level interface");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// get the short* pointer from the Java array
|
|
||||||
jboolean isCopy;
|
|
||||||
jshort* dst = _env->GetShortArrayElements(_location, &isCopy);
|
|
||||||
if (dst != nullptr) {
|
|
||||||
//ATA_INFO("Need audioData " << int32_t(_nbChunk));
|
|
||||||
s_localContext->record(int32_t(_id), static_cast<short*>(dst), int32_t(_nbChunk));
|
|
||||||
}
|
|
||||||
// TODO : Understand why it did not work corectly ...
|
|
||||||
//if (isCopy == JNI_TRUE) {
|
|
||||||
// release the short* pointer
|
|
||||||
_env->ReleaseShortArrayElements(_location, dst, 0);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,42 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef ORCHESTRA_BUILD_JAVA
|
|
||||||
|
|
||||||
#include <audio/orchestra/DeviceInfo.h>
|
|
||||||
#include <audio/orchestra/mode.h>
|
|
||||||
#include <audio/orchestra/error.h>
|
|
||||||
#include <audio/orchestra/StreamOptions.h>
|
|
||||||
#include <audio/format.h>
|
|
||||||
#include <ememory/memory.h>
|
|
||||||
|
|
||||||
namespace audio {
|
|
||||||
namespace orchestra {
|
|
||||||
namespace api {
|
|
||||||
class Android;
|
|
||||||
namespace android {
|
|
||||||
uint32_t getDeviceCount();
|
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
|
||||||
int32_t open(uint32_t _device,
|
|
||||||
audio::orchestra::mode _mode,
|
|
||||||
uint32_t _channels,
|
|
||||||
uint32_t _firstChannel,
|
|
||||||
uint32_t _sampleRate,
|
|
||||||
audio::format _format,
|
|
||||||
uint32_t *_bufferSize,
|
|
||||||
const audio::orchestra::StreamOptions& _options,
|
|
||||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance);
|
|
||||||
enum audio::orchestra::error closeStream(int32_t _id);
|
|
||||||
enum audio::orchestra::error startStream(int32_t _id);
|
|
||||||
enum audio::orchestra::error stopStream(int32_t _id);
|
|
||||||
enum audio::orchestra::error abortStream(int32_t _id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -11,8 +11,8 @@
|
|||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Asio::create() {
|
audio::orchestra::Api* audio::orchestra::api::Asio::create() {
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Asio>(new audio::orchestra::api::Asio());
|
return new audio::orchestra::api::Asio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Asio::create()
|
|||||||
#include "asiodrivers.h"
|
#include "asiodrivers.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "api::Asio"
|
||||||
|
|
||||||
static AsioDrivers drivers;
|
static AsioDrivers drivers;
|
||||||
static ASIOCallbacks asioCallbacks;
|
static ASIOCallbacks asioCallbacks;
|
||||||
static ASIODriverInfo driverInfo;
|
static ASIODriverInfo driverInfo;
|
||||||
@@ -87,7 +90,7 @@ audio::orchestra::api::Asio::Asio() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::api::Asio::~Asio() {
|
audio::orchestra::api::Asio::~Asio() {
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
if (m_coInitialized) {
|
if (m_coInitialized) {
|
||||||
@@ -113,7 +116,7 @@ rtaudio::DeviceInfo audio::orchestra::api::Asio::getDeviceInfo(uint32_t _device)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
|
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
if (_device >= m_devices.size()) {
|
if (_device >= m_devices.size()) {
|
||||||
ATA_ERROR("device ID was not present before stream was opened.");
|
ATA_ERROR("device ID was not present before stream was opened.");
|
||||||
return info;
|
return info;
|
||||||
@@ -216,14 +219,14 @@ void audio::orchestra::api::Asio::saveDeviceInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Asio::open(uint32_t _device,
|
bool audio::orchestra::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t* _bufferSize,
|
uint32_t* _bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
// For ASIO, a duplex stream MUST use the same driver.
|
// For ASIO, a duplex stream MUST use the same driver.
|
||||||
if ( _mode == audio::orchestra::mode_input
|
if ( _mode == audio::orchestra::mode_input
|
||||||
&& m_mode == audio::orchestra::mode_output
|
&& m_mode == audio::orchestra::mode_output
|
||||||
@@ -500,7 +503,7 @@ bool audio::orchestra::api::Asio::open(uint32_t _device,
|
|||||||
}
|
}
|
||||||
m_sampleRate = _sampleRate;
|
m_sampleRate = _sampleRate;
|
||||||
m_device[modeToIdTable(_mode)] = _device;
|
m_device[modeToIdTable(_mode)] = _device;
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
if ( _mode == audio::orchestra::mode_output
|
if ( _mode == audio::orchestra::mode_output
|
||||||
&& _mode == audio::orchestra::mode_input) {
|
&& _mode == audio::orchestra::mode_input) {
|
||||||
// We had already set up an output stream.
|
// We had already set up an output stream.
|
||||||
@@ -547,12 +550,12 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Asio::closeStream() {
|
enum audio::orchestra::error audio::orchestra::api::Asio::closeStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("no open stream to close!");
|
ATA_ERROR("no open stream to close!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
ASIOStop();
|
ASIOStop();
|
||||||
}
|
}
|
||||||
ASIODisposeBuffers();
|
ASIODisposeBuffers();
|
||||||
@@ -572,7 +575,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::closeStream() {
|
|||||||
m_deviceBuffer = 0;
|
m_deviceBuffer = 0;
|
||||||
}
|
}
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +587,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::startStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
ATA_ERROR("the stream is already running!");
|
ATA_ERROR("the stream is already running!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -596,7 +599,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::startStream() {
|
|||||||
m_private->drainCounter = 0;
|
m_private->drainCounter = 0;
|
||||||
m_private->internalDrain = false;
|
m_private->internalDrain = false;
|
||||||
ResetEvent(m_private->condition);
|
ResetEvent(m_private->condition);
|
||||||
m_state = audio::orchestra::state::running;
|
m_state = audio::orchestra::state_running;
|
||||||
asioXRun = false;
|
asioXRun = false;
|
||||||
unlock:
|
unlock:
|
||||||
stopThreadCalled = false;
|
stopThreadCalled = false;
|
||||||
@@ -610,7 +613,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::stopStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -620,7 +623,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::stopStream() {
|
|||||||
WaitForSingleObject(m_private->condition, INFINITE); // block until signaled
|
WaitForSingleObject(m_private->condition, INFINITE); // block until signaled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
ASIOError result = ASIOStop();
|
ASIOError result = ASIOStop();
|
||||||
if (result != ASE_OK) {
|
if (result != ASE_OK) {
|
||||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") stopping device.");
|
ATA_ERROR("error (" << getAsioErrorString(result) << ") stopping device.");
|
||||||
@@ -635,7 +638,7 @@ enum audio::orchestra::error audio::orchestra::api::Asio::abortStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
error(audio::orchestra::error_warning);
|
error(audio::orchestra::error_warning);
|
||||||
return;
|
return;
|
||||||
@@ -663,18 +666,18 @@ static unsigned __stdcall asioStopStream(void *_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
||||||
if ( m_state == audio::orchestra::state::stopped
|
if ( m_state == audio::orchestra::state_stopped
|
||||||
|| m_state == audio::orchestra::state::stopping) {
|
|| m_state == audio::orchestra::state_stopping) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
||||||
// Check if we were draining the stream and signal if finished.
|
// Check if we were draining the stream and signal if finished.
|
||||||
if (m_private->drainCounter > 3) {
|
if (m_private->drainCounter > 3) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
if (m_private->internalDrain == false) {
|
if (m_private->internalDrain == false) {
|
||||||
SetEvent(m_private->condition);
|
SetEvent(m_private->condition);
|
||||||
} else { // spawn a thread to stop the stream
|
} else { // spawn a thread to stop the stream
|
||||||
@@ -694,11 +697,11 @@ bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
|||||||
audio::Time streamTime = getStreamTime();
|
audio::Time streamTime = getStreamTime();
|
||||||
std::vector<enum audio::orchestra::status status;
|
std::vector<enum audio::orchestra::status status;
|
||||||
if (m_mode != audio::orchestra::mode_input && asioXRun == true) {
|
if (m_mode != audio::orchestra::mode_input && asioXRun == true) {
|
||||||
status.push_back(audio::orchestra::status::underflow);
|
status.push_back(audio::orchestra::status_underflow);
|
||||||
asioXRun = false;
|
asioXRun = false;
|
||||||
}
|
}
|
||||||
if (m_mode != audio::orchestra::mode_output && asioXRun == true) {
|
if (m_mode != audio::orchestra::mode_output && asioXRun == true) {
|
||||||
status.push_back(audio::orchestra::status::underflow;
|
status.push_back(audio::orchestra::status_underflow;
|
||||||
asioXRun = false;
|
asioXRun = false;
|
||||||
}
|
}
|
||||||
int32_t cbReturnValue = info->callback(m_userBuffer[1],
|
int32_t cbReturnValue = info->callback(m_userBuffer[1],
|
||||||
@@ -708,7 +711,7 @@ bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
|||||||
m_bufferSize,
|
m_bufferSize,
|
||||||
status);
|
status);
|
||||||
if (cbReturnValue == 2) {
|
if (cbReturnValue == 2) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
m_private->drainCounter = 2;
|
m_private->drainCounter = 2;
|
||||||
unsigned threadId;
|
unsigned threadId;
|
||||||
m_callbackInfo.thread = _beginthreadex(nullptr,
|
m_callbackInfo.thread = _beginthreadex(nullptr,
|
||||||
|
@@ -4,8 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_ASIO
|
#if !defined(__AUDIO_ORCHESTRA_API_ASIO_H__) && defined(ORCHESTRA_BUILD_ASIO)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_ASIO_H__
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -13,12 +14,12 @@ namespace audio {
|
|||||||
class AsioPrivate:
|
class AsioPrivate:
|
||||||
class Asio: public audio::orchestra::Api {
|
class Asio: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Asio();
|
Asio();
|
||||||
virtual ~Asio();
|
virtual ~Asio();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeAsio;
|
return audio::orchestra::WINDOWS_ASIO;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -33,18 +34,18 @@ namespace audio {
|
|||||||
// will most likely produce highly undesireable results!
|
// will most likely produce highly undesireable results!
|
||||||
bool callbackEvent(long _bufferIndex);
|
bool callbackEvent(long _bufferIndex);
|
||||||
private:
|
private:
|
||||||
ememory::SharedPtr<AsioPrivate> m_private;
|
std::shared_ptr<AsioPrivate> m_private;
|
||||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||||
void saveDeviceInfo();
|
void saveDeviceInfo();
|
||||||
bool m_coInitialized;
|
bool m_coInitialized;
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
#include <thread>
|
#include <etk/thread.h>
|
||||||
#include <ethread/tools.h>
|
#include <etk/thread/tools.h>
|
||||||
#include <audio/orchestra/api/Core.h>
|
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Core::create() {
|
audio::orchestra::Api* audio::orchestra::api::Core::create() {
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Core>(new audio::orchestra::api::Core());
|
return new audio::orchestra::api::Core();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "api::Core"
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
namespace api {
|
namespace api {
|
||||||
@@ -37,7 +39,7 @@ namespace audio {
|
|||||||
uint32_t nStreams[2]; // number of streams to use
|
uint32_t nStreams[2]; // number of streams to use
|
||||||
bool xrun[2];
|
bool xrun[2];
|
||||||
char *deviceBuffer;
|
char *deviceBuffer;
|
||||||
std::condition_variable condition;
|
std11::condition_variable condition;
|
||||||
int32_t drainCounter; // Tracks callback counts when draining
|
int32_t drainCounter; // Tracks callback counts when draining
|
||||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||||
CorePrivate() :
|
CorePrivate() :
|
||||||
@@ -85,7 +87,7 @@ audio::orchestra::api::Core::~Core() {
|
|||||||
// The subclass destructor gets called before the base class
|
// The subclass destructor gets called before the base class
|
||||||
// destructor, so close an existing stream before deallocating
|
// destructor, so close an existing stream before deallocating
|
||||||
// apiDeviceId memory.
|
// apiDeviceId memory.
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,7 @@ uint32_t audio::orchestra::api::Core::getDeviceCount() {
|
|||||||
ATA_ERROR("OS-X error getting device info!");
|
ATA_ERROR("OS-X error getting device info!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (dataSize / sizeof(AudioDeviceID)) * 2;
|
return dataSize / sizeof(AudioDeviceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t audio::orchestra::api::Core::getDefaultInputDevice() {
|
uint32_t audio::orchestra::api::Core::getDefaultInputDevice() {
|
||||||
@@ -143,7 +145,7 @@ uint32_t audio::orchestra::api::Core::getDefaultInputDevice() {
|
|||||||
}
|
}
|
||||||
for (uint32_t iii=0; iii<nDevices; iii++) {
|
for (uint32_t iii=0; iii<nDevices; iii++) {
|
||||||
if (id == deviceList[iii]) {
|
if (id == deviceList[iii]) {
|
||||||
return iii*2+1;
|
return iii;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ATA_ERROR("No default device found!");
|
ATA_ERROR("No default device found!");
|
||||||
@@ -187,7 +189,7 @@ uint32_t audio::orchestra::api::Core::getDefaultOutputDevice() {
|
|||||||
}
|
}
|
||||||
for (uint32_t iii=0; iii<nDevices; iii++) {
|
for (uint32_t iii=0; iii<nDevices; iii++) {
|
||||||
if (id == deviceList[iii]) {
|
if (id == deviceList[iii]) {
|
||||||
return iii*2;
|
return iii;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ATA_ERROR("No default device found!");
|
ATA_ERROR("No default device found!");
|
||||||
@@ -196,25 +198,19 @@ uint32_t audio::orchestra::api::Core::getDefaultOutputDevice() {
|
|||||||
|
|
||||||
audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t _device) {
|
audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t _device) {
|
||||||
audio::orchestra::DeviceInfo info;
|
audio::orchestra::DeviceInfo info;
|
||||||
|
info.probed = false;
|
||||||
// Get device ID
|
// Get device ID
|
||||||
uint32_t nDevices = getDeviceCount();
|
uint32_t nDevices = getDeviceCount();
|
||||||
if (nDevices == 0) {
|
if (nDevices == 0) {
|
||||||
ATA_ERROR("no devices found!");
|
ATA_ERROR("no devices found!");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
if (_device >= nDevices) {
|
if (_device >= nDevices) {
|
||||||
ATA_ERROR("device ID is invalid!");
|
ATA_ERROR("device ID is invalid!");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
info.input = false;
|
AudioDeviceID deviceList[ nDevices ];
|
||||||
if (_device%2 == 1) {
|
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices;
|
||||||
info.input = true;
|
|
||||||
}
|
|
||||||
// The /2 corespond of not mixing input and output ... ==< then the user number of devide is twice the number of real device ...
|
|
||||||
AudioDeviceID deviceList[nDevices/2];
|
|
||||||
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2;
|
|
||||||
AudioObjectPropertyAddress property = {
|
AudioObjectPropertyAddress property = {
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
@@ -228,13 +224,10 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t
|
|||||||
(void*)&deviceList);
|
(void*)&deviceList);
|
||||||
if (result != noErr) {
|
if (result != noErr) {
|
||||||
ATA_ERROR("OS-X system error getting device IDs.");
|
ATA_ERROR("OS-X system error getting device IDs.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
AudioDeviceID id = deviceList[ _device/2 ];
|
AudioDeviceID id = deviceList[ _device ];
|
||||||
// ------------------------------------------------
|
|
||||||
// Get the device name.
|
// Get the device name.
|
||||||
// ------------------------------------------------
|
|
||||||
info.name.erase();
|
info.name.erase();
|
||||||
CFStringRef cfname;
|
CFStringRef cfname;
|
||||||
dataSize = sizeof(CFStringRef);
|
dataSize = sizeof(CFStringRef);
|
||||||
@@ -242,85 +235,102 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t
|
|||||||
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
|
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
|
||||||
if (result != noErr) {
|
if (result != noErr) {
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device manufacturer.");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device manufacturer.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
//const char *mname = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
|
//const char *mname = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
|
||||||
int32_t length = CFStringGetLength(cfname);
|
int32_t length = CFStringGetLength(cfname);
|
||||||
std::vector<char> name;
|
char *mname = (char *)malloc(length * 3 + 1);
|
||||||
name.resize(length * 3 + 1, '\0');
|
CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());
|
||||||
CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding());
|
info.name.append((const char *)mname, strlen(mname));
|
||||||
info.name.append(&name[0], strlen(&name[0]));
|
|
||||||
info.name.append(": ");
|
info.name.append(": ");
|
||||||
CFRelease(cfname);
|
CFRelease(cfname);
|
||||||
|
free(mname);
|
||||||
property.mSelector = kAudioObjectPropertyName;
|
property.mSelector = kAudioObjectPropertyName;
|
||||||
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
|
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
|
||||||
if (result != noErr) {
|
if (result != noErr) {
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device name.");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device name.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
//const char *name = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
|
//const char *name = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
|
||||||
length = CFStringGetLength(cfname);
|
length = CFStringGetLength(cfname);
|
||||||
name.resize(length * 3 + 1, '\0');
|
char *name = (char *)malloc(length * 3 + 1);
|
||||||
CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding());
|
CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());
|
||||||
info.name.append(&name[0], strlen(&name[0]));
|
info.name.append((const char *)name, strlen(name));
|
||||||
CFRelease(cfname);
|
CFRelease(cfname);
|
||||||
// ------------------------------------------------
|
free(name);
|
||||||
// Get the output stream "configuration".
|
// Get the output stream "configuration".
|
||||||
// ------------------------------------------------
|
AudioBufferList *bufferList = nil;
|
||||||
property.mSelector = kAudioDevicePropertyStreamConfiguration;
|
property.mSelector = kAudioDevicePropertyStreamConfiguration;
|
||||||
|
property.mScope = kAudioDevicePropertyScopeOutput;
|
||||||
if (info.input == false) {
|
// property.mElement = kAudioObjectPropertyElementWildcard;
|
||||||
property.mScope = kAudioDevicePropertyScopeOutput;
|
|
||||||
} else {
|
|
||||||
property.mScope = kAudioDevicePropertyScopeInput;
|
|
||||||
}
|
|
||||||
AudioBufferList *bufferList = nullptr;
|
|
||||||
dataSize = 0;
|
dataSize = 0;
|
||||||
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
|
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
|
||||||
if (result != noErr || dataSize == 0) {
|
if (result != noErr || dataSize == 0) {
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration info for device (" << _device << ").");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting output stream configuration info for device (" << _device << ").");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// Allocate the AudioBufferList.
|
// Allocate the AudioBufferList.
|
||||||
bufferList = (AudioBufferList *) malloc(dataSize);
|
bufferList = (AudioBufferList *) malloc(dataSize);
|
||||||
if (bufferList == nullptr) {
|
if (bufferList == nullptr) {
|
||||||
ATA_ERROR("memory error allocating AudioBufferList.");
|
ATA_ERROR("memory error allocating output AudioBufferList.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList);
|
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList);
|
||||||
if ( result != noErr
|
if ( result != noErr
|
||||||
|| dataSize == 0) {
|
|| dataSize == 0) {
|
||||||
free(bufferList);
|
free(bufferList);
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ").");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting output stream configuration for device (" << _device << ").");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// Get channel information.
|
// Get output channel information.
|
||||||
for (size_t iii=0; iii<bufferList->mNumberBuffers; ++iii) {
|
uint32_t i, nStreams = bufferList->mNumberBuffers;
|
||||||
for (size_t jjj=0; jjj<bufferList->mBuffers[iii].mNumberChannels; ++jjj) {
|
for (i=0; i<nStreams; i++) {
|
||||||
info.channels.push_back(audio::channel_unknow);
|
info.outputChannels += bufferList->mBuffers[i].mNumberChannels;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(bufferList);
|
free(bufferList);
|
||||||
if (info.channels.size() == 0) {
|
// Get the input stream "configuration".
|
||||||
ATA_DEBUG("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ") ==> no channels.");
|
property.mScope = kAudioDevicePropertyScopeInput;
|
||||||
info.clear();
|
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
|
||||||
|
if ( result != noErr
|
||||||
|
|| dataSize == 0) {
|
||||||
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting input stream configuration info for device (" << _device << ").");
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
// Allocate the AudioBufferList.
|
||||||
// ------------------------------------------------
|
bufferList = (AudioBufferList *) malloc(dataSize);
|
||||||
|
if (bufferList == nullptr) {
|
||||||
|
ATA_ERROR("memory error allocating input AudioBufferList.");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList);
|
||||||
|
if (result != noErr || dataSize == 0) {
|
||||||
|
free(bufferList);
|
||||||
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting input stream configuration for device (" << _device << ").");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
// Get input channel information.
|
||||||
|
nStreams = bufferList->mNumberBuffers;
|
||||||
|
for (i=0; i<nStreams; i++) {
|
||||||
|
info.inputChannels += bufferList->mBuffers[i].mNumberChannels;
|
||||||
|
}
|
||||||
|
free(bufferList);
|
||||||
|
// If device opens for both playback and capture, we determine the channels.
|
||||||
|
if ( info.outputChannels > 0
|
||||||
|
&& info.inputChannels > 0) {
|
||||||
|
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||||
|
}
|
||||||
|
// Probe the device sample rates.
|
||||||
|
bool isInput = false;
|
||||||
|
if (info.outputChannels == 0) {
|
||||||
|
isInput = true;
|
||||||
|
}
|
||||||
// Determine the supported sample rates.
|
// Determine the supported sample rates.
|
||||||
// ------------------------------------------------
|
|
||||||
property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
||||||
|
if (isInput == false) property.mScope = kAudioDevicePropertyScopeOutput;
|
||||||
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
|
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
|
||||||
if ( result != kAudioHardwareNoError
|
if ( result != kAudioHardwareNoError
|
||||||
|| dataSize == 0) {
|
|| dataSize == 0) {
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rate info.");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rate info.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
uint32_t nRanges = dataSize / sizeof(AudioValueRange);
|
uint32_t nRanges = dataSize / sizeof(AudioValueRange);
|
||||||
@@ -328,7 +338,6 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t
|
|||||||
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &rangeList);
|
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &rangeList);
|
||||||
if (result != kAudioHardwareNoError) {
|
if (result != kAudioHardwareNoError) {
|
||||||
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rates.");
|
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rates.");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
double minimumRate = 100000000.0, maximumRate = 0.0;
|
double minimumRate = 100000000.0, maximumRate = 0.0;
|
||||||
@@ -349,40 +358,33 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t
|
|||||||
}
|
}
|
||||||
if (info.sampleRates.size() == 0) {
|
if (info.sampleRates.size() == 0) {
|
||||||
ATA_ERROR("No supported sample rates found for device (" << _device << ").");
|
ATA_ERROR("No supported sample rates found for device (" << _device << ").");
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------
|
|
||||||
// Determine the format.
|
|
||||||
// ------------------------------------------------
|
|
||||||
// CoreAudio always uses 32-bit floating point data for PCM streams.
|
// CoreAudio always uses 32-bit floating point data for PCM streams.
|
||||||
// Thus, any other "physical" formats supported by the device are of
|
// Thus, any other "physical" formats supported by the device are of
|
||||||
// no interest to the client.
|
// no interest to the client.
|
||||||
info.nativeFormats.push_back(audio::format_float);
|
info.nativeFormats.push_back(audio::format_float);
|
||||||
// ------------------------------------------------
|
if (info.outputChannels > 0) {
|
||||||
// Determine the default channel.
|
|
||||||
// ------------------------------------------------
|
|
||||||
|
|
||||||
if (info.input == false) {
|
|
||||||
if (getDefaultOutputDevice() == _device) {
|
if (getDefaultOutputDevice() == _device) {
|
||||||
info.isDefault = true;
|
info.isDefaultOutput = true;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (getDefaultInputDevice() == _device) {
|
|
||||||
info.isDefault = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.isCorrect = true;
|
if (info.inputChannels > 0) {
|
||||||
|
if (getDefaultInputDevice() == _device) {
|
||||||
|
info.isDefaultInput = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.probed = true;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice,
|
OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice,
|
||||||
const AudioTimeStamp* _inNow,
|
const AudioTimeStamp* _inNow,
|
||||||
const AudioBufferList* _inInputData,
|
const AudioBufferList* _inInputData,
|
||||||
const AudioTimeStamp* _inInputTime,
|
const AudioTimeStamp* _inInputTime,
|
||||||
AudioBufferList* _outOutputData,
|
AudioBufferList* _outOutputData,
|
||||||
const AudioTimeStamp* _inOutputTime,
|
const AudioTimeStamp* _inOutputTime,
|
||||||
void* _userData) {
|
void* _userData) {
|
||||||
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
||||||
audio::Time inputTime;
|
audio::Time inputTime;
|
||||||
audio::Time outputTime;
|
audio::Time outputTime;
|
||||||
@@ -431,14 +433,14 @@ static OSStatus rateListener(AudioObjectID _inDevice,
|
|||||||
return kAudioHardwareNoError;
|
return kAudioHardwareNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Core::open(uint32_t _device,
|
bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
// Get device ID
|
// Get device ID
|
||||||
uint32_t nDevices = getDeviceCount();
|
uint32_t nDevices = getDeviceCount();
|
||||||
if (nDevices == 0) {
|
if (nDevices == 0) {
|
||||||
@@ -451,8 +453,8 @@ bool audio::orchestra::api::Core::open(uint32_t _device,
|
|||||||
ATA_ERROR("device ID is invalid!");
|
ATA_ERROR("device ID is invalid!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AudioDeviceID deviceList[ nDevices/2 ];
|
AudioDeviceID deviceList[ nDevices ];
|
||||||
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2;
|
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices;
|
||||||
AudioObjectPropertyAddress property = {
|
AudioObjectPropertyAddress property = {
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
@@ -468,7 +470,7 @@ bool audio::orchestra::api::Core::open(uint32_t _device,
|
|||||||
ATA_ERROR("OS-X system error getting device IDs.");
|
ATA_ERROR("OS-X system error getting device IDs.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AudioDeviceID id = deviceList[ _device/2 ];
|
AudioDeviceID id = deviceList[ _device ];
|
||||||
// Setup for stream mode.
|
// Setup for stream mode.
|
||||||
bool isInput = false;
|
bool isInput = false;
|
||||||
if (_mode == audio::orchestra::mode_input) {
|
if (_mode == audio::orchestra::mode_input) {
|
||||||
@@ -503,7 +505,7 @@ bool audio::orchestra::api::Core::open(uint32_t _device,
|
|||||||
// channels. CoreAudio devices can have an arbitrary number of
|
// channels. CoreAudio devices can have an arbitrary number of
|
||||||
// streams and each stream can have an arbitrary number of channels.
|
// streams and each stream can have an arbitrary number of channels.
|
||||||
// For each stream, a single buffer of interleaved samples is
|
// For each stream, a single buffer of interleaved samples is
|
||||||
// provided. orchestra prefers the use of one stream of interleaved
|
// provided. RtAudio prefers the use of one stream of interleaved
|
||||||
// data or multiple consecutive single-channel streams. However, we
|
// data or multiple consecutive single-channel streams. However, we
|
||||||
// now support multiple consecutive multi-channel streams of
|
// now support multiple consecutive multi-channel streams of
|
||||||
// interleaved data as well.
|
// interleaved data as well.
|
||||||
@@ -825,7 +827,7 @@ bool audio::orchestra::api::Core::open(uint32_t _device,
|
|||||||
}
|
}
|
||||||
m_sampleRate = _sampleRate;
|
m_sampleRate = _sampleRate;
|
||||||
m_device[modeToIdTable(_mode)] = _device;
|
m_device[modeToIdTable(_mode)] = _device;
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
ATA_VERBOSE("Set state as stopped");
|
ATA_VERBOSE("Set state as stopped");
|
||||||
// Setup the buffer conversion information structure.
|
// Setup the buffer conversion information structure.
|
||||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||||
@@ -869,19 +871,19 @@ error:
|
|||||||
free(m_deviceBuffer);
|
free(m_deviceBuffer);
|
||||||
m_deviceBuffer = 0;
|
m_deviceBuffer = 0;
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
ATA_VERBOSE("Set state as closed");
|
ATA_VERBOSE("Set state as closed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Core::closeStream() {
|
enum audio::orchestra::error audio::orchestra::api::Core::closeStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("no open stream to close!");
|
ATA_ERROR("no open stream to close!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
if ( m_mode == audio::orchestra::mode_output
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|| m_mode == audio::orchestra::mode_duplex) {
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
AudioDeviceStop(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
AudioDeviceStop(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
||||||
}
|
}
|
||||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
@@ -894,7 +896,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::closeStream() {
|
|||||||
if ( m_mode == audio::orchestra::mode_input
|
if ( m_mode == audio::orchestra::mode_input
|
||||||
|| ( m_mode == audio::orchestra::mode_duplex
|
|| ( m_mode == audio::orchestra::mode_duplex
|
||||||
&& m_device[0] != m_device[1])) {
|
&& m_device[0] != m_device[1])) {
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
AudioDeviceStop(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
AudioDeviceStop(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
||||||
}
|
}
|
||||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
@@ -911,7 +913,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::closeStream() {
|
|||||||
m_deviceBuffer = nullptr;
|
m_deviceBuffer = nullptr;
|
||||||
}
|
}
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
ATA_VERBOSE("Set state as closed");
|
ATA_VERBOSE("Set state as closed");
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
@@ -922,7 +924,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::startStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
ATA_ERROR("the stream is already running!");
|
ATA_ERROR("the stream is already running!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -946,7 +948,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::startStream() {
|
|||||||
}
|
}
|
||||||
m_private->drainCounter = 0;
|
m_private->drainCounter = 0;
|
||||||
m_private->internalDrain = false;
|
m_private->internalDrain = false;
|
||||||
m_state = audio::orchestra::state::running;
|
m_state = audio::orchestra::state_running;
|
||||||
ATA_VERBOSE("Set state as running");
|
ATA_VERBOSE("Set state as running");
|
||||||
unlock:
|
unlock:
|
||||||
if (result == noErr) {
|
if (result == noErr) {
|
||||||
@@ -959,7 +961,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::stopStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -967,7 +969,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::stopStream() {
|
|||||||
if ( m_mode == audio::orchestra::mode_output
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|| m_mode == audio::orchestra::mode_duplex) {
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
if (m_private->drainCounter == 0) {
|
if (m_private->drainCounter == 0) {
|
||||||
std::unique_lock<std::mutex> lck(m_mutex);
|
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||||
m_private->drainCounter = 2;
|
m_private->drainCounter = 2;
|
||||||
m_private->condition.wait(lck);
|
m_private->condition.wait(lck);
|
||||||
}
|
}
|
||||||
@@ -986,7 +988,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::stopStream() {
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
ATA_VERBOSE("Set state as stopped");
|
ATA_VERBOSE("Set state as stopped");
|
||||||
unlock:
|
unlock:
|
||||||
if (result == noErr) {
|
if (result == noErr) {
|
||||||
@@ -999,7 +1001,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::abortStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1015,7 @@ enum audio::orchestra::error audio::orchestra::api::Core::abortStream() {
|
|||||||
// callbackEvent() function probably should return before the AudioDeviceStop()
|
// callbackEvent() function probably should return before the AudioDeviceStop()
|
||||||
// function is called.
|
// function is called.
|
||||||
void audio::orchestra::api::Core::coreStopStream(void *_userData) {
|
void audio::orchestra::api::Core::coreStopStream(void *_userData) {
|
||||||
ethread::setName("CoreAudio_stopStream");
|
etk::thread::setName("CoreAudio_stopStream");
|
||||||
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
||||||
myClass->stopStream();
|
myClass->stopStream();
|
||||||
}
|
}
|
||||||
@@ -1023,20 +1025,20 @@ bool audio::orchestra::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
|||||||
const audio::Time& _inTime,
|
const audio::Time& _inTime,
|
||||||
const AudioBufferList *_outBufferList,
|
const AudioBufferList *_outBufferList,
|
||||||
const audio::Time& _outTime) {
|
const audio::Time& _outTime) {
|
||||||
if ( m_state == audio::orchestra::state::stopped
|
if ( m_state == audio::orchestra::state_stopped
|
||||||
|| m_state == audio::orchestra::state::stopping) {
|
|| m_state == audio::orchestra::state_stopping) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check if we were draining the stream and signal is finished.
|
// Check if we were draining the stream and signal is finished.
|
||||||
if (m_private->drainCounter > 3) {
|
if (m_private->drainCounter > 3) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
ATA_VERBOSE("Set state as stopping");
|
ATA_VERBOSE("Set state as stopping");
|
||||||
if (m_private->internalDrain == true) {
|
if (m_private->internalDrain == true) {
|
||||||
new std::thread(&audio::orchestra::api::Core::coreStopStream, this);
|
new std11::thread(&audio::orchestra::api::Core::coreStopStream, this);
|
||||||
} else {
|
} else {
|
||||||
// external call to stopStream()
|
// external call to stopStream()
|
||||||
m_private->condition.notify_one();
|
m_private->condition.notify_one();
|
||||||
@@ -1051,12 +1053,12 @@ bool audio::orchestra::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
|||||||
std::vector<enum audio::orchestra::status> status;
|
std::vector<enum audio::orchestra::status> status;
|
||||||
if ( m_mode != audio::orchestra::mode_input
|
if ( m_mode != audio::orchestra::mode_input
|
||||||
&& m_private->xrun[0] == true) {
|
&& m_private->xrun[0] == true) {
|
||||||
status.push_back(audio::orchestra::status::underflow);
|
status.push_back(audio::orchestra::status_underflow);
|
||||||
m_private->xrun[0] = false;
|
m_private->xrun[0] = false;
|
||||||
}
|
}
|
||||||
if ( m_mode != audio::orchestra::mode_output
|
if ( m_mode != audio::orchestra::mode_output
|
||||||
&& m_private->xrun[1] == true) {
|
&& m_private->xrun[1] == true) {
|
||||||
status.push_back(audio::orchestra::status::overflow);
|
status.push_back(audio::orchestra::status_overflow);
|
||||||
m_private->xrun[1] = false;
|
m_private->xrun[1] = false;
|
||||||
}
|
}
|
||||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||||
@@ -1066,7 +1068,7 @@ bool audio::orchestra::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
|||||||
m_bufferSize,
|
m_bufferSize,
|
||||||
status);
|
status);
|
||||||
if (cbReturnValue == 2) {
|
if (cbReturnValue == 2) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
ATA_VERBOSE("Set state as stopping");
|
ATA_VERBOSE("Set state as stopping");
|
||||||
m_private->drainCounter = 2;
|
m_private->drainCounter = 2;
|
||||||
abortStream();
|
abortStream();
|
||||||
|
@@ -4,8 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_MACOSX_CORE
|
#if !defined(__AUDIO_ORCHESTRA_API_CORE_H__) && defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_CORE_H__
|
||||||
|
|
||||||
#include <CoreAudio/AudioHardware.h>
|
#include <CoreAudio/AudioHardware.h>
|
||||||
|
|
||||||
@@ -16,12 +17,12 @@ namespace audio {
|
|||||||
class CorePrivate;
|
class CorePrivate;
|
||||||
class Core: public audio::orchestra::Api {
|
class Core: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Core();
|
Core();
|
||||||
virtual ~Core();
|
virtual ~Core();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeCoreOSX;
|
return audio::orchestra::type_coreOSX;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -46,15 +47,15 @@ namespace audio {
|
|||||||
void* _infoPointer);
|
void* _infoPointer);
|
||||||
static void coreStopStream(void *_userData);
|
static void coreStopStream(void *_userData);
|
||||||
private:
|
private:
|
||||||
ememory::SharedPtr<CorePrivate> m_private;
|
std::shared_ptr<CorePrivate> m_private;
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
static const char* getErrorCode(OSStatus _code);
|
static const char* getErrorCode(OSStatus _code);
|
||||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||||
uint32_t _nAddresses,
|
uint32_t _nAddresses,
|
||||||
|
@@ -4,8 +4,10 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_IOS_CORE
|
#if !defined(__AUDIO_ORCHESTRA_API_CORE_IOS_H__) && defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_CORE_IOS_H__
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -13,12 +15,12 @@ namespace audio {
|
|||||||
class CoreIosPrivate;
|
class CoreIosPrivate;
|
||||||
class CoreIos: public audio::orchestra::Api {
|
class CoreIos: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
CoreIos();
|
CoreIos();
|
||||||
virtual ~CoreIos();
|
virtual ~CoreIos();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeCoreIOS;
|
return audio::orchestra::type_coreIOS;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -34,20 +36,20 @@ namespace audio {
|
|||||||
private:
|
private:
|
||||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||||
void saveDeviceInfo();
|
void saveDeviceInfo();
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
public:
|
public:
|
||||||
void callBackEvent(void* _data,
|
void callBackEvent(void* _data,
|
||||||
int32_t _nbChunk,
|
int32_t _nbChunk,
|
||||||
const audio::Time& _time);
|
const audio::Time& _time);
|
||||||
public:
|
public:
|
||||||
ememory::SharedPtr<CoreIosPrivate> m_private;
|
std11::shared_ptr<CoreIosPrivate> m_private;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,11 +14,13 @@
|
|||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <audio/orchestra/api/CoreIos.h>
|
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::CoreIos::create() {
|
#undef __class__
|
||||||
|
#define __class__ "api::CoreIos"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::CoreIos::create() {
|
||||||
ATA_INFO("Create CoreIos device ... ");
|
ATA_INFO("Create CoreIos device ... ");
|
||||||
return ememory::SharedPtr<audio::orchestra::api::CoreIos>(new audio::orchestra::api::CoreIos());
|
return new audio::orchestra::api::CoreIos();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define kOutputBus 0
|
#define kOutputBus 0
|
||||||
@@ -44,19 +46,23 @@ audio::orchestra::api::CoreIos::CoreIos(void) :
|
|||||||
ATA_ERROR("Get count devices : " << 2);
|
ATA_ERROR("Get count devices : " << 2);
|
||||||
audio::orchestra::DeviceInfo tmp;
|
audio::orchestra::DeviceInfo tmp;
|
||||||
// Add default output format :
|
// Add default output format :
|
||||||
tmp.name = "speaker";
|
tmp.name = "out";
|
||||||
tmp.sampleRates.push_back(48000);
|
tmp.sampleRates.push_back(48000);
|
||||||
tmp.channels.push_back(audio::channel_frontRight);
|
tmp.outputChannels = 2;
|
||||||
tmp.channels.push_back(audio::channel_frontLeft);
|
tmp.inputChannels = 0;
|
||||||
tmp.isDefault = true;
|
tmp.duplexChannels = 0;
|
||||||
|
tmp.isDefaultOutput = true;
|
||||||
|
tmp.isDefaultInput = false;
|
||||||
tmp.nativeFormats.push_back(audio::format_int16);
|
tmp.nativeFormats.push_back(audio::format_int16);
|
||||||
m_devices.push_back(tmp);
|
m_devices.push_back(tmp);
|
||||||
// add default input format:
|
// add default input format:
|
||||||
tmp.name = "microphone";
|
tmp.name = "in";
|
||||||
tmp.sampleRates.push_back(48000);
|
tmp.sampleRates.push_back(48000);
|
||||||
tmp.channels.push_back(audio::channel_frontRight);
|
tmp.outputChannels = 0;
|
||||||
tmp.channels.push_back(audio::channel_frontLeft);
|
tmp.inputChannels = 2;
|
||||||
tmp.isDefault = true;
|
tmp.duplexChannels = 0;
|
||||||
|
tmp.isDefaultOutput = false;
|
||||||
|
tmp.isDefaultInput = true;
|
||||||
tmp.nativeFormats.push_back(audio::format_int16);
|
tmp.nativeFormats.push_back(audio::format_int16);
|
||||||
m_devices.push_back(tmp);
|
m_devices.push_back(tmp);
|
||||||
ATA_INFO("Create CoreIOs interface (end)");
|
ATA_INFO("Create CoreIOs interface (end)");
|
||||||
@@ -108,12 +114,12 @@ enum audio::orchestra::error audio::orchestra::api::CoreIos::abortStream(void) {
|
|||||||
|
|
||||||
void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
|
void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
|
||||||
int32_t _nbChunk,
|
int32_t _nbChunk,
|
||||||
const audio::Time& _time) {
|
const audio::Time& _time) {
|
||||||
int32_t doStopStream = 0;
|
int32_t doStopStream = 0;
|
||||||
std::vector<enum audio::orchestra::status> status;
|
std::vector<enum audio::orchestra::status> status;
|
||||||
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {
|
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {
|
||||||
doStopStream = m_callback(nullptr,
|
doStopStream = m_callback(nullptr,
|
||||||
audio::Time(),
|
audio::Time(),
|
||||||
&m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0],
|
&m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0],
|
||||||
_time,
|
_time,
|
||||||
_nbChunk,
|
_nbChunk,
|
||||||
@@ -123,7 +129,7 @@ void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
|
|||||||
doStopStream = m_callback(_data,
|
doStopStream = m_callback(_data,
|
||||||
_time,
|
_time,
|
||||||
nullptr,
|
nullptr,
|
||||||
audio::Time(),
|
audio::Time(),
|
||||||
_nbChunk,
|
_nbChunk,
|
||||||
status);
|
status);
|
||||||
}
|
}
|
||||||
@@ -161,14 +167,14 @@ static OSStatus playbackCallback(void *_userData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool audio::orchestra::api::CoreIos::open(uint32_t _device,
|
bool audio::orchestra::api::CoreIos::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||||
if (_mode != audio::orchestra::mode_output) {
|
if (_mode != audio::orchestra::mode_output) {
|
||||||
ATA_ERROR("Can not start a device input or duplex for CoreIos ...");
|
ATA_ERROR("Can not start a device input or duplex for CoreIos ...");
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -4,8 +4,10 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_DS
|
#if !defined(__AUDIO_ORCHESTRA_API_DS_H__) && defined(ORCHESTRA_BUILD_DS)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_DS_H__
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -13,14 +15,16 @@ namespace audio {
|
|||||||
class DsPrivate;
|
class DsPrivate;
|
||||||
class Ds: public audio::orchestra::Api {
|
class Ds: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Ds();
|
Ds();
|
||||||
virtual ~Ds();
|
virtual ~Ds();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeDs;
|
return audio::orchestra::type_ds;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
|
uint32_t getDefaultOutputDevice();
|
||||||
|
uint32_t getDefaultInputDevice();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
enum audio::orchestra::error closeStream();
|
enum audio::orchestra::error closeStream();
|
||||||
enum audio::orchestra::error startStream();
|
enum audio::orchestra::error startStream();
|
||||||
@@ -34,18 +38,18 @@ namespace audio {
|
|||||||
void callbackEvent();
|
void callbackEvent();
|
||||||
private:
|
private:
|
||||||
static void dsCallbackEvent(void *_userData);
|
static void dsCallbackEvent(void *_userData);
|
||||||
ememory::SharedPtr<DsPrivate> m_private;
|
std11::shared_ptr<DsPrivate> m_private;
|
||||||
bool m_coInitialized;
|
bool m_coInitialized;
|
||||||
bool m_buffersRolling;
|
bool m_buffersRolling;
|
||||||
long m_duplexPrerollBytes;
|
long m_duplexPrerollBytes;
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
enum audio::orchestra::mode _mode,
|
enum audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
enum audio::format _format,
|
enum audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,11 @@
|
|||||||
#include <audio/orchestra/api/Dummy.h>
|
#include <audio/orchestra/api/Dummy.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Dummy::create() {
|
#undef __class__
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Dummy>(new audio::orchestra::api::Dummy());
|
#define __class__ "api::Dummy"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::Dummy::create() {
|
||||||
|
return new audio::orchestra::api::Dummy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -45,14 +48,14 @@ enum audio::orchestra::error audio::orchestra::api::Dummy::abortStream() {
|
|||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Dummy::open(uint32_t _device,
|
bool audio::orchestra::api::Dummy::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,22 +4,23 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef ORCHESTRA_BUILD_DUMMY
|
#if !defined(__AUDIO_ORCHESTRA_DUMMY__) && defined(ORCHESTRA_BUILD_DUMMY)
|
||||||
|
#define __AUDIO_ORCHESTRA_DUMMY__
|
||||||
|
|
||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
namespace api {
|
namespace api {
|
||||||
class Dummy: public audio::orchestra::Api {
|
class Dummy: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Dummy();
|
Dummy();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeDummy;
|
return audio::orchestra::type_dummy;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -28,14 +29,14 @@ namespace audio {
|
|||||||
enum audio::orchestra::error stopStream();
|
enum audio::orchestra::error stopStream();
|
||||||
enum audio::orchestra::error abortStream();
|
enum audio::orchestra::error abortStream();
|
||||||
private:
|
private:
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,11 +13,13 @@
|
|||||||
#include <audio/orchestra/Interface.h>
|
#include <audio/orchestra/Interface.h>
|
||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ethread/tools.h>
|
#include <etk/thread/tools.h>
|
||||||
#include <audio/orchestra/api/Jack.h>
|
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Jack::create() {
|
#undef __class__
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Jack>(new audio::orchestra::api::Jack());
|
#define __class__ "api::Jack"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::Jack::create() {
|
||||||
|
return new audio::orchestra::api::Jack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ namespace audio {
|
|||||||
jack_port_t **ports[2];
|
jack_port_t **ports[2];
|
||||||
std::string deviceName[2];
|
std::string deviceName[2];
|
||||||
bool xrun[2];
|
bool xrun[2];
|
||||||
std::condition_variable condition;
|
std11::condition_variable condition;
|
||||||
int32_t drainCounter; // Tracks callback counts when draining
|
int32_t drainCounter; // Tracks callback counts when draining
|
||||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||||
|
|
||||||
@@ -89,7 +91,7 @@ audio::orchestra::api::Jack::Jack() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::api::Jack::~Jack() {
|
audio::orchestra::api::Jack::~Jack() {
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,36 +125,34 @@ uint32_t audio::orchestra::api::Jack::getDeviceCount() {
|
|||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
return nDevices*2;
|
return nDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t _device) {
|
audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||||
audio::orchestra::DeviceInfo info;
|
audio::orchestra::DeviceInfo info;
|
||||||
|
info.probed = false;
|
||||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
||||||
jack_status_t *status = nullptr;
|
jack_status_t *status = nullptr;
|
||||||
jack_client_t *client = jack_client_open("orchestraJackInfo", options, status);
|
jack_client_t *client = jack_client_open("orchestraJackInfo", options, status);
|
||||||
if (client == nullptr) {
|
if (client == nullptr) {
|
||||||
ATA_ERROR("Jack server not found or connection error!");
|
ATA_ERROR("Jack server not found or connection error!");
|
||||||
// TODO : audio::orchestra::error_warning;
|
// TODO : audio::orchestra::error_warning;
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
const char **ports;
|
const char **ports;
|
||||||
std::string port, previousPort;
|
std::string port, previousPort;
|
||||||
uint32_t nPorts = 0, nDevices = 0;
|
uint32_t nPorts = 0, nDevices = 0;
|
||||||
ports = jack_get_ports(client, nullptr, nullptr, 0);
|
ports = jack_get_ports(client, nullptr, nullptr, 0);
|
||||||
int32_t deviceID = _device/2;
|
|
||||||
info.input = _device%2==0?true:false; // note that jack sens are inverted
|
|
||||||
if (ports) {
|
if (ports) {
|
||||||
// Parse the port names up to the first colon (:).
|
// Parse the port names up to the first colon (:).
|
||||||
size_t iColon = 0;
|
size_t iColon = 0;
|
||||||
do {
|
do {
|
||||||
port = (char *) ports[nPorts];
|
port = (char *) ports[ nPorts ];
|
||||||
iColon = port.find(":");
|
iColon = port.find(":");
|
||||||
if (iColon != std::string::npos) {
|
if (iColon != std::string::npos) {
|
||||||
port = port.substr(0, iColon);
|
port = port.substr(0, iColon);
|
||||||
if (port != previousPort) {
|
if (port != previousPort) {
|
||||||
if (nDevices == deviceID) {
|
if (nDevices == _device) {
|
||||||
info.name = port;
|
info.name = port;
|
||||||
}
|
}
|
||||||
nDevices++;
|
nDevices++;
|
||||||
@@ -162,7 +162,7 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t
|
|||||||
} while (ports[++nPorts]);
|
} while (ports[++nPorts]);
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
if (deviceID >= nDevices) {
|
if (_device >= nDevices) {
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
ATA_ERROR("device ID is invalid!");
|
ATA_ERROR("device ID is invalid!");
|
||||||
// TODO : audio::orchestra::error_invalidUse;
|
// TODO : audio::orchestra::error_invalidUse;
|
||||||
@@ -171,44 +171,50 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t
|
|||||||
// Get the current jack server sample rate.
|
// Get the current jack server sample rate.
|
||||||
info.sampleRates.clear();
|
info.sampleRates.clear();
|
||||||
info.sampleRates.push_back(jack_get_sample_rate(client));
|
info.sampleRates.push_back(jack_get_sample_rate(client));
|
||||||
if (info.input == true) {
|
// Count the available ports containing the client name as device
|
||||||
ports = jack_get_ports(client, info.name.c_str(), nullptr, JackPortIsOutput);
|
// channels. Jack "input ports" equal RtAudio output channels.
|
||||||
if (ports) {
|
uint32_t nChannels = 0;
|
||||||
int32_t iii=0;
|
ports = jack_get_ports(client, info.name.c_str(), nullptr, JackPortIsInput);
|
||||||
while (ports[iii]) {
|
if (ports) {
|
||||||
ATA_ERROR(" ploppp='" << ports[iii] << "'");
|
while (ports[ nChannels ]) {
|
||||||
info.channels.push_back(audio::channel_unknow);
|
nChannels++;
|
||||||
iii++;
|
|
||||||
}
|
|
||||||
free(ports);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ports = jack_get_ports(client, info.name.c_str(), nullptr, JackPortIsInput);
|
|
||||||
if (ports) {
|
|
||||||
int32_t iii=0;
|
|
||||||
while (ports[iii]) {
|
|
||||||
ATA_ERROR(" ploppp='" << ports[iii] << "'");
|
|
||||||
info.channels.push_back(audio::channel_unknow);
|
|
||||||
iii++;
|
|
||||||
}
|
|
||||||
free(ports);
|
|
||||||
}
|
}
|
||||||
|
free(ports);
|
||||||
|
info.outputChannels = nChannels;
|
||||||
}
|
}
|
||||||
if (info.channels.size() == 0) {
|
// Jack "output ports" equal RtAudio input channels.
|
||||||
|
nChannels = 0;
|
||||||
|
ports = jack_get_ports(client, info.name.c_str(), nullptr, JackPortIsOutput);
|
||||||
|
if (ports) {
|
||||||
|
while (ports[ nChannels ]) {
|
||||||
|
nChannels++;
|
||||||
|
}
|
||||||
|
free(ports);
|
||||||
|
info.inputChannels = nChannels;
|
||||||
|
}
|
||||||
|
if (info.outputChannels == 0 && info.inputChannels == 0) {
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
ATA_ERROR("error determining Jack input/output channels!");
|
ATA_ERROR("error determining Jack input/output channels!");
|
||||||
// TODO : audio::orchestra::error_warning;
|
// TODO : audio::orchestra::error_warning;
|
||||||
info.clear();
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
// If device opens for both playback and capture, we determine the channels.
|
||||||
|
if (info.outputChannels > 0 && info.inputChannels > 0) {
|
||||||
|
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||||
|
}
|
||||||
// Jack always uses 32-bit floats.
|
// Jack always uses 32-bit floats.
|
||||||
info.nativeFormats.push_back(audio::format_float);
|
info.nativeFormats.push_back(audio::format_float);
|
||||||
// Jack doesn't provide default devices so we'll use the first available one.
|
// Jack doesn't provide default devices so we'll use the first available one.
|
||||||
if (deviceID == 0) {
|
if ( _device == 0
|
||||||
info.isDefault = true;
|
&& info.outputChannels > 0) {
|
||||||
|
info.isDefaultOutput = true;
|
||||||
|
}
|
||||||
|
if ( _device == 0
|
||||||
|
&& info.inputChannels > 0) {
|
||||||
|
info.isDefaultInput = true;
|
||||||
}
|
}
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
info.isCorrect = true;
|
info.probed = true;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +234,7 @@ int32_t audio::orchestra::api::Jack::jackCallbackHandler(jack_nframes_t _nframes
|
|||||||
// it this way because the jackShutdown() function must return before
|
// it this way because the jackShutdown() function must return before
|
||||||
// the jack_deactivate() function (in closeStream()) will return.
|
// the jack_deactivate() function (in closeStream()) will return.
|
||||||
void audio::orchestra::api::Jack::jackCloseStream(void* _userData) {
|
void audio::orchestra::api::Jack::jackCloseStream(void* _userData) {
|
||||||
ethread::setName("Jack_closeStream");
|
etk::thread::setName("Jack_closeStream");
|
||||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||||
myClass->closeStream();
|
myClass->closeStream();
|
||||||
}
|
}
|
||||||
@@ -243,7 +249,7 @@ void audio::orchestra::api::Jack::jackShutdown(void* _userData) {
|
|||||||
if (myClass->isStreamRunning() == false) {
|
if (myClass->isStreamRunning() == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new std::thread(&audio::orchestra::api::Jack::jackCloseStream, _userData);
|
new std11::thread(&audio::orchestra::api::Jack::jackCloseStream, _userData);
|
||||||
ATA_ERROR("The Jack server is shutting down this client ... stream stopped and closed!!");
|
ATA_ERROR("The Jack server is shutting down this client ... stream stopped and closed!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,14 +264,14 @@ int32_t audio::orchestra::api::Jack::jackXrun(void* _userData) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Jack::open(uint32_t _device,
|
bool audio::orchestra::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t* _bufferSize,
|
uint32_t* _bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
// Look for jack server and try to become a client (only do once per stream).
|
// Look for jack server and try to become a client (only do once per stream).
|
||||||
jack_client_t *client = 0;
|
jack_client_t *client = 0;
|
||||||
if ( _mode == audio::orchestra::mode_output
|
if ( _mode == audio::orchestra::mode_output
|
||||||
@@ -289,8 +295,6 @@ bool audio::orchestra::api::Jack::open(uint32_t _device,
|
|||||||
const char **ports;
|
const char **ports;
|
||||||
std::string port, previousPort, deviceName;
|
std::string port, previousPort, deviceName;
|
||||||
uint32_t nPorts = 0, nDevices = 0;
|
uint32_t nPorts = 0, nDevices = 0;
|
||||||
int32_t deviceID = _device/2;
|
|
||||||
bool isInput = _device%2==0?true:false;
|
|
||||||
ports = jack_get_ports(client, nullptr, nullptr, 0);
|
ports = jack_get_ports(client, nullptr, nullptr, 0);
|
||||||
if (ports) {
|
if (ports) {
|
||||||
// Parse the port names up to the first colon (:).
|
// Parse the port names up to the first colon (:).
|
||||||
@@ -301,7 +305,7 @@ bool audio::orchestra::api::Jack::open(uint32_t _device,
|
|||||||
if (iColon != std::string::npos) {
|
if (iColon != std::string::npos) {
|
||||||
port = port.substr(0, iColon);
|
port = port.substr(0, iColon);
|
||||||
if (port != previousPort) {
|
if (port != previousPort) {
|
||||||
if (nDevices == deviceID) {
|
if (nDevices == _device) {
|
||||||
deviceName = port;
|
deviceName = port;
|
||||||
}
|
}
|
||||||
nDevices++;
|
nDevices++;
|
||||||
@@ -319,9 +323,7 @@ bool audio::orchestra::api::Jack::open(uint32_t _device,
|
|||||||
// channels. Jack "input ports" equal RtAudio output channels.
|
// channels. Jack "input ports" equal RtAudio output channels.
|
||||||
uint32_t nChannels = 0;
|
uint32_t nChannels = 0;
|
||||||
uint64_t flag = JackPortIsInput;
|
uint64_t flag = JackPortIsInput;
|
||||||
if (_mode == audio::orchestra::mode_input) {
|
if (_mode == audio::orchestra::mode_input) flag = JackPortIsOutput;
|
||||||
flag = JackPortIsOutput;
|
|
||||||
}
|
|
||||||
ports = jack_get_ports(client, deviceName.c_str(), nullptr, flag);
|
ports = jack_get_ports(client, deviceName.c_str(), nullptr, flag);
|
||||||
if (ports) {
|
if (ports) {
|
||||||
while (ports[ nChannels ]) {
|
while (ports[ nChannels ]) {
|
||||||
@@ -423,7 +425,7 @@ bool audio::orchestra::api::Jack::open(uint32_t _device,
|
|||||||
}
|
}
|
||||||
m_device[modeToIdTable(_mode)] = _device;
|
m_device[modeToIdTable(_mode)] = _device;
|
||||||
m_channelOffset[modeToIdTable(_mode)] = _firstChannel;
|
m_channelOffset[modeToIdTable(_mode)] = _firstChannel;
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
if ( m_mode == audio::orchestra::mode_output
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
&& _mode == audio::orchestra::mode_input) {
|
&& _mode == audio::orchestra::mode_input) {
|
||||||
// We had already set up the stream for output.
|
// We had already set up the stream for output.
|
||||||
@@ -483,12 +485,12 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Jack::closeStream() {
|
enum audio::orchestra::error audio::orchestra::api::Jack::closeStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("no open stream to close!");
|
ATA_ERROR("no open stream to close!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
if (m_private != nullptr) {
|
if (m_private != nullptr) {
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
jack_deactivate(m_private->client);
|
jack_deactivate(m_private->client);
|
||||||
}
|
}
|
||||||
jack_client_close(m_private->client);
|
jack_client_close(m_private->client);
|
||||||
@@ -509,7 +511,7 @@ enum audio::orchestra::error audio::orchestra::api::Jack::closeStream() {
|
|||||||
m_deviceBuffer = nullptr;
|
m_deviceBuffer = nullptr;
|
||||||
}
|
}
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,7 +521,7 @@ enum audio::orchestra::error audio::orchestra::api::Jack::startStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
ATA_ERROR("the stream is already running!");
|
ATA_ERROR("the stream is already running!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -577,7 +579,7 @@ enum audio::orchestra::error audio::orchestra::api::Jack::startStream() {
|
|||||||
}
|
}
|
||||||
m_private->drainCounter = 0;
|
m_private->drainCounter = 0;
|
||||||
m_private->internalDrain = false;
|
m_private->internalDrain = false;
|
||||||
m_state = audio::orchestra::state::running;
|
m_state = audio::orchestra::state_running;
|
||||||
unlock:
|
unlock:
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
@@ -589,7 +591,7 @@ enum audio::orchestra::error audio::orchestra::api::Jack::stopStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -597,12 +599,12 @@ enum audio::orchestra::error audio::orchestra::api::Jack::stopStream() {
|
|||||||
|| m_mode == audio::orchestra::mode_duplex) {
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
if (m_private->drainCounter == 0) {
|
if (m_private->drainCounter == 0) {
|
||||||
m_private->drainCounter = 2;
|
m_private->drainCounter = 2;
|
||||||
std::unique_lock<std::mutex> lck(m_mutex);
|
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||||
m_private->condition.wait(lck);
|
m_private->condition.wait(lck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jack_deactivate(m_private->client);
|
jack_deactivate(m_private->client);
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +612,7 @@ enum audio::orchestra::error audio::orchestra::api::Jack::abortStream() {
|
|||||||
if (verifyStream() != audio::orchestra::error_none) {
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
return audio::orchestra::error_fail;
|
return audio::orchestra::error_fail;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
@@ -624,17 +626,17 @@ enum audio::orchestra::error audio::orchestra::api::Jack::abortStream() {
|
|||||||
// callbackEvent() function must return before the jack_deactivate()
|
// callbackEvent() function must return before the jack_deactivate()
|
||||||
// function will return.
|
// function will return.
|
||||||
static void jackStopStream(void* _userData) {
|
static void jackStopStream(void* _userData) {
|
||||||
ethread::setName("Jack_stopStream");
|
etk::thread::setName("Jack_stopStream");
|
||||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||||
myClass->stopStream();
|
myClass->stopStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||||
if ( m_state == audio::orchestra::state::stopped
|
if ( m_state == audio::orchestra::state_stopped
|
||||||
|| m_state == audio::orchestra::state::stopping) {
|
|| m_state == audio::orchestra::state_stopping) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -644,9 +646,9 @@ bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
|||||||
}
|
}
|
||||||
// Check if we were draining the stream and signal is finished.
|
// Check if we were draining the stream and signal is finished.
|
||||||
if (m_private->drainCounter > 3) {
|
if (m_private->drainCounter > 3) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
if (m_private->internalDrain == true) {
|
if (m_private->internalDrain == true) {
|
||||||
new std::thread(jackStopStream, this);
|
new std11::thread(jackStopStream, this);
|
||||||
} else {
|
} else {
|
||||||
m_private->condition.notify_one();
|
m_private->condition.notify_one();
|
||||||
}
|
}
|
||||||
@@ -657,11 +659,11 @@ bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
|||||||
audio::Time streamTime = getStreamTime();
|
audio::Time streamTime = getStreamTime();
|
||||||
std::vector<enum audio::orchestra::status> status;
|
std::vector<enum audio::orchestra::status> status;
|
||||||
if (m_mode != audio::orchestra::mode_input && m_private->xrun[0] == true) {
|
if (m_mode != audio::orchestra::mode_input && m_private->xrun[0] == true) {
|
||||||
status.push_back(audio::orchestra::status::underflow);
|
status.push_back(audio::orchestra::status_underflow);
|
||||||
m_private->xrun[0] = false;
|
m_private->xrun[0] = false;
|
||||||
}
|
}
|
||||||
if (m_mode != audio::orchestra::mode_output && m_private->xrun[1] == true) {
|
if (m_mode != audio::orchestra::mode_output && m_private->xrun[1] == true) {
|
||||||
status.push_back(audio::orchestra::status::overflow);
|
status.push_back(audio::orchestra::status_overflow);
|
||||||
m_private->xrun[1] = false;
|
m_private->xrun[1] = false;
|
||||||
}
|
}
|
||||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||||
@@ -671,9 +673,9 @@ bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
|||||||
m_bufferSize,
|
m_bufferSize,
|
||||||
status);
|
status);
|
||||||
if (cbReturnValue == 2) {
|
if (cbReturnValue == 2) {
|
||||||
m_state = audio::orchestra::state::stopping;
|
m_state = audio::orchestra::state_stopping;
|
||||||
m_private->drainCounter = 2;
|
m_private->drainCounter = 2;
|
||||||
new std::thread(jackStopStream, this);
|
new std11::thread(jackStopStream, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cbReturnValue == 1) {
|
else if (cbReturnValue == 1) {
|
||||||
|
@@ -4,8 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_JACK
|
#if !defined(__AUDIO_ORCHESTRA_API_JACK_H__) && defined(ORCHESTRA_BUILD_JACK)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_JACK_H__
|
||||||
|
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
|
|
||||||
@@ -15,12 +16,12 @@ namespace audio {
|
|||||||
class JackPrivate;
|
class JackPrivate;
|
||||||
class Jack: public audio::orchestra::Api {
|
class Jack: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Jack();
|
Jack();
|
||||||
virtual ~Jack();
|
virtual ~Jack();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typeJack;
|
return audio::orchestra::type_jack;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -40,15 +41,15 @@ namespace audio {
|
|||||||
static void jackShutdown(void* _userData);
|
static void jackShutdown(void* _userData);
|
||||||
static int32_t jackCallbackHandler(jack_nframes_t _nframes, void* _userData);
|
static int32_t jackCallbackHandler(jack_nframes_t _nframes, void* _userData);
|
||||||
private:
|
private:
|
||||||
ememory::SharedPtr<JackPrivate> m_private;
|
std11::shared_ptr<JackPrivate> m_private;
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
830
audio/orchestra/api/Oss.cpp
Normal file
830
audio/orchestra/api/Oss.cpp
Normal file
@@ -0,0 +1,830 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
* @fork from RTAudio
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(ORCHESTRA_BUILD_OSS)
|
||||||
|
#include <audio/orchestra/Interface.h>
|
||||||
|
#include <audio/orchestra/debug.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "soundcard.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "api::Oss"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::Oss::create() {
|
||||||
|
return new audio::orchestra::api::Oss();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *ossCallbackHandler(void* _userData);
|
||||||
|
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
namespace orchestra {
|
||||||
|
namespace api {
|
||||||
|
class OssPrivate {
|
||||||
|
public:
|
||||||
|
int32_t id[2]; // device ids
|
||||||
|
bool xrun[2];
|
||||||
|
bool triggered;
|
||||||
|
std11::condition_variable runnable;
|
||||||
|
std11::shared_ptr<std11::thread> thread;
|
||||||
|
bool threadRunning;
|
||||||
|
OssPrivate():
|
||||||
|
triggered(false),
|
||||||
|
threadRunning(false) {
|
||||||
|
id[0] = 0;
|
||||||
|
id[1] = 0;
|
||||||
|
xrun[0] = false;
|
||||||
|
xrun[1] = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audio::orchestra::api::Oss::Oss() :
|
||||||
|
m_private(new audio::orchestra::api::OssPrivate()) {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
audio::orchestra::api::Oss::~Oss() {
|
||||||
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
|
closeStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t audio::orchestra::api::Oss::getDeviceCount() {
|
||||||
|
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||||
|
if (mixerfd == -1) {
|
||||||
|
ATA_ERROR("error opening '/dev/mixer'.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
oss_sysinfo sysinfo;
|
||||||
|
if (ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo) == -1) {
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("error getting sysinfo, OSS version >= 4.0 is required.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
close(mixerfd);
|
||||||
|
return sysinfo.numaudios;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio::orchestra::DeviceInfo audio::orchestra::api::Oss::getDeviceInfo(uint32_t _device) {
|
||||||
|
rtaudio::DeviceInfo info;
|
||||||
|
info.probed = false;
|
||||||
|
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||||
|
if (mixerfd == -1) {
|
||||||
|
ATA_ERROR("error opening '/dev/mixer'.");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
oss_sysinfo sysinfo;
|
||||||
|
int32_t result = ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo);
|
||||||
|
if (result == -1) {
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("error getting sysinfo, OSS version >= 4.0 is required.");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
unsigned nDevices = sysinfo.numaudios;
|
||||||
|
if (nDevices == 0) {
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("no devices found!");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
if (_device >= nDevices) {
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("device ID is invalid!");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
oss_audioinfo ainfo;
|
||||||
|
ainfo.dev = _device;
|
||||||
|
result = ioctl(mixerfd, SNDCTL_AUDIOINFO, &ainfo);
|
||||||
|
close(mixerfd);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("error getting device (" << ainfo.name << ") info.");
|
||||||
|
error(audio::orchestra::error_warning);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
// Probe channels
|
||||||
|
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_output) {
|
||||||
|
info.outputChannels = ainfo.max_channels;
|
||||||
|
}
|
||||||
|
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_input) {
|
||||||
|
info.inputChannels = ainfo.max_channels;
|
||||||
|
}
|
||||||
|
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex) {
|
||||||
|
if ( info.outputChannels > 0
|
||||||
|
&& info.inputChannels > 0
|
||||||
|
&& ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex) {
|
||||||
|
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Probe data formats ... do for input
|
||||||
|
uint64_t mask = ainfo.iformats;
|
||||||
|
if ( mask & AFMT_S16_LE
|
||||||
|
|| mask & AFMT_S16_BE) {
|
||||||
|
info.nativeFormats.push_back(audio::format_int16);
|
||||||
|
}
|
||||||
|
if (mask & AFMT_S8) {
|
||||||
|
info.nativeFormats.push_back(audio::format_int8);
|
||||||
|
}
|
||||||
|
if ( mask & AFMT_S32_LE
|
||||||
|
|| mask & AFMT_S32_BE) {
|
||||||
|
info.nativeFormats.push_back(audio::format_int32);
|
||||||
|
}
|
||||||
|
if (mask & AFMT_FLOAT) {
|
||||||
|
info.nativeFormats.push_back(audio::format_float);
|
||||||
|
}
|
||||||
|
if ( mask & AFMT_S24_LE
|
||||||
|
|| mask & AFMT_S24_BE) {
|
||||||
|
info.nativeFormats.push_back(audio::format_int24);
|
||||||
|
}
|
||||||
|
// Check that we have at least one supported format
|
||||||
|
if (info.nativeFormats == 0) {
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") data format not supported by RtAudio.");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
// Probe the supported sample rates.
|
||||||
|
info.sampleRates.clear();
|
||||||
|
if (ainfo.nrates) {
|
||||||
|
for (uint32_t i=0; i<ainfo.nrates; i++) {
|
||||||
|
for (uint32_t k=0; k<MAX_SAMPLE_RATES; k++) {
|
||||||
|
if (ainfo.rates[i] == SAMPLE_RATES[k]) {
|
||||||
|
info.sampleRates.push_back(SAMPLE_RATES[k]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check min and max rate values;
|
||||||
|
for (uint32_t k=0; k<MAX_SAMPLE_RATES; k++) {
|
||||||
|
if ( ainfo.min_rate <= (int) SAMPLE_RATES[k]
|
||||||
|
&& ainfo.max_rate >= (int) SAMPLE_RATES[k]) {
|
||||||
|
info.sampleRates.push_back(SAMPLE_RATES[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info.sampleRates.size() == 0) {
|
||||||
|
ATA_ERROR("no supported sample rates found for device (" << ainfo.name << ").");
|
||||||
|
} else {
|
||||||
|
info.probed = true;
|
||||||
|
info.name = ainfo.name;
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool audio::orchestra::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||||
|
StreamMode _mode,
|
||||||
|
uint32_t _channels,
|
||||||
|
uint32_t _firstChannel,
|
||||||
|
uint32_t _sampleRate,
|
||||||
|
rtaudio::format _format,
|
||||||
|
uint32_t* _bufferSize,
|
||||||
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
|
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||||
|
if (mixerfd == -1) {
|
||||||
|
ATA_ERROR("error opening '/dev/mixer'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
oss_sysinfo sysinfo;
|
||||||
|
int32_t result = ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo);
|
||||||
|
if (result == -1) {
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("error getting sysinfo, OSS version >= 4.0 is required.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned nDevices = sysinfo.numaudios;
|
||||||
|
if (nDevices == 0) {
|
||||||
|
// This should not happen because a check is made before this function is called.
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("no devices found!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_device >= nDevices) {
|
||||||
|
// This should not happen because a check is made before this function is called.
|
||||||
|
close(mixerfd);
|
||||||
|
ATA_ERROR("device ID is invalid!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
oss_audioinfo ainfo;
|
||||||
|
ainfo.dev = _device;
|
||||||
|
result = ioctl(mixerfd, SNDCTL_AUDIOINFO, &ainfo);
|
||||||
|
close(mixerfd);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("error getting device (" << ainfo.name << ") info.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check if device supports input or output
|
||||||
|
if ( ( _mode == audio::orchestra::mode_output
|
||||||
|
&& !(ainfo.caps & PCM_CAP_audio::orchestra::mode_output))
|
||||||
|
|| ( _mode == audio::orchestra::mode_input
|
||||||
|
&& !(ainfo.caps & PCM_CAP_audio::orchestra::mode_input))) {
|
||||||
|
if (_mode == audio::orchestra::mode_output) {
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") does not support output.");
|
||||||
|
} else {
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") does not support input.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int32_t flags = 0;
|
||||||
|
if (_mode == audio::orchestra::mode_output) {
|
||||||
|
flags |= O_WRONLY;
|
||||||
|
} else { // _mode == audio::orchestra::mode_input
|
||||||
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|
&& m_device[0] == _device) {
|
||||||
|
// We just set the same device for playback ... close and reopen for duplex (OSS only).
|
||||||
|
close(m_private->id[0]);
|
||||||
|
m_private->id[0] = 0;
|
||||||
|
if (!(ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex)) {
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") does not support duplex mode.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check that the number previously set channels is the same.
|
||||||
|
if (m_nUserChannels[0] != _channels) {
|
||||||
|
ATA_ERROR("input/output channels must be equal for OSS duplex device (" << ainfo.name << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
flags |= O_RDWR;
|
||||||
|
} else {
|
||||||
|
flags |= O_RDONLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set exclusive access if specified.
|
||||||
|
if (_options.flags & RTAUDIO_HOG_DEVICE) {
|
||||||
|
flags |= O_EXCL;
|
||||||
|
}
|
||||||
|
// Try to open the device.
|
||||||
|
int32_t fd;
|
||||||
|
fd = open(ainfo.devnode, flags, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno == EBUSY) {
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") is busy.");
|
||||||
|
} else {
|
||||||
|
ATA_ERROR("error opening device (" << ainfo.name << ").");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// For duplex operation, specifically set this mode (this doesn't seem to work).
|
||||||
|
/*
|
||||||
|
if (flags | O_RDWR) {
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_SETaudio::orchestra::mode_duplex, nullptr);
|
||||||
|
if (result == -1) {
|
||||||
|
m_errorStream << "error setting duplex mode for device (" << ainfo.name << ").";
|
||||||
|
m_errorText = m_errorStream.str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Check the device channel support.
|
||||||
|
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||||
|
if (ainfo.max_channels < (int)(_channels + _firstChannel)) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("the device (" << ainfo.name << ") does not support requested channel parameters.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Set the number of channels.
|
||||||
|
int32_t deviceChannels = _channels + _firstChannel;
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_CHANNELS, &deviceChannels);
|
||||||
|
if ( result == -1
|
||||||
|
|| deviceChannels < (int)(_channels + _firstChannel)) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("error setting channel parameters on device (" << ainfo.name << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_nDeviceChannels[modeToIdTable(_mode)] = deviceChannels;
|
||||||
|
// Get the data format mask
|
||||||
|
int32_t mask;
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_GETFMTS, &mask);
|
||||||
|
if (result == -1) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("error getting device (" << ainfo.name << ") data formats.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Determine how to set the device format.
|
||||||
|
m_userFormat = _format;
|
||||||
|
int32_t deviceFormat = -1;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = false;
|
||||||
|
if (_format == RTAUDIO_SINT8) {
|
||||||
|
if (mask & AFMT_S8) {
|
||||||
|
deviceFormat = AFMT_S8;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT8;
|
||||||
|
}
|
||||||
|
} else if (_format == RTAUDIO_SINT16) {
|
||||||
|
if (mask & AFMT_S16_NE) {
|
||||||
|
deviceFormat = AFMT_S16_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT16;
|
||||||
|
} else if (mask & AFMT_S16_OE) {
|
||||||
|
deviceFormat = AFMT_S16_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT16;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
}
|
||||||
|
} else if (_format == RTAUDIO_SINT24) {
|
||||||
|
if (mask & AFMT_S24_NE) {
|
||||||
|
deviceFormat = AFMT_S24_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT24;
|
||||||
|
} else if (mask & AFMT_S24_OE) {
|
||||||
|
deviceFormat = AFMT_S24_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT24;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
}
|
||||||
|
} else if (_format == RTAUDIO_SINT32) {
|
||||||
|
if (mask & AFMT_S32_NE) {
|
||||||
|
deviceFormat = AFMT_S32_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT32;
|
||||||
|
} else if (mask & AFMT_S32_OE) {
|
||||||
|
deviceFormat = AFMT_S32_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT32;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deviceFormat == -1) {
|
||||||
|
// The user requested format is not natively supported by the device.
|
||||||
|
if (mask & AFMT_S16_NE) {
|
||||||
|
deviceFormat = AFMT_S16_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT16;
|
||||||
|
} else if (mask & AFMT_S32_NE) {
|
||||||
|
deviceFormat = AFMT_S32_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT32;
|
||||||
|
} else if (mask & AFMT_S24_NE) {
|
||||||
|
deviceFormat = AFMT_S24_NE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT24;
|
||||||
|
} else if (mask & AFMT_S16_OE) {
|
||||||
|
deviceFormat = AFMT_S16_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT16;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
} else if (mask & AFMT_S32_OE) {
|
||||||
|
deviceFormat = AFMT_S32_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT32;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
} else if (mask & AFMT_S24_OE) {
|
||||||
|
deviceFormat = AFMT_S24_OE;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT24;
|
||||||
|
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||||
|
} else if (mask & AFMT_S8) {
|
||||||
|
deviceFormat = AFMT_S8;
|
||||||
|
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_deviceFormat[modeToIdTable(_mode)] == 0) {
|
||||||
|
// This really shouldn't happen ...
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") data format not supported by RtAudio.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Set the data format.
|
||||||
|
int32_t temp = deviceFormat;
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_SETFMT, &deviceFormat);
|
||||||
|
if ( result == -1
|
||||||
|
|| deviceFormat != temp) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("error setting data format on device (" << ainfo.name << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Attempt to set the buffer size. According to OSS, the minimum
|
||||||
|
// number of buffers is two. The supposed minimum buffer size is 16
|
||||||
|
// bytes, so that will be our lower bound. The argument to this
|
||||||
|
// call is in the form 0xMMMMSSSS (hex), where the buffer size (in
|
||||||
|
// bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
|
||||||
|
// We'll check the actual value used near the end of the setup
|
||||||
|
// procedure.
|
||||||
|
int32_t ossBufferBytes = *_bufferSize * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]) * deviceChannels;
|
||||||
|
if (ossBufferBytes < 16) {
|
||||||
|
ossBufferBytes = 16;
|
||||||
|
}
|
||||||
|
int32_t buffers = 0;
|
||||||
|
buffers = _options.numberOfBuffers;
|
||||||
|
if (_options.flags.m_minimizeLatency == true) {
|
||||||
|
buffers = 2;
|
||||||
|
}
|
||||||
|
if (buffers < 2) {
|
||||||
|
buffers = 3;
|
||||||
|
}
|
||||||
|
temp = ((int) buffers << 16) + (int)(log10((double)ossBufferBytes) / log10(2.0));
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp);
|
||||||
|
if (result == -1) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("error setting buffer size on device (" << ainfo.name << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_nBuffers = buffers;
|
||||||
|
// Save buffer size (in sample frames).
|
||||||
|
*_bufferSize = ossBufferBytes / (audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]) * deviceChannels);
|
||||||
|
m_bufferSize = *_bufferSize;
|
||||||
|
// Set the sample rate.
|
||||||
|
int32_t srate = _sampleRate;
|
||||||
|
result = ioctl(fd, SNDCTL_DSP_SPEED, &srate);
|
||||||
|
if (result == -1) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("error setting sample rate (" << _sampleRate << ") on device (" << ainfo.name << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Verify the sample rate setup worked.
|
||||||
|
if (abs(srate - _sampleRate) > 100) {
|
||||||
|
close(fd);
|
||||||
|
ATA_ERROR("device (" << ainfo.name << ") does not support sample rate (" << _sampleRate << ").");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_sampleRate = _sampleRate;
|
||||||
|
if ( _mode == audio::orchestra::mode_input
|
||||||
|
&& m__mode == audio::orchestra::mode_output
|
||||||
|
&& m_device[0] == _device) {
|
||||||
|
// We're doing duplex setup here.
|
||||||
|
m_deviceFormat[0] = m_deviceFormat[1];
|
||||||
|
m_nDeviceChannels[0] = deviceChannels;
|
||||||
|
}
|
||||||
|
// Set interleaving parameters.
|
||||||
|
m_deviceInterleaved[modeToIdTable(_mode)] = true;
|
||||||
|
// Set flags for buffer conversion
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
m_private->id[modeToIdTable(_mode)] = fd;
|
||||||
|
// Allocate necessary internal buffers.
|
||||||
|
uint64_t bufferBytes;
|
||||||
|
bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||||
|
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
|
||||||
|
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) {
|
||||||
|
ATA_ERROR("error allocating user buffer memory.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||||
|
bool makeBuffer = true;
|
||||||
|
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||||
|
if (_mode == audio::orchestra::mode_input) {
|
||||||
|
if ( m__mode == audio::orchestra::mode_output
|
||||||
|
&& m_deviceBuffer) {
|
||||||
|
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||||
|
if (bufferBytes <= bytesOut) {
|
||||||
|
makeBuffer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (makeBuffer) {
|
||||||
|
bufferBytes *= *_bufferSize;
|
||||||
|
if (m_deviceBuffer) {
|
||||||
|
free(m_deviceBuffer);
|
||||||
|
}
|
||||||
|
m_deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||||
|
if (m_deviceBuffer == nullptr) {
|
||||||
|
ATA_ERROR("error allocating device buffer memory.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_device[modeToIdTable(_mode)] = _device;
|
||||||
|
m_state = audio::orchestra::state_stopped;
|
||||||
|
// Setup the buffer conversion information structure.
|
||||||
|
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||||
|
setConvertInfo(_mode, _firstChannel);
|
||||||
|
}
|
||||||
|
// Setup thread if necessary.
|
||||||
|
if (m_mode == audio::orchestra::mode_output && _mode == audio::orchestra::mode_input) {
|
||||||
|
// We had already set up an output stream.
|
||||||
|
m_mode = audio::orchestra::mode_duplex;
|
||||||
|
if (m_device[0] == _device) {
|
||||||
|
m_private->id[0] = fd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_mode = _mode;
|
||||||
|
// Setup callback thread.
|
||||||
|
m_private->threadRunning = true;
|
||||||
|
m_private->thread = new std11::thread(ossCallbackHandler, this);
|
||||||
|
if (m_private->thread == nullptr) {
|
||||||
|
m_private->threadRunning = false;
|
||||||
|
ATA_ERROR("creating callback thread!");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
error:
|
||||||
|
if (m_private->id[0] != nullptr) {
|
||||||
|
close(m_private->id[0]);
|
||||||
|
m_private->id[0] = nullptr;
|
||||||
|
}
|
||||||
|
if (m_private->id[1] != nullptr) {
|
||||||
|
close(m_private->id[1]);
|
||||||
|
m_private->id[1] = nullptr;
|
||||||
|
}
|
||||||
|
for (int32_t i=0; i<2; i++) {
|
||||||
|
if (m_userBuffer[i]) {
|
||||||
|
free(m_userBuffer[i]);
|
||||||
|
m_userBuffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_deviceBuffer) {
|
||||||
|
free(m_deviceBuffer);
|
||||||
|
m_deviceBuffer = 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::error audio::orchestra::api::Oss::closeStream() {
|
||||||
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
|
ATA_ERROR("no open stream to close!");
|
||||||
|
return audio::orchestra::error_warning;
|
||||||
|
}
|
||||||
|
m_private->threadRunning = false;
|
||||||
|
m_mutex.lock();
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
m_private->runnable.notify_one();
|
||||||
|
}
|
||||||
|
m_mutex.unlock();
|
||||||
|
m_private->thread->join();
|
||||||
|
if (m_state == audio::orchestra::state_running) {
|
||||||
|
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||||
|
ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||||
|
} else {
|
||||||
|
ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||||
|
}
|
||||||
|
m_state = audio::orchestra::state_stopped;
|
||||||
|
}
|
||||||
|
if (m_private->id[0] != nullptr) {
|
||||||
|
close(m_private->id[0]);
|
||||||
|
m_private->id[0] = nullptr;
|
||||||
|
}
|
||||||
|
if (m_private->id[1] != nullptr) {
|
||||||
|
close(m_private->id[1]);
|
||||||
|
m_private->id[1] = nullptr;
|
||||||
|
}
|
||||||
|
for (int32_t i=0; i<2; i++) {
|
||||||
|
if (m_userBuffer[i]) {
|
||||||
|
free(m_userBuffer[i]);
|
||||||
|
m_userBuffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_deviceBuffer) {
|
||||||
|
free(m_deviceBuffer);
|
||||||
|
m_deviceBuffer = 0;
|
||||||
|
}
|
||||||
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
|
m_state = audio::orchestra::state_closed;
|
||||||
|
return audio::orchestra::error_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::error audio::orchestra::api::Oss::startStream() {
|
||||||
|
// TODO : Check return ...
|
||||||
|
audio::orchestra::Api::startStream();
|
||||||
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
|
return audio::orchestra::error_fail;
|
||||||
|
}
|
||||||
|
if (m_state == audio::orchestra::state_running) {
|
||||||
|
ATA_ERROR("the stream is already running!");
|
||||||
|
return audio::orchestra::error_warning;
|
||||||
|
}
|
||||||
|
m_mutex.lock();
|
||||||
|
m_state = audio::orchestra::state_running;
|
||||||
|
// No need to do anything else here ... OSS automatically starts
|
||||||
|
// when fed samples.
|
||||||
|
m_mutex.unlock();
|
||||||
|
m_private->runnable.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::error audio::orchestra::api::Oss::stopStream() {
|
||||||
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
|
return audio::orchestra::error_fail;
|
||||||
|
}
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
ATA_ERROR("the stream is already stopped!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mutex.lock();
|
||||||
|
// The state might change while waiting on a mutex.
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
m_mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32_t result = 0;
|
||||||
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
|
// Flush the output with zeros a few times.
|
||||||
|
char *buffer;
|
||||||
|
int32_t samples;
|
||||||
|
audio::format format;
|
||||||
|
if (m_doConvertBuffer[0]) {
|
||||||
|
buffer = m_deviceBuffer;
|
||||||
|
samples = m_bufferSize * m_nDeviceChannels[0];
|
||||||
|
format = m_deviceFormat[0];
|
||||||
|
} else {
|
||||||
|
buffer = m_userBuffer[0];
|
||||||
|
samples = m_bufferSize * m_nUserChannels[0];
|
||||||
|
format = m_userFormat;
|
||||||
|
}
|
||||||
|
memset(buffer, 0, samples * audio::getFormatBytes(format));
|
||||||
|
for (uint32_t i=0; i<m_nBuffers+1; i++) {
|
||||||
|
result = write(m_private->id[0], buffer, samples * audio::getFormatBytes(format));
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("audio write error.");
|
||||||
|
return audio::orchestra::error_warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("system error stopping callback procedure on device (" << m_device[0] << ").");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
m_private->triggered = false;
|
||||||
|
}
|
||||||
|
if ( m_mode == audio::orchestra::mode_input
|
||||||
|
|| ( m_mode == audio::orchestra::mode_duplex
|
||||||
|
&& m_private->id[0] != m_private->id[1])) {
|
||||||
|
result = ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("system error stopping input callback procedure on device (" << m_device[0] << ").");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
m_state = audio::orchestra::state_stopped;
|
||||||
|
m_mutex.unlock();
|
||||||
|
if (result != -1) {
|
||||||
|
return audio::orchestra::error_none;
|
||||||
|
}
|
||||||
|
return audio::orchestra::error_systemError;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::error audio::orchestra::api::Oss::abortStream() {
|
||||||
|
if (verifyStream() != audio::orchestra::error_none) {
|
||||||
|
return audio::orchestra::error_fail;
|
||||||
|
}
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
ATA_ERROR("the stream is already stopped!");
|
||||||
|
return audio::orchestra::error_warning;
|
||||||
|
}
|
||||||
|
m_mutex.lock();
|
||||||
|
// The state might change while waiting on a mutex.
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
m_mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32_t result = 0;
|
||||||
|
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||||
|
result = ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("system error stopping callback procedure on device (" << m_device[0] << ").");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
m_private->triggered = false;
|
||||||
|
}
|
||||||
|
if (m_mode == audio::orchestra::mode_input || (m_mode == audio::orchestra::mode_duplex && m_private->id[0] != m_private->id[1])) {
|
||||||
|
result = ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||||
|
if (result == -1) {
|
||||||
|
ATA_ERROR("system error stopping input callback procedure on device (" << m_device[0] << ").");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
m_state = audio::orchestra::state_stopped;
|
||||||
|
m_mutex.unlock();
|
||||||
|
if (result != -1) {
|
||||||
|
return audio::orchestra::error_none;
|
||||||
|
}
|
||||||
|
return audio::orchestra::error_systemError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::orchestra::api::Oss::callbackEvent() {
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||||
|
m_private->runnable.wait(lck);
|
||||||
|
if (m_state != audio::orchestra::state_running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
|
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||||
|
return audio::orchestra::error_warning;
|
||||||
|
}
|
||||||
|
// Invoke user callback to get fresh output data.
|
||||||
|
int32_t doStopStream = 0;
|
||||||
|
audio::Time streamTime = getStreamTime();
|
||||||
|
std::vector<enum audio::orchestra::status> status;
|
||||||
|
if ( m_mode != audio::orchestra::mode_input
|
||||||
|
&& m_private->xrun[0] == true) {
|
||||||
|
status.push_back(audio::orchestra::status_underflow);
|
||||||
|
m_private->xrun[0] = false;
|
||||||
|
}
|
||||||
|
if ( m_mode != audio::orchestra::mode_output
|
||||||
|
&& m_private->xrun[1] == true) {
|
||||||
|
status.push_back(audio::orchestra::status_overflow);
|
||||||
|
m_private->xrun[1] = false;
|
||||||
|
}
|
||||||
|
doStopStream = m_callback(m_userBuffer[1],
|
||||||
|
streamTime,
|
||||||
|
m_userBuffer[0],
|
||||||
|
streamTime,
|
||||||
|
m_bufferSize,
|
||||||
|
status);
|
||||||
|
if (doStopStream == 2) {
|
||||||
|
this->abortStream();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mutex.lock();
|
||||||
|
// The state might change while waiting on a mutex.
|
||||||
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
int32_t result;
|
||||||
|
char *buffer;
|
||||||
|
int32_t samples;
|
||||||
|
audio::format format;
|
||||||
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
|
// Setup parameters and do buffer conversion if necessary.
|
||||||
|
if (m_doConvertBuffer[0]) {
|
||||||
|
buffer = m_deviceBuffer;
|
||||||
|
convertBuffer(buffer, m_userBuffer[0], m_convertInfo[0]);
|
||||||
|
samples = m_bufferSize * m_nDeviceChannels[0];
|
||||||
|
format = m_deviceFormat[0];
|
||||||
|
} else {
|
||||||
|
buffer = m_userBuffer[0];
|
||||||
|
samples = m_bufferSize * m_nUserChannels[0];
|
||||||
|
format = m_userFormat;
|
||||||
|
}
|
||||||
|
// Do byte swapping if necessary.
|
||||||
|
if (m_doByteSwap[0]) {
|
||||||
|
byteSwapBuffer(buffer, samples, format);
|
||||||
|
}
|
||||||
|
if ( m_mode == audio::orchestra::mode_duplex
|
||||||
|
&& m_private->triggered == false) {
|
||||||
|
int32_t trig = 0;
|
||||||
|
ioctl(m_private->id[0], SNDCTL_DSP_SETTRIGGER, &trig);
|
||||||
|
result = write(m_private->id[0], buffer, samples * audio::getFormatBytes(format));
|
||||||
|
trig = PCM_ENABLE_audio::orchestra::mode_input|PCM_ENABLE_audio::orchestra::mode_output;
|
||||||
|
ioctl(m_private->id[0], SNDCTL_DSP_SETTRIGGER, &trig);
|
||||||
|
m_private->triggered = true;
|
||||||
|
} else {
|
||||||
|
// Write samples to device.
|
||||||
|
result = write(m_private->id[0], buffer, samples * audio::getFormatBytes(format));
|
||||||
|
}
|
||||||
|
if (result == -1) {
|
||||||
|
// We'll assume this is an underrun, though there isn't a
|
||||||
|
// specific means for determining that.
|
||||||
|
m_private->xrun[0] = true;
|
||||||
|
ATA_ERROR("audio write error.");
|
||||||
|
//error(audio::orchestra::error_warning);
|
||||||
|
// Continue on to input section.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( m_mode == audio::orchestra::mode_input
|
||||||
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
|
// Setup parameters.
|
||||||
|
if (m_doConvertBuffer[1]) {
|
||||||
|
buffer = m_deviceBuffer;
|
||||||
|
samples = m_bufferSize * m_nDeviceChannels[1];
|
||||||
|
format = m_deviceFormat[1];
|
||||||
|
} else {
|
||||||
|
buffer = m_userBuffer[1];
|
||||||
|
samples = m_bufferSize * m_nUserChannels[1];
|
||||||
|
format = m_userFormat;
|
||||||
|
}
|
||||||
|
// Read samples from device.
|
||||||
|
result = read(m_private->id[1], buffer, samples * audio::getFormatBytes(format));
|
||||||
|
if (result == -1) {
|
||||||
|
// We'll assume this is an overrun, though there isn't a
|
||||||
|
// specific means for determining that.
|
||||||
|
m_private->xrun[1] = true;
|
||||||
|
ATA_ERROR("audio read error.");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
// Do byte swapping if necessary.
|
||||||
|
if (m_doByteSwap[1]) {
|
||||||
|
byteSwapBuffer(buffer, samples, format);
|
||||||
|
}
|
||||||
|
// Do buffer conversion if necessary.
|
||||||
|
if (m_doConvertBuffer[1]) {
|
||||||
|
convertBuffer(m_userBuffer[1], m_deviceBuffer, m_convertInfo[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
m_mutex.unlock();
|
||||||
|
audio::orchestra::Api::tickStreamTime();
|
||||||
|
if (doStopStream == 1) {
|
||||||
|
this->stopStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ossCallbackHandler(void* _userData) {
|
||||||
|
etk::thread::setName("OSS callback-" + m_name);
|
||||||
|
audio::orchestra::api::Alsa* myClass = reinterpret_cast<audio::orchestra::api::Oss*>(_userData);
|
||||||
|
while (myClass->m_private->threadRunning == true) {
|
||||||
|
myClass->callbackEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
51
audio/orchestra/api/Oss.h
Normal file
51
audio/orchestra/api/Oss.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
* @fork from RTAudio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__AUDIO_ORCHESTRA_API_OSS_H__) && defined(ORCHESTRA_BUILD_OSS)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_OSS_H__
|
||||||
|
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
namespace orchestra {
|
||||||
|
namespace api {
|
||||||
|
class OssPrivate;
|
||||||
|
class Oss: public audio::orchestra::Api {
|
||||||
|
public:
|
||||||
|
static audio::orchestra::Api* create();
|
||||||
|
public:
|
||||||
|
Oss();
|
||||||
|
virtual ~Oss();
|
||||||
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
|
return audio::orchestra::type_oss;
|
||||||
|
}
|
||||||
|
uint32_t getDeviceCount();
|
||||||
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
|
enum audio::orchestra::error closeStream();
|
||||||
|
enum audio::orchestra::error startStream();
|
||||||
|
enum audio::orchestra::error stopStream();
|
||||||
|
enum audio::orchestra::error abortStream();
|
||||||
|
// This function is intended for internal use only. It must be
|
||||||
|
// public because it is called by the internal callback handler,
|
||||||
|
// which is not a member of RtAudio. External use of this function
|
||||||
|
// will most likely produce highly undesireable results!
|
||||||
|
void callbackEvent();
|
||||||
|
private:
|
||||||
|
std11::shared_ptr<OssPrivate> m_private;
|
||||||
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
|
audio::orchestra::mode _mode,
|
||||||
|
uint32_t _channels,
|
||||||
|
uint32_t _firstChannel,
|
||||||
|
uint32_t _sampleRate,
|
||||||
|
audio::format _format,
|
||||||
|
uint32_t *_bufferSize,
|
||||||
|
const audio::orchestra::StreamOptions& _options);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -15,12 +15,13 @@
|
|||||||
#include <pulse/error.h>
|
#include <pulse/error.h>
|
||||||
#include <pulse/simple.h>
|
#include <pulse/simple.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ethread/tools.h>
|
#include <etk/thread/tools.h>
|
||||||
#include <audio/orchestra/api/PulseDeviceList.h>
|
|
||||||
#include <audio/orchestra/api/Pulse.h>
|
|
||||||
|
|
||||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Pulse::create() {
|
#undef __class__
|
||||||
return ememory::SharedPtr<audio::orchestra::api::Pulse>(new audio::orchestra::api::Pulse());
|
#define __class__ "api::Pulse"
|
||||||
|
|
||||||
|
audio::orchestra::Api* audio::orchestra::api::Pulse::create() {
|
||||||
|
return new audio::orchestra::api::Pulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -52,13 +53,15 @@ namespace audio {
|
|||||||
namespace api {
|
namespace api {
|
||||||
class PulsePrivate {
|
class PulsePrivate {
|
||||||
public:
|
public:
|
||||||
pa_simple* handle;
|
pa_simple *s_play;
|
||||||
ememory::SharedPtr<std::thread> thread;
|
pa_simple *s_rec;
|
||||||
|
std11::shared_ptr<std11::thread> thread;
|
||||||
bool threadRunning;
|
bool threadRunning;
|
||||||
std::condition_variable runnable_cv;
|
std11::condition_variable runnable_cv;
|
||||||
bool runnable;
|
bool runnable;
|
||||||
PulsePrivate() :
|
PulsePrivate() :
|
||||||
handle(0),
|
s_play(0),
|
||||||
|
s_rec(0),
|
||||||
threadRunning(false),
|
threadRunning(false),
|
||||||
runnable(false) {
|
runnable(false) {
|
||||||
|
|
||||||
@@ -73,27 +76,31 @@ audio::orchestra::api::Pulse::Pulse() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::api::Pulse::~Pulse() {
|
audio::orchestra::api::Pulse::~Pulse() {
|
||||||
if (m_state != audio::orchestra::state::closed) {
|
if (m_state != audio::orchestra::state_closed) {
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t audio::orchestra::api::Pulse::getDeviceCount() {
|
uint32_t audio::orchestra::api::Pulse::getDeviceCount() {
|
||||||
#if 1
|
return 1;
|
||||||
std::vector<audio::orchestra::DeviceInfo> list = audio::orchestra::api::pulse::getDeviceList();
|
|
||||||
return list.size();
|
|
||||||
#else
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::orchestra::DeviceInfo audio::orchestra::api::Pulse::getDeviceInfo(uint32_t _device) {
|
audio::orchestra::DeviceInfo audio::orchestra::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||||
std::vector<audio::orchestra::DeviceInfo> list = audio::orchestra::api::pulse::getDeviceList();
|
audio::orchestra::DeviceInfo info;
|
||||||
if (_device >= list.size()) {
|
info.probed = true;
|
||||||
ATA_ERROR("Request device out of IDs:" << _device << " >= " << list.size());
|
info.name = "PulseAudio";
|
||||||
return audio::orchestra::DeviceInfo();
|
info.outputChannels = 2;
|
||||||
|
info.inputChannels = 2;
|
||||||
|
info.duplexChannels = 2;
|
||||||
|
info.isDefaultOutput = true;
|
||||||
|
info.isDefaultInput = true;
|
||||||
|
for (const uint32_t *sr = SUPPORTED_SAMPLERATES; *sr; ++sr) {
|
||||||
|
info.sampleRates.push_back(*sr);
|
||||||
}
|
}
|
||||||
return list[_device];
|
info.nativeFormats.push_back(audio::format_int16);
|
||||||
|
info.nativeFormats.push_back(audio::format_int32);
|
||||||
|
info.nativeFormats.push_back(audio::format_float);
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pulseaudio_callback(void* _userData) {
|
static void pulseaudio_callback(void* _userData) {
|
||||||
@@ -102,7 +109,7 @@ static void pulseaudio_callback(void* _userData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void audio::orchestra::api::Pulse::callbackEvent() {
|
void audio::orchestra::api::Pulse::callbackEvent() {
|
||||||
ethread::setName("Pulse IO-" + m_name);
|
etk::thread::setName("Pulse IO-" + m_name);
|
||||||
while (m_private->threadRunning == true) {
|
while (m_private->threadRunning == true) {
|
||||||
callbackEventOneCycle();
|
callbackEventOneCycle();
|
||||||
}
|
}
|
||||||
@@ -111,36 +118,38 @@ void audio::orchestra::api::Pulse::callbackEvent() {
|
|||||||
enum audio::orchestra::error audio::orchestra::api::Pulse::closeStream() {
|
enum audio::orchestra::error audio::orchestra::api::Pulse::closeStream() {
|
||||||
m_private->threadRunning = false;
|
m_private->threadRunning = false;
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
m_private->runnable = true;
|
m_private->runnable = true;
|
||||||
m_private->runnable_cv.notify_one();;
|
m_private->runnable_cv.notify_one();;
|
||||||
}
|
}
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
m_private->thread->join();
|
m_private->thread->join();
|
||||||
if (m_mode == audio::orchestra::mode_output) {
|
if (m_private->s_play) {
|
||||||
pa_simple_flush(m_private->handle, nullptr);
|
pa_simple_flush(m_private->s_play, nullptr);
|
||||||
|
pa_simple_free(m_private->s_play);
|
||||||
|
}
|
||||||
|
if (m_private->s_rec) {
|
||||||
|
pa_simple_free(m_private->s_rec);
|
||||||
}
|
}
|
||||||
pa_simple_free(m_private->handle);
|
|
||||||
m_private->handle = nullptr;
|
|
||||||
m_userBuffer[0].clear();
|
m_userBuffer[0].clear();
|
||||||
m_userBuffer[1].clear();
|
m_userBuffer[1].clear();
|
||||||
m_state = audio::orchestra::state::closed;
|
m_state = audio::orchestra::state_closed;
|
||||||
m_mode = audio::orchestra::mode_unknow;
|
m_mode = audio::orchestra::mode_unknow;
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
std::unique_lock<std::mutex> lck(m_mutex);
|
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||||
while (!m_private->runnable) {
|
while (!m_private->runnable) {
|
||||||
m_private->runnable_cv.wait(lck);
|
m_private->runnable_cv.wait(lck);
|
||||||
}
|
}
|
||||||
if (m_state != audio::orchestra::state::running) {
|
if (m_state != audio::orchestra::state_running) {
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -159,12 +168,13 @@ void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
|||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
void *pulse_in = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0];
|
void *pulse_in = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0];
|
||||||
void *pulse_out = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0];
|
void *pulse_out = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0];
|
||||||
if (m_state != audio::orchestra::state::running) {
|
if (m_state != audio::orchestra::state_running) {
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
int32_t pa_error;
|
int32_t pa_error;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
if (m_mode == audio::orchestra::mode_output) {
|
if ( m_mode == audio::orchestra::mode_output
|
||||||
|
|| m_mode == audio::orchestra::mode_duplex) {
|
||||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]) {
|
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]) {
|
||||||
convertBuffer(m_deviceBuffer,
|
convertBuffer(m_deviceBuffer,
|
||||||
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
||||||
@@ -173,18 +183,18 @@ void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
|||||||
} else {
|
} else {
|
||||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||||
}
|
}
|
||||||
if (pa_simple_write(m_private->handle, pulse_out, bytes, &pa_error) < 0) {
|
if (pa_simple_write(m_private->s_play, pulse_out, bytes, &pa_error) < 0) {
|
||||||
ATA_ERROR("audio write error, " << pa_strerror(pa_error) << ".");
|
ATA_ERROR("audio write error, " << pa_strerror(pa_error) << ".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_mode == audio::orchestra::mode_input) {
|
if (m_mode == audio::orchestra::mode_input || m_mode == audio::orchestra::mode_duplex) {
|
||||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
||||||
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
||||||
} else {
|
} else {
|
||||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||||
}
|
}
|
||||||
if (pa_simple_read(m_private->handle, pulse_in, bytes, &pa_error) < 0) {
|
if (pa_simple_read(m_private->s_rec, pulse_in, bytes, &pa_error) < 0) {
|
||||||
ATA_ERROR("audio read error, " << pa_strerror(pa_error) << ".");
|
ATA_ERROR("audio read error, " << pa_strerror(pa_error) << ".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -207,16 +217,16 @@ unlock:
|
|||||||
enum audio::orchestra::error audio::orchestra::api::Pulse::startStream() {
|
enum audio::orchestra::error audio::orchestra::api::Pulse::startStream() {
|
||||||
// TODO : Check return ...
|
// TODO : Check return ...
|
||||||
audio::orchestra::Api::startStream();
|
audio::orchestra::Api::startStream();
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is not open!");
|
ATA_ERROR("the stream is not open!");
|
||||||
return audio::orchestra::error_invalidUse;
|
return audio::orchestra::error_invalidUse;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::running) {
|
if (m_state == audio::orchestra::state_running) {
|
||||||
ATA_ERROR("the stream is already running!");
|
ATA_ERROR("the stream is already running!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
m_state = audio::orchestra::state::running;
|
m_state = audio::orchestra::state_running;
|
||||||
m_private->runnable = true;
|
m_private->runnable = true;
|
||||||
m_private->runnable_cv.notify_one();
|
m_private->runnable_cv.notify_one();
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
@@ -224,65 +234,61 @@ enum audio::orchestra::error audio::orchestra::api::Pulse::startStream() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Pulse::stopStream() {
|
enum audio::orchestra::error audio::orchestra::api::Pulse::stopStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is not open!");
|
ATA_ERROR("the stream is not open!");
|
||||||
return audio::orchestra::error_invalidUse;
|
return audio::orchestra::error_invalidUse;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
if ( m_private != nullptr
|
if (m_private->s_play) {
|
||||||
&& m_private->handle != nullptr
|
|
||||||
&& m_mode == audio::orchestra::mode_output) {
|
|
||||||
int32_t pa_error;
|
int32_t pa_error;
|
||||||
if (pa_simple_drain(m_private->handle, &pa_error) < 0) {
|
if (pa_simple_drain(m_private->s_play, &pa_error) < 0) {
|
||||||
ATA_ERROR("error draining output device, " << pa_strerror(pa_error) << ".");
|
ATA_ERROR("error draining output device, " << pa_strerror(pa_error) << ".");
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return audio::orchestra::error_systemError;
|
return audio::orchestra::error_systemError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum audio::orchestra::error audio::orchestra::api::Pulse::abortStream() {
|
enum audio::orchestra::error audio::orchestra::api::Pulse::abortStream() {
|
||||||
if (m_state == audio::orchestra::state::closed) {
|
if (m_state == audio::orchestra::state_closed) {
|
||||||
ATA_ERROR("the stream is not open!");
|
ATA_ERROR("the stream is not open!");
|
||||||
return audio::orchestra::error_invalidUse;
|
return audio::orchestra::error_invalidUse;
|
||||||
}
|
}
|
||||||
if (m_state == audio::orchestra::state::stopped) {
|
if (m_state == audio::orchestra::state_stopped) {
|
||||||
ATA_ERROR("the stream is already stopped!");
|
ATA_ERROR("the stream is already stopped!");
|
||||||
return audio::orchestra::error_warning;
|
return audio::orchestra::error_warning;
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
if ( m_private != nullptr
|
if (m_private && m_private->s_play) {
|
||||||
&& m_private->handle != nullptr
|
|
||||||
&& m_mode == audio::orchestra::mode_output) {
|
|
||||||
int32_t pa_error;
|
int32_t pa_error;
|
||||||
if (pa_simple_flush(m_private->handle, &pa_error) < 0) {
|
if (pa_simple_flush(m_private->s_play, &pa_error) < 0) {
|
||||||
ATA_ERROR("error flushing output device, " << pa_strerror(pa_error) << ".");
|
ATA_ERROR("error flushing output device, " << pa_strerror(pa_error) << ".");
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return audio::orchestra::error_systemError;
|
return audio::orchestra::error_systemError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return audio::orchestra::error_none;
|
return audio::orchestra::error_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio::orchestra::api::Pulse::open(uint32_t _device,
|
bool audio::orchestra::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options) {
|
const audio::orchestra::StreamOptions& _options) {
|
||||||
uint64_t bufferBytes = 0;
|
uint64_t bufferBytes = 0;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
if (_device != 0) {
|
if (_device != 0) {
|
||||||
@@ -370,15 +376,15 @@ bool audio::orchestra::api::Pulse::open(uint32_t _device,
|
|||||||
int32_t error;
|
int32_t error;
|
||||||
switch (_mode) {
|
switch (_mode) {
|
||||||
case audio::orchestra::mode_input:
|
case audio::orchestra::mode_input:
|
||||||
m_private->handle = pa_simple_new(nullptr, "orchestra", PA_STREAM_RECORD, nullptr, "Record", &ss, nullptr, nullptr, &error);
|
m_private->s_rec = pa_simple_new(nullptr, "orchestra", PA_STREAM_RECORD, nullptr, "Record", &ss, nullptr, nullptr, &error);
|
||||||
if (m_private->handle == nullptr) {
|
if (!m_private->s_rec) {
|
||||||
ATA_ERROR("error connecting input to PulseAudio server.");
|
ATA_ERROR("error connecting input to PulseAudio server.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case audio::orchestra::mode_output:
|
case audio::orchestra::mode_output:
|
||||||
m_private->handle = pa_simple_new(nullptr, "orchestra", PA_STREAM_PLAYBACK, nullptr, "Playback", &ss, nullptr, nullptr, &error);
|
m_private->s_play = pa_simple_new(nullptr, "orchestra", PA_STREAM_PLAYBACK, nullptr, "Playback", &ss, nullptr, nullptr, &error);
|
||||||
if (m_private->handle == nullptr) {
|
if (!m_private->s_play) {
|
||||||
ATA_ERROR("error connecting output to PulseAudio server.");
|
ATA_ERROR("error connecting output to PulseAudio server.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -388,22 +394,24 @@ bool audio::orchestra::api::Pulse::open(uint32_t _device,
|
|||||||
}
|
}
|
||||||
if (m_mode == audio::orchestra::mode_unknow) {
|
if (m_mode == audio::orchestra::mode_unknow) {
|
||||||
m_mode = _mode;
|
m_mode = _mode;
|
||||||
} else {
|
} else if (m_mode == _mode) {
|
||||||
goto error;
|
goto error;
|
||||||
|
}else {
|
||||||
|
m_mode = audio::orchestra::mode_duplex;
|
||||||
}
|
}
|
||||||
if (m_private->threadRunning == false) {
|
if (!m_private->threadRunning) {
|
||||||
m_private->threadRunning = true;
|
m_private->threadRunning = true;
|
||||||
m_private->thread = ememory::makeShared<std::thread>(&pulseaudio_callback, this);
|
m_private->thread = std11::make_shared<std11::thread>(&pulseaudio_callback, this);
|
||||||
if (m_private->thread == nullptr) {
|
if (m_private->thread == nullptr) {
|
||||||
ATA_ERROR("error creating thread.");
|
ATA_ERROR("error creating thread.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_state = audio::orchestra::state::stopped;
|
m_state = audio::orchestra::state_stopped;
|
||||||
return true;
|
return true;
|
||||||
error:
|
error:
|
||||||
for (int32_t iii=0; iii<2; ++iii) {
|
for (int32_t i=0; i<2; i++) {
|
||||||
m_userBuffer[iii].clear();
|
m_userBuffer[i].clear();
|
||||||
}
|
}
|
||||||
if (m_deviceBuffer) {
|
if (m_deviceBuffer) {
|
||||||
free(m_deviceBuffer);
|
free(m_deviceBuffer);
|
||||||
|
@@ -4,8 +4,10 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_PULSE
|
#if !defined(__AUDIO_ORCHESTRA_API_PULSE_H__) && defined(ORCHESTRA_BUILD_PULSE)
|
||||||
|
#define __AUDIO_ORCHESTRA_API_PULSE_H__
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
@@ -13,12 +15,12 @@ namespace audio {
|
|||||||
class PulsePrivate;
|
class PulsePrivate;
|
||||||
class Pulse: public audio::orchestra::Api {
|
class Pulse: public audio::orchestra::Api {
|
||||||
public:
|
public:
|
||||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
static audio::orchestra::Api* create();
|
||||||
public:
|
public:
|
||||||
Pulse();
|
Pulse();
|
||||||
virtual ~Pulse();
|
virtual ~Pulse();
|
||||||
const std::string& getCurrentApi() {
|
enum audio::orchestra::type getCurrentApi() {
|
||||||
return audio::orchestra::typePulse;
|
return audio::orchestra::type_pulse;
|
||||||
}
|
}
|
||||||
uint32_t getDeviceCount();
|
uint32_t getDeviceCount();
|
||||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
@@ -33,17 +35,17 @@ namespace audio {
|
|||||||
void callbackEventOneCycle();
|
void callbackEventOneCycle();
|
||||||
void callbackEvent();
|
void callbackEvent();
|
||||||
private:
|
private:
|
||||||
ememory::SharedPtr<PulsePrivate> m_private;
|
std11::shared_ptr<PulsePrivate> m_private;
|
||||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||||
void saveDeviceInfo();
|
void saveDeviceInfo();
|
||||||
bool open(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
audio::orchestra::mode _mode,
|
audio::orchestra::mode _mode,
|
||||||
uint32_t _channels,
|
uint32_t _channels,
|
||||||
uint32_t _firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t _sampleRate,
|
uint32_t _sampleRate,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
const audio::orchestra::StreamOptions& _options);
|
const audio::orchestra::StreamOptions& _options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,362 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
* @fork from RTAudio
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <pulse/pulseaudio.h>
|
|
||||||
#include <audio/orchestra/api/PulseDeviceList.h>
|
|
||||||
#include <audio/orchestra/debug.h>
|
|
||||||
#include <audio/Time.h>
|
|
||||||
#include <audio/Duration.h>
|
|
||||||
#include <audio/format.h>
|
|
||||||
#include <etk/stdTools.h>
|
|
||||||
|
|
||||||
// This callback gets called when our context changes state. We really only
|
|
||||||
// care about when it's ready or if it has failed
|
|
||||||
static void callbackStateMachine(pa_context* _contex, void *_userdata) {
|
|
||||||
pa_context_state_t state;
|
|
||||||
int *pulseAudioReady = static_cast<int*>(_userdata);
|
|
||||||
state = pa_context_get_state(_contex);
|
|
||||||
switch (state) {
|
|
||||||
// There are just here for reference
|
|
||||||
case PA_CONTEXT_UNCONNECTED:
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_UNCONNECTED");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_CONNECTING:
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_CONNECTING");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_AUTHORIZING:
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_AUTHORIZING");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_SETTING_NAME:
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_SETTING_NAME");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ATA_VERBOSE("pulse state: default");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_FAILED:
|
|
||||||
*pulseAudioReady = 2;
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_FAILED");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_TERMINATED:
|
|
||||||
*pulseAudioReady = 2;
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_TERMINATED");
|
|
||||||
break;
|
|
||||||
case PA_CONTEXT_READY:
|
|
||||||
*pulseAudioReady = 1;
|
|
||||||
ATA_VERBOSE("pulse state: PA_CONTEXT_READY");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static audio::format getFormatFromPulseFormat(enum pa_sample_format _format) {
|
|
||||||
switch (_format) {
|
|
||||||
case PA_SAMPLE_U8:
|
|
||||||
return audio::format_int8;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_ALAW:
|
|
||||||
ATA_ERROR("Not supported: uint8_t a-law");
|
|
||||||
return audio::format_unknow;
|
|
||||||
case PA_SAMPLE_ULAW:
|
|
||||||
ATA_ERROR("Not supported: uint8_t mu-law");
|
|
||||||
return audio::format_unknow;
|
|
||||||
case PA_SAMPLE_S16LE:
|
|
||||||
return audio::format_int16;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S16BE:
|
|
||||||
return audio::format_int16;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_FLOAT32LE:
|
|
||||||
return audio::format_float;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_FLOAT32BE:
|
|
||||||
return audio::format_float;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S32LE:
|
|
||||||
return audio::format_int32;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S32BE:
|
|
||||||
return audio::format_int32;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S24LE:
|
|
||||||
return audio::format_int24;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S24BE:
|
|
||||||
return audio::format_int24;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S24_32LE:
|
|
||||||
return audio::format_int24_on_int32;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_S24_32BE:
|
|
||||||
return audio::format_int24_on_int32;
|
|
||||||
break;
|
|
||||||
case PA_SAMPLE_INVALID:
|
|
||||||
case PA_SAMPLE_MAX:
|
|
||||||
ATA_ERROR("Not supported: invalid");
|
|
||||||
return audio::format_unknow;
|
|
||||||
}
|
|
||||||
ATA_ERROR("Not supported: UNKNOW flag...");
|
|
||||||
return audio::format_unknow;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<audio::channel> getChannelOrderFromPulseChannel(const struct pa_channel_map& _map) {
|
|
||||||
std::vector<audio::channel> out;
|
|
||||||
|
|
||||||
for (int32_t iii=0; iii<_map.channels; ++iii) {
|
|
||||||
switch(_map.map[iii]) {
|
|
||||||
default:
|
|
||||||
case PA_CHANNEL_POSITION_MAX:
|
|
||||||
case PA_CHANNEL_POSITION_INVALID:
|
|
||||||
out.push_back(audio::channel_unknow);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_MONO:
|
|
||||||
case PA_CHANNEL_POSITION_FRONT_CENTER:
|
|
||||||
out.push_back(audio::channel_frontCenter);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_FRONT_LEFT:
|
|
||||||
out.push_back(audio::channel_frontLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_FRONT_RIGHT:
|
|
||||||
out.push_back(audio::channel_frontRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_REAR_CENTER:
|
|
||||||
out.push_back(audio::channel_rearCenter);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_REAR_LEFT:
|
|
||||||
out.push_back(audio::channel_rearLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_REAR_RIGHT:
|
|
||||||
out.push_back(audio::channel_rearRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_LFE:
|
|
||||||
out.push_back(audio::channel_lfe);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
|
|
||||||
out.push_back(audio::channel_centerLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
|
|
||||||
out.push_back(audio::channel_centerRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_SIDE_LEFT:
|
|
||||||
out.push_back(audio::channel_topCenterLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_SIDE_RIGHT:
|
|
||||||
out.push_back(audio::channel_topCenterRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_CENTER:
|
|
||||||
case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
|
|
||||||
out.push_back(audio::channel_topFrontCenter);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
|
|
||||||
out.push_back(audio::channel_topFrontLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
|
|
||||||
out.push_back(audio::channel_topFrontRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
|
|
||||||
out.push_back(audio::channel_topRearLeft);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
|
|
||||||
out.push_back(audio::channel_topRearRight);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
|
|
||||||
out.push_back(audio::channel_topRearCenter);
|
|
||||||
break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX0: out.push_back(audio::channel_aux0); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX1: out.push_back(audio::channel_aux1); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX2: out.push_back(audio::channel_aux2); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX3: out.push_back(audio::channel_aux3); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX4: out.push_back(audio::channel_aux4); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX5: out.push_back(audio::channel_aux5); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX6: out.push_back(audio::channel_aux6); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX7: out.push_back(audio::channel_aux7); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX8: out.push_back(audio::channel_aux8); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX9: out.push_back(audio::channel_aux9); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX10: out.push_back(audio::channel_aux10); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX11: out.push_back(audio::channel_aux11); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX12: out.push_back(audio::channel_aux12); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX13: out.push_back(audio::channel_aux13); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX14: out.push_back(audio::channel_aux14); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX15: out.push_back(audio::channel_aux15); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX16: out.push_back(audio::channel_aux16); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX17: out.push_back(audio::channel_aux17); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX18: out.push_back(audio::channel_aux18); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX19: out.push_back(audio::channel_aux19); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX20: out.push_back(audio::channel_aux20); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX21: out.push_back(audio::channel_aux21); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX22: out.push_back(audio::channel_aux22); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX23: out.push_back(audio::channel_aux23); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX24: out.push_back(audio::channel_aux24); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX25: out.push_back(audio::channel_aux25); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX26: out.push_back(audio::channel_aux26); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX27: out.push_back(audio::channel_aux27); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX28: out.push_back(audio::channel_aux28); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX29: out.push_back(audio::channel_aux29); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX30: out.push_back(audio::channel_aux30); break;
|
|
||||||
case PA_CHANNEL_POSITION_AUX31: out.push_back(audio::channel_aux31); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// Callback on getting data from pulseaudio:
|
|
||||||
static void callbackGetSinkList(pa_context* _contex, const pa_sink_info* _info, int _eol, void* _userdata) {
|
|
||||||
std::vector<audio::orchestra::DeviceInfo>* list = static_cast<std::vector<audio::orchestra::DeviceInfo>*>(_userdata);
|
|
||||||
// If eol is set to a positive number, you're at the end of the list
|
|
||||||
if (_eol > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
audio::orchestra::DeviceInfo info;
|
|
||||||
info.isCorrect = true;
|
|
||||||
info.input = false;
|
|
||||||
info.name = _info->name;
|
|
||||||
info.desc = _info->description;
|
|
||||||
info.sampleRates.push_back(_info->sample_spec.rate);
|
|
||||||
info.nativeFormats.push_back(getFormatFromPulseFormat(_info->sample_spec.format));
|
|
||||||
info.channels = getChannelOrderFromPulseChannel(_info->channel_map);
|
|
||||||
ATA_VERBOSE("plop=" << _info->index << " " << _info->name);
|
|
||||||
//ATA_DEBUG(" ports=" << _info->n_ports);
|
|
||||||
list->push_back(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// allback to get data from pulseaudio:
|
|
||||||
static void callbackGetSourceList(pa_context* _contex, const pa_source_info* _info, int _eol, void* _userdata) {
|
|
||||||
std::vector<audio::orchestra::DeviceInfo>* list = static_cast<std::vector<audio::orchestra::DeviceInfo>*>(_userdata);
|
|
||||||
if (_eol > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
audio::orchestra::DeviceInfo info;
|
|
||||||
info.isCorrect = true;
|
|
||||||
info.input = true;
|
|
||||||
info.name = _info->name;
|
|
||||||
info.desc = _info->description;
|
|
||||||
info.sampleRates.push_back(_info->sample_spec.rate);
|
|
||||||
info.nativeFormats.push_back(getFormatFromPulseFormat(_info->sample_spec.format));
|
|
||||||
info.channels = getChannelOrderFromPulseChannel(_info->channel_map);
|
|
||||||
ATA_VERBOSE("plop=" << _info->index << " " << _info->name);
|
|
||||||
list->push_back(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// to not update all the time ...
|
|
||||||
static std::vector<audio::orchestra::DeviceInfo> pulseAudioListOfDevice;
|
|
||||||
static audio::Time pulseAudioListOfDeviceTime;
|
|
||||||
|
|
||||||
std::vector<audio::orchestra::DeviceInfo> audio::orchestra::api::pulse::getDeviceList() {
|
|
||||||
audio::Duration delta = audio::Time::now() - pulseAudioListOfDeviceTime;
|
|
||||||
if (delta < audio::Duration(30,0)) {
|
|
||||||
return pulseAudioListOfDevice;
|
|
||||||
}
|
|
||||||
// Define our pulse audio loop and connection variables
|
|
||||||
pa_mainloop* pulseAudioMainLoop;
|
|
||||||
pa_mainloop_api* pulseAudioMainLoopAPI;
|
|
||||||
pa_operation* pulseAudioOperation;
|
|
||||||
pa_context* pulseAudioContex;
|
|
||||||
pa_context_flags_t pulseAudioFlags = PA_CONTEXT_NOAUTOSPAWN;
|
|
||||||
std::vector<audio::orchestra::DeviceInfo>& out = pulseAudioListOfDevice;
|
|
||||||
out.clear();
|
|
||||||
// We'll need these state variables to keep track of our requests
|
|
||||||
int state = 0;
|
|
||||||
int pulseAudioReady = 0;
|
|
||||||
// Create a mainloop API and connection to the default server
|
|
||||||
pulseAudioMainLoop = pa_mainloop_new();
|
|
||||||
pulseAudioMainLoopAPI = pa_mainloop_get_api(pulseAudioMainLoop);
|
|
||||||
pulseAudioContex = pa_context_new(pulseAudioMainLoopAPI, "orchestraPulseCount");
|
|
||||||
// If there's an error, the callback will set pulseAudioReady
|
|
||||||
pa_context_set_state_callback(pulseAudioContex, callbackStateMachine, &pulseAudioReady);
|
|
||||||
// This function connects to the pulse server
|
|
||||||
pa_context_connect(pulseAudioContex, NULL, pulseAudioFlags, NULL);
|
|
||||||
bool playLoop = true;
|
|
||||||
while (playLoop == true) {
|
|
||||||
// We can't do anything until PA is ready, so just iterate the mainloop
|
|
||||||
// and continue
|
|
||||||
if (pulseAudioReady == 0) {
|
|
||||||
pa_mainloop_iterate(pulseAudioMainLoop, 1, nullptr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// We couldn't get a connection to the server, so exit out
|
|
||||||
if (pulseAudioReady == 2) {
|
|
||||||
pa_context_disconnect(pulseAudioContex);
|
|
||||||
pa_context_unref(pulseAudioContex);
|
|
||||||
pa_mainloop_free(pulseAudioMainLoop);
|
|
||||||
ATA_ERROR("Pulse interface error: Can not connect to the pulseaudio iterface...");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// At this point, we're connected to the server and ready to make
|
|
||||||
// requests
|
|
||||||
switch (state) {
|
|
||||||
// State 0: we haven't done anything yet
|
|
||||||
case 0:
|
|
||||||
ATA_DEBUG("Request sink list");
|
|
||||||
pulseAudioOperation = pa_context_get_sink_info_list(pulseAudioContex,
|
|
||||||
callbackGetSinkList,
|
|
||||||
&out);
|
|
||||||
state++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// Now we wait for our operation to complete. When it's
|
|
||||||
// complete our pa_output_devicelist is filled out, and we move
|
|
||||||
// along to the next state
|
|
||||||
if (pa_operation_get_state(pulseAudioOperation) == PA_OPERATION_DONE) {
|
|
||||||
pa_operation_unref(pulseAudioOperation);
|
|
||||||
ATA_DEBUG("Request sources list");
|
|
||||||
pulseAudioOperation = pa_context_get_source_info_list(pulseAudioContex,
|
|
||||||
callbackGetSourceList,
|
|
||||||
&out);
|
|
||||||
state++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (pa_operation_get_state(pulseAudioOperation) == PA_OPERATION_DONE) {
|
|
||||||
ATA_DEBUG("All is done");
|
|
||||||
// Now we're done, clean up and disconnect and return
|
|
||||||
pa_operation_unref(pulseAudioOperation);
|
|
||||||
pa_context_disconnect(pulseAudioContex);
|
|
||||||
pa_context_unref(pulseAudioContex);
|
|
||||||
pa_mainloop_free(pulseAudioMainLoop);
|
|
||||||
playLoop = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// We should never see this state
|
|
||||||
ATA_ERROR("Error in getting the devices list ...");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// Iterate the main loop ..
|
|
||||||
if (playLoop == true) {
|
|
||||||
pa_mainloop_iterate(pulseAudioMainLoop, 1, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: need to do it better ...
|
|
||||||
// set default device:
|
|
||||||
int32_t idInput = -1;
|
|
||||||
int32_t idOutput = -1;
|
|
||||||
for (int32_t iii=0; iii<out.size(); ++iii) {
|
|
||||||
if (out[iii].input == true) {
|
|
||||||
if (idInput != -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (etk::end_with(out[iii].name, ".monitor", false) == false) {
|
|
||||||
idInput = iii;
|
|
||||||
out[iii].isDefault = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (idOutput != -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (etk::end_with(out[iii].name, ".monitor", false) == false) {
|
|
||||||
idOutput = iii;
|
|
||||||
out[iii].isDefault = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,23 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
* @fork from RTAudio
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#ifdef ORCHESTRA_BUILD_PULSE
|
|
||||||
|
|
||||||
#include <etk/types.h>
|
|
||||||
#include <audio/orchestra/DeviceInfo.h>
|
|
||||||
|
|
||||||
namespace audio {
|
|
||||||
namespace orchestra {
|
|
||||||
namespace api {
|
|
||||||
namespace pulse {
|
|
||||||
std::vector<audio::orchestra::DeviceInfo> getDeviceList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -4,14 +4,15 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <thread>
|
#ifndef __AUDIO_ORCHESTRA_CB_H__
|
||||||
#include <condition_variable>
|
#define __AUDIO_ORCHESTRA_CB_H__
|
||||||
#include <mutex>
|
#include <etk/thread.h>
|
||||||
#include <chrono>
|
#include <etk/condition_variable.h>
|
||||||
#include <functional>
|
#include <etk/mutex.h>
|
||||||
#include <ememory/memory.h>
|
#include <etk/chrono.h>
|
||||||
|
#include <etk/functional.h>
|
||||||
|
#include <etk/memory.h>
|
||||||
#include <audio/channel.h>
|
#include <audio/channel.h>
|
||||||
#include <audio/format.h>
|
#include <audio/format.h>
|
||||||
#include <audio/orchestra/error.h>
|
#include <audio/orchestra/error.h>
|
||||||
@@ -23,3 +24,7 @@
|
|||||||
#include <audio/orchestra/StreamOptions.h>
|
#include <audio/orchestra/StreamOptions.h>
|
||||||
#include <audio/orchestra/StreamParameters.h>
|
#include <audio/orchestra/StreamParameters.h>
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@@ -8,6 +8,6 @@
|
|||||||
#include <audio/orchestra/debug.h>
|
#include <audio/orchestra/debug.h>
|
||||||
|
|
||||||
int32_t audio::orchestra::getLogId() {
|
int32_t audio::orchestra::getLogId() {
|
||||||
static int32_t g_val = elog::registerInstance("audio-orchestra");
|
static int32_t g_val = etk::log::registerInstance("audio-orchestra");
|
||||||
return g_val;
|
return g_val;
|
||||||
}
|
}
|
||||||
|
@@ -4,18 +4,19 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <elog/log.h>
|
#ifndef __AUDIO_ORCHESTRA_DEBUG_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_DEBUG_H__
|
||||||
|
|
||||||
|
#include <etk/log.h>
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
int32_t getLogId();
|
int32_t getLogId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#define ATA_BASE(info,data) ELOG_BASE(audio::orchestra::getLogId(),info,data)
|
#define ATA_BASE(info,data) TK_LOG_BASE(audio::orchestra::getLogId(),info,data)
|
||||||
|
|
||||||
#define ATA_PRINT(data) ATA_BASE(-1, data)
|
|
||||||
#define ATA_CRITICAL(data) ATA_BASE(1, data)
|
#define ATA_CRITICAL(data) ATA_BASE(1, data)
|
||||||
#define ATA_ERROR(data) ATA_BASE(2, data)
|
#define ATA_ERROR(data) ATA_BASE(2, data)
|
||||||
#define ATA_WARNING(data) ATA_BASE(3, data)
|
#define ATA_WARNING(data) ATA_BASE(3, data)
|
||||||
@@ -39,3 +40,5 @@ namespace audio {
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -4,7 +4,9 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_ERROR_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_ERROR_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
|
|
||||||
@@ -20,3 +22,5 @@ namespace audio {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -18,22 +18,4 @@ int32_t audio::orchestra::modeToIdTable(enum mode _mode) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& audio::operator <<(std::ostream& _os, enum audio::orchestra::mode _obj) {
|
|
||||||
switch (_obj) {
|
|
||||||
case audio::orchestra::mode_unknow:
|
|
||||||
_os << "unknow";
|
|
||||||
break;
|
|
||||||
case audio::orchestra::mode_duplex:
|
|
||||||
_os << "duplex";
|
|
||||||
break;
|
|
||||||
case audio::orchestra::mode_output:
|
|
||||||
_os << "output";
|
|
||||||
break;
|
|
||||||
case audio::orchestra::mode_input:
|
|
||||||
_os << "input";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return _os;
|
|
||||||
}
|
}
|
@@ -4,10 +4,13 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_MODE_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_MODE_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
enum mode {
|
enum mode {
|
||||||
@@ -18,6 +21,6 @@ namespace audio {
|
|||||||
};
|
};
|
||||||
int32_t modeToIdTable(enum mode _mode);
|
int32_t modeToIdTable(enum mode _mode);
|
||||||
}
|
}
|
||||||
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::mode _obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -4,18 +4,22 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_STATE_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_STATE_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
enum class state {
|
enum state {
|
||||||
closed,
|
state_closed,
|
||||||
stopped,
|
state_stopped,
|
||||||
stopping,
|
state_stopping,
|
||||||
running
|
state_running
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -14,7 +14,7 @@ static const char* listValue[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, enum audio::orchestra::status _obj) {
|
std::ostream& audio::orchestra::operator <<(std::ostream& _os, enum audio::orchestra::status _obj) {
|
||||||
_os << listValue[int32_t(_obj)];
|
_os << listValue[_obj];
|
||||||
return _os;
|
return _os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,19 +4,23 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_STATUS_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_STATUS_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
enum class status {
|
enum status {
|
||||||
ok, //!< nothing...
|
status_ok, //!< nothing...
|
||||||
overflow, //!< Internal buffer has more data than they can accept
|
status_overflow, //!< Internal buffer has more data than they can accept
|
||||||
underflow //!< The internal buffer is empty
|
status_underflow //!< The internal buffer is empty
|
||||||
};
|
};
|
||||||
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::status _obj);
|
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::status _obj);
|
||||||
std::ostream& operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::status>& _obj);
|
std::ostream& operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::status>& _obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -12,14 +12,62 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
const std::string audio::orchestra::typeUndefined = "undefined";
|
#undef __class__
|
||||||
const std::string audio::orchestra::typeAlsa = "alsa";
|
#define __class__ "type"
|
||||||
const std::string audio::orchestra::typePulse = "pulse";
|
|
||||||
const std::string audio::orchestra::typeOss = "oss";
|
static const char* listType[] = {
|
||||||
const std::string audio::orchestra::typeJack = "jack";
|
"undefined",
|
||||||
const std::string audio::orchestra::typeCoreOSX = "coreOSX";
|
"alsa",
|
||||||
const std::string audio::orchestra::typeCoreIOS = "coreIOS";
|
"pulse",
|
||||||
const std::string audio::orchestra::typeAsio = "asio";
|
"oss",
|
||||||
const std::string audio::orchestra::typeDs = "ds";
|
"jack",
|
||||||
const std::string audio::orchestra::typeJava = "java";
|
"coreOSX",
|
||||||
const std::string audio::orchestra::typeDummy = "dummy";
|
"corIOS",
|
||||||
|
"asio",
|
||||||
|
"ds",
|
||||||
|
"java",
|
||||||
|
"dummy",
|
||||||
|
"user1",
|
||||||
|
"user2",
|
||||||
|
"user3",
|
||||||
|
"user4"
|
||||||
|
};
|
||||||
|
static int32_t listTypeSize = sizeof(listType)/sizeof(char*);
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const enum audio::orchestra::type& _obj) {
|
||||||
|
_os << listType[_obj];
|
||||||
|
return _os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::type>& _obj) {
|
||||||
|
_os << std::string("{");
|
||||||
|
for (size_t iii=0; iii<_obj.size(); ++iii) {
|
||||||
|
if (iii!=0) {
|
||||||
|
_os << std::string(";");
|
||||||
|
}
|
||||||
|
_os << _obj[iii];
|
||||||
|
}
|
||||||
|
_os << std::string("}");
|
||||||
|
return _os;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
template <enum audio::format> std::string to_string(const enum audio::format& _variable) {
|
||||||
|
return listType[_value];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
std::string audio::orchestra::getTypeString(enum audio::orchestra::type _value) {
|
||||||
|
return listType[_value];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum audio::orchestra::type audio::orchestra::getTypeFromString(const std::string& _value) {
|
||||||
|
for (int32_t iii=0; iii<listTypeSize; ++iii) {
|
||||||
|
if (_value == listType[iii]) {
|
||||||
|
return static_cast<enum audio::orchestra::type>(iii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_value == "auto") {
|
||||||
|
return audio::orchestra::type_undefined;
|
||||||
|
}
|
||||||
|
return audio::orchestra::type_undefined;
|
||||||
|
}
|
||||||
|
@@ -4,27 +4,41 @@
|
|||||||
* @license APACHE v2.0 (see license file)
|
* @license APACHE v2.0 (see license file)
|
||||||
* @fork from RTAudio
|
* @fork from RTAudio
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
#ifndef __AUDIO_ORCHESTRA_TYPE_H__
|
||||||
|
#define __AUDIO_ORCHESTRA_TYPE_H__
|
||||||
|
|
||||||
#include <etk/types.h>
|
#include <etk/types.h>
|
||||||
#include <etk/stdTools.h>
|
#include <etk/stdTools.h>
|
||||||
|
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
namespace orchestra {
|
namespace orchestra {
|
||||||
/**
|
/**
|
||||||
* @brief Audio API specifier arguments.
|
* @brief Audio API specifier arguments.
|
||||||
*/
|
*/
|
||||||
extern const std::string typeUndefined; //!< Error API.
|
enum type {
|
||||||
extern const std::string typeAlsa; //!< LINUX The Advanced Linux Sound Architecture.
|
type_undefined, //!< Error API.
|
||||||
extern const std::string typePulse; //!< LINUX The Linux PulseAudio.
|
type_alsa, //!< LINUX The Advanced Linux Sound Architecture.
|
||||||
extern const std::string typeOss; //!< LINUX The Linux Open Sound System.
|
type_pulse, //!< LINUX The Linux PulseAudio.
|
||||||
extern const std::string typeJack; //!< UNIX The Jack Low-Latency Audio Server.
|
type_oss, //!< LINUX The Linux Open Sound System.
|
||||||
extern const std::string typeCoreOSX; //!< Macintosh OSX Core Audio.
|
type_jack, //!< UNIX The Jack Low-Latency Audio Server.
|
||||||
extern const std::string typeCoreIOS; //!< Macintosh iOS Core Audio.
|
type_coreOSX, //!< Macintosh OSX Core Audio.
|
||||||
extern const std::string typeAsio; //!< WINDOWS The Steinberg Audio Stream I/O.
|
type_coreIOS, //!< Macintosh iOS Core Audio.
|
||||||
extern const std::string typeDs; //!< WINDOWS The Microsoft Direct Sound.
|
type_asio, //!< WINDOWS The Steinberg Audio Stream I/O.
|
||||||
extern const std::string typeJava; //!< ANDROID Interface.
|
type_ds, //!< WINDOWS The Microsoft Direct Sound.
|
||||||
extern const std::string typeDummy; //!< Empty wrapper (non-functional).
|
type_java, //!< ANDROID Interface.
|
||||||
|
type_dummy, //!< Empty wrapper (non-functional).
|
||||||
|
type_user1, //!< User interface 1.
|
||||||
|
type_user2, //!< User interface 2.
|
||||||
|
type_user3, //!< User interface 3.
|
||||||
|
type_user4, //!< User interface 4.
|
||||||
|
};
|
||||||
|
std::ostream& operator <<(std::ostream& _os, const enum audio::orchestra::type& _obj);
|
||||||
|
std::ostream& operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::type>& _obj);
|
||||||
|
std::string getTypeString(enum audio::orchestra::type _value);
|
||||||
|
enum audio::orchestra::type getTypeFromString(const std::string& _value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -1,181 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import lutin.module as module
|
|
||||||
import lutin.tools as tools
|
|
||||||
import lutin.debug as debug
|
|
||||||
|
|
||||||
|
|
||||||
def get_type():
|
|
||||||
return "LIBRARY"
|
|
||||||
|
|
||||||
def get_desc():
|
|
||||||
return "Generic wrapper on all audio interface"
|
|
||||||
|
|
||||||
def get_licence():
|
|
||||||
return "APACHE-2"
|
|
||||||
|
|
||||||
def get_compagny_type():
|
|
||||||
return "com"
|
|
||||||
|
|
||||||
def get_compagny_name():
|
|
||||||
return "atria-soft"
|
|
||||||
|
|
||||||
def get_maintainer():
|
|
||||||
return ["Mr DUPIN Edouard <yui.heero@gmail.com>"]
|
|
||||||
|
|
||||||
def get_version():
|
|
||||||
return [0,3,0]
|
|
||||||
|
|
||||||
def create(target, module_name):
|
|
||||||
my_module = module.Module(__file__, module_name, get_type())
|
|
||||||
my_module.add_src_file([
|
|
||||||
'audio/orchestra/debug.cpp',
|
|
||||||
'audio/orchestra/status.cpp',
|
|
||||||
'audio/orchestra/type.cpp',
|
|
||||||
'audio/orchestra/mode.cpp',
|
|
||||||
'audio/orchestra/state.cpp',
|
|
||||||
'audio/orchestra/error.cpp',
|
|
||||||
'audio/orchestra/base.cpp',
|
|
||||||
'audio/orchestra/Interface.cpp',
|
|
||||||
'audio/orchestra/Flags.cpp',
|
|
||||||
'audio/orchestra/Api.cpp',
|
|
||||||
'audio/orchestra/DeviceInfo.cpp',
|
|
||||||
'audio/orchestra/StreamOptions.cpp',
|
|
||||||
'audio/orchestra/api/Dummy.cpp'
|
|
||||||
])
|
|
||||||
my_module.add_header_file([
|
|
||||||
'audio/orchestra/debug.h',
|
|
||||||
'audio/orchestra/status.h',
|
|
||||||
'audio/orchestra/type.h',
|
|
||||||
'audio/orchestra/mode.h',
|
|
||||||
'audio/orchestra/state.h',
|
|
||||||
'audio/orchestra/error.h',
|
|
||||||
'audio/orchestra/base.h',
|
|
||||||
'audio/orchestra/Interface.h',
|
|
||||||
'audio/orchestra/Flags.h',
|
|
||||||
'audio/orchestra/Api.h',
|
|
||||||
'audio/orchestra/DeviceInfo.h',
|
|
||||||
'audio/orchestra/StreamOptions.h',
|
|
||||||
'audio/orchestra/CallbackInfo.h',
|
|
||||||
'audio/orchestra/StreamParameters.h'
|
|
||||||
])
|
|
||||||
my_module.add_module_depend(['audio', 'etk'])
|
|
||||||
# add all the time the dummy interface
|
|
||||||
my_module.add_export_flag('c++', ['-DORCHESTRA_BUILD_DUMMY'])
|
|
||||||
# TODO : Add a FILE interface:
|
|
||||||
|
|
||||||
if target.config_based_on=="Windows":
|
|
||||||
my_module.add_src_file([
|
|
||||||
'audio/orchestra/api/Asio.cpp',
|
|
||||||
'audio/orchestra/api/Ds.cpp',
|
|
||||||
])
|
|
||||||
# load optionnal API:
|
|
||||||
my_module.add_optionnal_module_depend('asio', ["c++", "-DORCHESTRA_BUILD_ASIO"])
|
|
||||||
my_module.add_optionnal_module_depend('ds', ["c++", "-DORCHESTRA_BUILD_DS"])
|
|
||||||
my_module.add_optionnal_module_depend('wasapi', ["c++", "-DORCHESTRA_BUILD_WASAPI"])
|
|
||||||
elif target.config_based_on=="Linux":
|
|
||||||
my_module.add_src_file([
|
|
||||||
'audio/orchestra/api/Alsa.cpp',
|
|
||||||
'audio/orchestra/api/Jack.cpp',
|
|
||||||
'audio/orchestra/api/Pulse.cpp',
|
|
||||||
'audio/orchestra/api/PulseDeviceList.cpp'
|
|
||||||
])
|
|
||||||
my_module.add_optionnal_module_depend('alsa', ["c++", "-DORCHESTRA_BUILD_ALSA"])
|
|
||||||
my_module.add_optionnal_module_depend('jack', ["c++", "-DORCHESTRA_BUILD_JACK"])
|
|
||||||
my_module.add_optionnal_module_depend('pulse', ["c++", "-DORCHESTRA_BUILD_PULSE"])
|
|
||||||
elif target.config_based_on=="MacOs":
|
|
||||||
my_module.add_src_file([
|
|
||||||
'audio/orchestra/api/Core.cpp'
|
|
||||||
])
|
|
||||||
# MacOsX core
|
|
||||||
my_module.add_optionnal_module_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_MACOSX_CORE"])
|
|
||||||
elif target.config_based_on=="IOs":
|
|
||||||
my_module.add_src_file('audio/orchestra/api/CoreIos.mm')
|
|
||||||
# IOsX core
|
|
||||||
my_module.add_optionnal_module_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_IOS_CORE"])
|
|
||||||
elif target.config_based_on=="Android":
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraConstants.java')
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraManagerCallback.java')
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraNative.java')
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraInterfaceInput.java')
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraInterfaceOutput.java')
|
|
||||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraManager.java')
|
|
||||||
# create inter language interface
|
|
||||||
my_module.add_src_file('org.musicdsp.orchestra.OrchestraConstants.javah')
|
|
||||||
my_module.add_path(tools.get_current_path(__file__) + '/android/', type='java')
|
|
||||||
my_module.add_module_depend(['SDK', 'jvm-basics', 'ejson'])
|
|
||||||
my_module.add_export_flag('c++', ['-DORCHESTRA_BUILD_JAVA'])
|
|
||||||
|
|
||||||
my_module.add_src_file('audio/orchestra/api/Android.cpp')
|
|
||||||
my_module.add_src_file('audio/orchestra/api/AndroidNativeInterface.cpp')
|
|
||||||
# add tre creator of the basic java class ...
|
|
||||||
target.add_action("BINARY", 11, "audio-orchestra-out-wrapper", tool_generate_add_java_section_in_class)
|
|
||||||
else:
|
|
||||||
debug.warning("unknow target for audio_orchestra : " + target.name);
|
|
||||||
|
|
||||||
my_module.add_path(tools.get_current_path(__file__))
|
|
||||||
|
|
||||||
return my_module
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##################################################################
|
|
||||||
##
|
|
||||||
## Android specific section
|
|
||||||
##
|
|
||||||
##################################################################
|
|
||||||
def tool_generate_add_java_section_in_class(target, module, package_name):
|
|
||||||
module.pkg_add("GENERATE_SECTION__IMPORT", [
|
|
||||||
"import org.musicdsp.orchestra.OrchestraManager;"
|
|
||||||
])
|
|
||||||
module.pkg_add("GENERATE_SECTION__DECLARE", [
|
|
||||||
"private OrchestraManager m_audioManagerHandle;"
|
|
||||||
])
|
|
||||||
module.pkg_add("GENERATE_SECTION__CONSTRUCTOR", [
|
|
||||||
"// load audio maneger if it does not work, it is not critical ...",
|
|
||||||
"try {",
|
|
||||||
" m_audioManagerHandle = new OrchestraManager();",
|
|
||||||
"} 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();",
|
|
||||||
"}"
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
77
lutin_audio_orchestra.py
Normal file
77
lutin_audio_orchestra.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import lutin.module as module
|
||||||
|
import lutin.tools as tools
|
||||||
|
import lutin.debug as debug
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "audio_orchestra : Generic wrapper on all audio interface"
|
||||||
|
|
||||||
|
|
||||||
|
def create(target):
|
||||||
|
myModule = module.Module(__file__, 'audio_orchestra', 'LIBRARY')
|
||||||
|
|
||||||
|
myModule.add_src_file([
|
||||||
|
'audio/orchestra/debug.cpp',
|
||||||
|
'audio/orchestra/status.cpp',
|
||||||
|
'audio/orchestra/type.cpp',
|
||||||
|
'audio/orchestra/mode.cpp',
|
||||||
|
'audio/orchestra/state.cpp',
|
||||||
|
'audio/orchestra/error.cpp',
|
||||||
|
'audio/orchestra/base.cpp',
|
||||||
|
'audio/orchestra/Interface.cpp',
|
||||||
|
'audio/orchestra/Flags.cpp',
|
||||||
|
'audio/orchestra/Api.cpp',
|
||||||
|
'audio/orchestra/DeviceInfo.cpp',
|
||||||
|
'audio/orchestra/StreamOptions.cpp',
|
||||||
|
'audio/orchestra/api/Dummy.cpp'
|
||||||
|
])
|
||||||
|
myModule.add_module_depend(['audio', 'etk'])
|
||||||
|
# add all the time the dummy interface
|
||||||
|
myModule.add_export_flag('c++', ['-DORCHESTRA_BUILD_DUMMY'])
|
||||||
|
# TODO : Add a FILE interface:
|
||||||
|
|
||||||
|
if target.name=="Windows":
|
||||||
|
myModule.add_src_file([
|
||||||
|
'audio/orchestra/api/Asio.cpp',
|
||||||
|
'audio/orchestra/api/Ds.cpp',
|
||||||
|
])
|
||||||
|
# load optionnal API:
|
||||||
|
myModule.add_optionnal_module_depend('asio', ["c++", "-DORCHESTRA_BUILD_ASIO"])
|
||||||
|
myModule.add_optionnal_module_depend('ds', ["c++", "-DORCHESTRA_BUILD_DS"])
|
||||||
|
myModule.add_optionnal_module_depend('wasapi', ["c++", "-DORCHESTRA_BUILD_WASAPI"])
|
||||||
|
elif target.name=="Linux":
|
||||||
|
myModule.add_src_file([
|
||||||
|
'audio/orchestra/api/Alsa.cpp',
|
||||||
|
'audio/orchestra/api/Jack.cpp',
|
||||||
|
'audio/orchestra/api/Pulse.cpp',
|
||||||
|
'audio/orchestra/api/Oss.cpp'
|
||||||
|
])
|
||||||
|
myModule.add_optionnal_module_depend('alsa', ["c++", "-DORCHESTRA_BUILD_ALSA"])
|
||||||
|
myModule.add_optionnal_module_depend('jack', ["c++", "-DORCHESTRA_BUILD_JACK"])
|
||||||
|
myModule.add_optionnal_module_depend('pulse', ["c++", "-DORCHESTRA_BUILD_PULSE"])
|
||||||
|
myModule.add_optionnal_module_depend('oss', ["c++", "-DORCHESTRA_BUILD_OSS"])
|
||||||
|
elif target.name=="MacOs":
|
||||||
|
myModule.add_src_file([
|
||||||
|
'audio/orchestra/api/Core.cpp',
|
||||||
|
'audio/orchestra/api/Oss.cpp'
|
||||||
|
])
|
||||||
|
# MacOsX core
|
||||||
|
myModule.add_optionnal_module_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_MACOSX_CORE"])
|
||||||
|
elif target.name=="IOs":
|
||||||
|
myModule.add_src_file('audio/orchestra/api/CoreIos.mm')
|
||||||
|
# IOsX core
|
||||||
|
myModule.add_optionnal_module_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_IOS_CORE"])
|
||||||
|
elif target.name=="Android":
|
||||||
|
myModule.add_src_file('audio/orchestra/api/Android.cpp')
|
||||||
|
# specidic java interface for android:
|
||||||
|
myModule.add_optionnal_module_depend('ewolAndroidAudio', ["c++", "-DORCHESTRA_BUILD_JAVA"])
|
||||||
|
#myModule.add_module_depend(['ewol'])
|
||||||
|
else:
|
||||||
|
debug.warning("unknow target for audio_orchestra : " + target.name);
|
||||||
|
|
||||||
|
myModule.add_export_path(tools.get_current_path(__file__))
|
||||||
|
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
||||||
|
|
@@ -1,37 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import lutin.module as module
|
|
||||||
import lutin.tools as tools
|
|
||||||
import lutin.debug as debug
|
|
||||||
|
|
||||||
|
|
||||||
def get_type():
|
|
||||||
return "BINARY"
|
|
||||||
|
|
||||||
def get_sub_type():
|
|
||||||
return "TOOLS"
|
|
||||||
|
|
||||||
def get_desc():
|
|
||||||
return "'in' tool for orchestra"
|
|
||||||
|
|
||||||
def get_licence():
|
|
||||||
return "APACHE-2"
|
|
||||||
|
|
||||||
def get_compagny_type():
|
|
||||||
return "com"
|
|
||||||
|
|
||||||
def get_compagny_name():
|
|
||||||
return "atria-soft"
|
|
||||||
|
|
||||||
def get_maintainer():
|
|
||||||
return ["Mr DUPIN Edouard <yui.heero@gmail.com>"]
|
|
||||||
|
|
||||||
def create(target, module_name):
|
|
||||||
my_module = module.Module(__file__, module_name, get_type())
|
|
||||||
|
|
||||||
my_module.add_src_file([
|
|
||||||
'orchestra-in.cpp'
|
|
||||||
])
|
|
||||||
my_module.add_module_depend(['audio-orchestra', 'test-debug'])
|
|
||||||
return my_module
|
|
||||||
|
|
||||||
|
|
@@ -1,37 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import lutin.module as module
|
|
||||||
import lutin.tools as tools
|
|
||||||
import lutin.debug as debug
|
|
||||||
|
|
||||||
|
|
||||||
def get_type():
|
|
||||||
return "BINARY"
|
|
||||||
|
|
||||||
def get_sub_type():
|
|
||||||
return "TOOLS"
|
|
||||||
|
|
||||||
def get_desc():
|
|
||||||
return "'list' i/o tool for orchestra"
|
|
||||||
|
|
||||||
def get_licence():
|
|
||||||
return "APACHE-2"
|
|
||||||
|
|
||||||
def get_compagny_type():
|
|
||||||
return "com"
|
|
||||||
|
|
||||||
def get_compagny_name():
|
|
||||||
return "atria-soft"
|
|
||||||
|
|
||||||
def get_maintainer():
|
|
||||||
return ["Mr DUPIN Edouard <yui.heero@gmail.com>"]
|
|
||||||
|
|
||||||
def create(target, module_name):
|
|
||||||
my_module = module.Module(__file__, module_name, get_type())
|
|
||||||
|
|
||||||
my_module.add_src_file([
|
|
||||||
'orchestra-list.cpp'
|
|
||||||
])
|
|
||||||
my_module.add_module_depend(['audio-orchestra', 'test-debug'])
|
|
||||||
return my_module
|
|
||||||
|
|
||||||
|
|
@@ -1,37 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import lutin.module as module
|
|
||||||
import lutin.tools as tools
|
|
||||||
import lutin.debug as debug
|
|
||||||
|
|
||||||
|
|
||||||
def get_type():
|
|
||||||
return "BINARY"
|
|
||||||
|
|
||||||
def get_sub_type():
|
|
||||||
return "TOOLS"
|
|
||||||
|
|
||||||
def get_desc():
|
|
||||||
return "'out' tool for orchestra"
|
|
||||||
|
|
||||||
def get_licence():
|
|
||||||
return "APACHE-2"
|
|
||||||
|
|
||||||
def get_compagny_type():
|
|
||||||
return "com"
|
|
||||||
|
|
||||||
def get_compagny_name():
|
|
||||||
return "atria-soft"
|
|
||||||
|
|
||||||
def get_maintainer():
|
|
||||||
return ["Mr DUPIN Edouard <yui.heero@gmail.com>"]
|
|
||||||
|
|
||||||
def create(target, module_name):
|
|
||||||
my_module = module.Module(__file__, module_name, get_type())
|
|
||||||
|
|
||||||
my_module.add_src_file([
|
|
||||||
'orchestra-out.cpp'
|
|
||||||
])
|
|
||||||
my_module.add_module_depend(['audio-orchestra', 'test-debug'])
|
|
||||||
return my_module
|
|
||||||
|
|
||||||
|
|
@@ -1,28 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <etk/etk.h>
|
|
||||||
#include <test-debug/debug.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <audio/orchestra/Interface.h>
|
|
||||||
|
|
||||||
int main(int _argc, const char **_argv) {
|
|
||||||
// the only one init for etk:
|
|
||||||
etk::init(_argc, _argv);
|
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
|
||||||
std::string data = _argv[iii];
|
|
||||||
if ( data == "-h"
|
|
||||||
|| data == "--help") {
|
|
||||||
std::cout << "Help : " << std::endl;
|
|
||||||
std::cout << " ./xxx ---" << std::endl;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio::orchestra::Interface interface;
|
|
||||||
TEST_PRINT("TODO : Need to write it");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,39 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <etk/etk.h>
|
|
||||||
#include <test-debug/debug.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <audio/orchestra/Interface.h>
|
|
||||||
|
|
||||||
int main(int _argc, const char **_argv) {
|
|
||||||
// the only one init for etk:
|
|
||||||
etk::init(_argc, _argv);
|
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
|
||||||
std::string data = _argv[iii];
|
|
||||||
if ( data == "-h"
|
|
||||||
|| data == "--help") {
|
|
||||||
std::cout << "Help : " << std::endl;
|
|
||||||
std::cout << " ./xxx ---" << std::endl;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio::orchestra::Interface interface;
|
|
||||||
std::vector<std::string> apis = interface.getListApi();
|
|
||||||
TEST_PRINT("Find : " << apis.size() << " apis.");
|
|
||||||
for (auto &it : apis) {
|
|
||||||
interface.instanciate(it);
|
|
||||||
TEST_PRINT("Device list for : '" << it << "'");
|
|
||||||
for (int32_t iii=0; iii<interface.getDeviceCount(); ++iii) {
|
|
||||||
audio::orchestra::DeviceInfo info = interface.getDeviceInfo(iii);
|
|
||||||
TEST_PRINT(" " << iii << " name :" << info.name);
|
|
||||||
info.display(2);
|
|
||||||
}
|
|
||||||
interface.clear();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,27 +0,0 @@
|
|||||||
/** @file
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
|
||||||
* @license APACHE v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <etk/etk.h>
|
|
||||||
#include <test-debug/debug.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <audio/orchestra/Interface.h>
|
|
||||||
|
|
||||||
int main(int _argc, const char **_argv) {
|
|
||||||
// the only one init for etk:
|
|
||||||
etk::init(_argc, _argv);
|
|
||||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
|
||||||
std::string data = _argv[iii];
|
|
||||||
if ( data == "-h"
|
|
||||||
|| data == "--help") {
|
|
||||||
std::cout << "Help : " << std::endl;
|
|
||||||
std::cout << " ./xxx ---" << std::endl;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio::orchestra::Interface interface;
|
|
||||||
TEST_PRINT("TODO : Need to write it");
|
|
||||||
return 0;
|
|
||||||
}
|
|
Reference in New Issue
Block a user