Commit fc14ecdd authored by Fabian Schlieper's avatar Fabian Schlieper
Browse files

fixes for linux

added jack interface
parent a733c28d
cmake_minimum_required( VERSION 2.8 )
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project( ITADataSources )
......@@ -128,6 +128,11 @@ endif( NOT WIN32)
add_library( ITADataSources ${ITADataSourcesHeader} ${ITADataSourcesSources} )
target_link_libraries( ITADataSources ${VISTA_USE_PACKAGE_LIBRARIES} )
#target_compile_features(ITADataSources PRIVATE cxx_range_for)
add_definitions( -std=c++11 )
set( BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_TEMP} )
......
......@@ -58,7 +58,7 @@ void ITAJackPortRegistered(jack_port_id_t port_id, int reg, void *arg);
class ITAJACKInterface {
public:
//! ITAPortaudio error code table
typedef enum ITA_JACK_ERRORCODE {
enum ITA_JACK_ERRORCODE {
//! Portaudio/ITAPortaudio no error
ITA_JACK_NO_ERROR=0,
ITA_JACK_ERROR=1,
......@@ -77,35 +77,15 @@ public:
};
//! Constructor with sample rate and buffer size
/**
* Set up internal variables of ITAPortaudio. No exception will be
* thrown here.
* \note Next do initialization
*
* \see #Initialize #Initialize(const int iDriver)
*/
ITAJACKInterface();
ITAJACKInterface(int blockSize = -1);
//! Destructor
~ITAJACKInterface();
//! Initialize Portaudio using default hardware and default host/driver
/**
* Initializes Portaudio with the current driver. If no driver has been set,
* the default output device will be used, while the input device will be
* deactivated (playback mode on, recording mode off).
*
* \return Will return error code if Portaudio could not be initialized with the current configuration, ITA_JACK_NO_ERROR otherwise
*/
ITA_JACK_ERRORCODE Initialize();
//! Initialize JACK
ITA_JACK_ERRORCODE Initialize(const std::string& clientName);
//! Use Portaudio with specific input device
ITA_JACK_ERRORCODE SetOutputDevice( int iOutputDevice );
//! Returns true if playback is enabled, false otherwise
bool IsPlaybackEnabled() const;
......@@ -153,18 +133,6 @@ public:
ITA_JACK_ERRORCODE GetDriverSampleRate(int iDeviceID, double& dSampleRate) const;
//! Returns the name of the current devices in Portaudio
std::string GetInputDeviceName() const;
//! Returns the name of the current devices in Portaudio
std::string GetOutputDeviceName() const;
//! Get default input device index
int GetDefaultInputDevice() const;
//! Get default output device index
int GetDefaultOutputDevice() const;
//! Get current input device index
int GetInputDevice() const;
......@@ -179,7 +147,7 @@ public:
/**
* \return Number of input channels (>=0) or #ITA_JACK_ERRORCODE (<0)
*/
int GetNumInputChannels(int iDeviceID) const;
int GetNumInputChannels(int iDeviceID=0) const;
//! Returns the number of output channels
/**
......
......@@ -11,8 +11,13 @@
#include <cmath>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
void WriteFromDatasourceToBuffer(ITADatasource* pSource,
......@@ -30,26 +35,34 @@ void WriteFromDatasourceToBuffer(ITADatasource* pSource,
unsigned int uiBlocklength = pSource->GetBlocklength();
ITAStreamInfo siState;
HANDLE hTimer=0;
long periodMs = (long)ceil(uiBlocklength / dSamplerate * 1000);
#ifdef _WIN32
HANDLE hTimer=0;
if (bOnline) {
// Timer erzeugen
if (FAILED(hTimer = CreateWaitableTimer(NULL, false, NULL)))
if (FAILED(hTimer = CreateWaitableTimer(NULL, false, NULL)))
ITA_EXCEPT1(UNKNOWN, "Timer konnte nicht erzeugt werden");
LARGE_INTEGER liDueTime;
liDueTime.QuadPart=0;
long ms = (long) ceil(uiBlocklength/dSamplerate*1000);
SetWaitableTimer(hTimer, &liDueTime, ms, NULL, NULL, true);
liDueTime.QuadPart = 0;
SetWaitableTimer(hTimer, &liDueTime, periodMs, NULL, NULL, true);
}
#endif
try {
unsigned int n=0;
float fProgress = 0.0f;
while (n < uiNumberOfSamples)
{
#ifdef _WIN32
// Warten
if (bOnline) WaitForSingleObject(hTimer, INFINITE);
#else
if (bOnline) usleep(periodMs * 1000);
#endif
// Daten von der Quelle holen
for (unsigned int i=0; i<uiChannels; i++) {
......@@ -87,15 +100,19 @@ void WriteFromDatasourceToBuffer(ITADatasource* pSource,
}
}
} catch (...) {
#ifdef _WIN32
if (bOnline) CloseHandle(hTimer);
#endif
throw;
}
if (bDisplayProgress)
printf("WriteFromDatasourceToBuffer: 100,00%% geschrieben");
#ifdef _WIN32
if (bOnline)
CloseHandle(hTimer);
#endif
}
void WriteFromDatasourceToFile(ITADatasource* pSource,
......@@ -125,6 +142,9 @@ void WriteFromDatasourceToFile(ITADatasource* pSource,
ITAAudiofileWriter* writer = ITAAudiofileWriter::create(sFilename, props);
ITAStreamInfo siState;
long periodMs = (long)ceil(uiBlocklength / dSamplerate * 1000);
#ifdef _WIN32
HANDLE hTimer=0;
if (bOnline) {
......@@ -136,16 +156,21 @@ void WriteFromDatasourceToFile(ITADatasource* pSource,
LARGE_INTEGER liDueTime;
liDueTime.QuadPart=0;
long ms = (long) ceil(uiBlocklength/dSamplerate*1000);
SetWaitableTimer(hTimer, &liDueTime, ms, NULL, NULL, true);
SetWaitableTimer(hTimer, &liDueTime, periodMs, NULL, NULL, true);
}
#endif
try {
unsigned int n=0;
float fProgress = 0.0;
while (n < uiNumberOfSamples) {
#ifdef _WIN32
// Warten
if (bOnline) WaitForSingleObject(hTimer, INFINITE);
#else
if (bOnline) usleep(periodMs * 1000);
#endif
// Daten von der Quelle holen
for (unsigned int i=0; i<uiChannels; i++) {
......@@ -168,7 +193,7 @@ void WriteFromDatasourceToFile(ITADatasource* pSource,
siState.dTimecode = (double) (siState.nSamples) / dSamplerate;
// Daten schreiben
writer->write(__min(uiBlocklength, (uiNumberOfSamples - n)), vpfData);
writer->write((std::min)(uiBlocklength, (uiNumberOfSamples - n)), vpfData);
n += uiBlocklength;
......@@ -183,7 +208,9 @@ void WriteFromDatasourceToFile(ITADatasource* pSource,
}
}
} catch (...) {
#ifdef _WIN32
if (bOnline) CloseHandle(hTimer);
#endif
delete writer;
throw;
}
......@@ -191,8 +218,10 @@ void WriteFromDatasourceToFile(ITADatasource* pSource,
if (bDisplayProgress)
printf("WriteFromDatasourceToFile: 100,00%% geschrieben\r");
#ifdef _WIN32
if (bOnline)
CloseHandle(hTimer);
#endif
delete writer;
}
......
......@@ -6,14 +6,16 @@
#include <vector>
#include <math.h>
#include <signal.h>
#include <future>
#include <ITADatasource.h>
#include <ITADatasourceRealization.h>
#include <ITADataSource.h>
#include <ITADataSourceRealization.h>
#include <ITAStreamInfo.h>
static int ITAJackProcess (jack_nframes_t nframes, void *arg);
void connectNewPortToInput(jack_port_t * port, ITAJACKInterface::ITAJackUserData* userData);
jack_client_t *ITAJACKInterface::s_jackClient = NULL;
......@@ -36,7 +38,8 @@ public:
};
ITAJACKInterface::ITAJACKInterface()
ITAJACKInterface::ITAJACKInterface(int blockSize)
:m_iBufferSize(blockSize)
{
m_jackClient = NULL;
......@@ -104,7 +107,11 @@ ITAJACKInterface::ITA_JACK_ERRORCODE ITAJACKInterface::Initialize(const std::str
jack_on_shutdown (m_jackClient, ITAJackShutdown, 0);
jack_set_port_connect_callback(m_jackClient, ITAJackPortConnected, &m_oUserData);
m_iBufferSize = jack_get_buffer_size(m_jackClient);
if (m_iBufferSize > 0)
jack_set_buffer_size(m_jackClient, m_iBufferSize);
else
m_iBufferSize = jack_get_buffer_size(m_jackClient);
m_dSampleRate = jack_get_sample_rate(m_jackClient);
// get physical ports
......@@ -451,3 +458,129 @@ static int ITAJackProcess (jack_nframes_t nframes, void *arg)
return 0;
}
// Callbacks
void ITAJackPortRegistered(jack_port_id_t port_id, int reg, void *arg)
{
ITAJACKInterface::ITAJackUserData* userData = (ITAJACKInterface::ITAJackUserData*)arg;
jack_port_t * port = jack_port_by_id (ITAJACKInterface::GetJackClient(), port_id);
// ignore own ports
if(jack_port_is_mine(ITAJACKInterface::GetJackClient(), port)) {
return;
}
// ignore mplayer!
if(strstr(jack_port_name (port), "MPlayer") != NULL) {
return;
}
int flags = jack_port_flags(port);
if(flags & JackPortIsOutput) {
std::async(std::launch::async, [port, userData] {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
connectNewPortToInput(port, userData);
});
}
/*
do_http_callback("port_registered",
"port_name=%s", jack_port_name (port),
"register=%d", reg,
"flags=%d", jack_port_flags(port),
NULL
);*/
}
int ITAJackXRUN(void *arg)
{
ITAJACKInterface::ITAJackUserData* userData = (ITAJACKInterface::ITAJackUserData*)arg;
userData->num_xruns++;
if((userData->num_xruns % 100) == 0)
// fprintf(stderr,"XRUNS: %lu\n",userData->num_xruns);
return 0;
}
void ITAJackMsg(const char *msg)
{
fprintf(stderr,"%s\n",msg);
}
void ITAJackShutdown (void *arg)
{
//if(arg != NULL)
// delete arg;
fprintf(stderr, "ITAJackShutdown: exiting ...\n");
exit(0);
}
void connectNewPortToInput(jack_port_t * port, ITAJACKInterface::ITAJackUserData* userData)
{
const char *portNameA = jack_port_name(port);
// get channel number by trailing number (-1 because 0 indexing)
int ch = atoi(&portNameA[strlen(portNameA) - 1]) - 1;
if (ch >= 0 && ch < JACK_MAX_CHANNELS) {
if (userData->input_ports[ch] && !jack_port_connected_to(userData->input_ports[ch], portNameA)) {
printf("Connecting port %s -> %s\n", portNameA, jack_port_name(userData->input_ports[ch]));
if (jack_connect(ITAJACKInterface::GetJackClient(), portNameA, jack_port_name(userData->input_ports[ch])) != 0) {
printf("\t... connection failed!\n");
}
}
}
// if mono, connect to all ports!
if (ch == -1) {
for (ch = 0; ch < JACK_MAX_CHANNELS; ch++) {
if (userData->input_ports[ch] && !jack_port_connected_to(userData->input_ports[ch], portNameA)) {
printf("Connecting port %s -> %s\n", portNameA, jack_port_name(userData->input_ports[ch]));
if (jack_connect(ITAJACKInterface::GetJackClient(), portNameA, jack_port_name(userData->input_ports[ch])) != 0)
printf("\t... connection failed!\n");
}
}
}
}
void ITAJackPortConnected(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
{
ITAJACKInterface::ITAJackUserData* userData = (ITAJACKInterface::ITAJackUserData*)arg;
jack_client_t *client = ITAJACKInterface::GetJackClient();
jack_port_t * portA = jack_port_by_id (client, a);
jack_port_t * portB = jack_port_by_id (client, b);
// ignore if any of the port belongs to the client
if(jack_port_is_mine(client, portA) || jack_port_is_mine(client, portB) ) {
return;
}
//int flagsA = jack_port_flags(portA);
int flagsB = jack_port_flags(portB);
if(flagsB & JackPortIsPhysical) {
const char *portNameA = jack_port_name(portA);
std::async(std::launch::async, [client, portNameA, portA, portB, userData] {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
jack_disconnect(client, portNameA, jack_port_name(portB));
connectNewPortToInput(portA, userData);
});
}
}
......@@ -122,5 +122,13 @@ set_property( TARGET StreamProbeTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataS
# Portaudio tests
add_subdirectory( "ITAPortaudioTests" )
if( VPORTAUDIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
add_subdirectory( "ITAPortaudioTests" )
endif( VPORTAUDIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
if( VJACK_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_JACK )
add_subdirectory( "ITAJACKTests" )
endif( VJACK_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_JACK )
add_subdirectory( "VistaNetTest" )
#include <ITAException.h>
#include <ITAFileDataSource.h>
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <stdio.h>
#include <iostream>
......
#include <ITAException.h>
#include <ITAFileDatasource.h>
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <ITAStreamFilterType1.h>
#include <ITAStringUtils.h>
#include <iostream>
......
......@@ -20,7 +20,7 @@
// $Id: Measure.cpp 1801 2011-04-13 14:07:25Z stienen $
#include <ITAsioInterface.h>
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <ITAException.h>
#include <ITAFileDatasource.h>
#include <stdio.h>
......
#include <ITAException.h>
#include <ITAAsioInterface.h>
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <stdio.h>
#include <iostream>
......
cmake_minimum_required( VERSION 2.8 )
if( NOT ITADATASOURCES_COMMON_BUILD )
project( ITADataSourcesTest )
list( APPEND CMAKE_MODULE_PATH "$ENV{VISTA_CMAKE_COMMON}" )
include( VistaCommon )
endif()
vista_use_package( ITADataSources REQUIRED FIND_DEPENDENCIES )
add_definitions( -DITA_DATA_SOURCES_DLL )
add_executable( ITAJackLoopback ITAJackLoopback.cpp )
target_link_libraries( ITAJackLoopback ${VISTA_USE_PACKAGE_LIBRARIES} )
vista_configure_app( ITAJackLoopback )
vista_install( ITAJackLoopback )
vista_create_default_info_file( ITAJackLoopback )
set_property( TARGET ITAJackLoopback PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources" )
// $Id: ITAPortaudioInterfaceRecorder.cpp 2333 2012-03-05 14:21:39Z stienen $
#include <iostream>
#include <string>
#include <ITADataSourceUtils.h>
#include <ITAJACKInterface.h>
#include <ITADataSourceRealization.h>
#include <ITAFileDatasource.h>
#include <ITAStreamFunctionGenerator.h>
static double dSampleRate = 44.1e3;
static int iBlockSize = 512;
static std::string sOutputFileName = "ITAPA_Record.wav";
float fRecordingTime = 5; // Seconds
class Loopback : public ITADatasourceRealization {
public:
Loopback(ITADatasource* pSource, long lChannels, double dSampleRate, long lBuffersize)
: ITADatasourceRealization((unsigned int)lChannels, dSampleRate,
(unsigned int)lBuffersize) {
this->pSource = pSource;
bFirst = true;
}
const float* GetBlockPointer(unsigned int uiChannel, const ITAStreamInfo* pStreamInfo) {
if (bFirst) {
for (unsigned int i = 0; i<m_uiChannels; i++)
memcpy(GetWritePointer(i),
pSource->GetBlockPointer(i, pStreamInfo),
m_uiBlocklength * sizeof(float));
IncrementWritePointer();
pSource->IncrementBlockPointer();
bFirst = false;
}
return ITADatasourceRealization::GetBlockPointer(uiChannel, pStreamInfo);
}
void IncrementBlockPointer() {
ITADatasourceRealization::IncrementBlockPointer();
bFirst = true;
}
private:
ITADatasource* pSource;
bool bFirst;
};
void loopback() {
ITAJACKInterface jack(iBlockSize);
jack.SetPlaybackEnabled(true);
jack.SetRecordEnabled(true);
auto err = jack.Initialize("jack-test");
if (err != ITAJACKInterface::ITA_JACK_NO_ERROR) {
std::cerr << "Failed to init jack!" << std::endl;
return;
}
auto dsIn = jack.GetRecordDatasource();
int blockSize = dsIn->GetBlocklength();
// TODO
ITADatasource* pSource = NULL;
try
{
pSource = new ITAFileDatasource("../ITAAsioTests/Trompete.wav", blockSize, true);
}
catch (ITAException& e)
{
std::cerr << "Could open audio file, error = " << e << std::endl;
pSource = new ITAStreamFunctionGenerator(1, dSampleRate, blockSize, ITAStreamFunctionGenerator::SINE, 300, 0.9f, true);
}
Loopback dsLoop(pSource, jack.GetNumInputChannels(), jack.GetSampleRate(), dsIn->GetBlocklength());
jack.SetPlaybackDatasource(&dsLoop);
jack.Open();
jack.Start();
getchar();
jack.Stop();
jack.Close();
jack.Finalize();
return;
}
int main(int argc,char *argv[]) {
std::cout << "Starting loopback ..." << std::endl;
loopback();
return 0;
}
\ No newline at end of file
ALSA_HW=1
SAMPLE_RATE=44100
BLOCK_SIZE=256
NUM_INPUTS=2
NUM_OUTPUTS=2
if [[ ! `pidof jackd` ]]; then
echo "Starting JACK server..."
jackd --realtime -P70 --sync -dalsa -dhw:${ALSA_HW},0 -r${SAMPLE_RATE} -p${BLOCK_SIZE} -n2 -i${NUM_INPUTS} -o${NUM_OUTPUTS} -s &
sleep 5
echo "Now starting test..."
fi
pidof jackd
bin/ITAJackLoopback
......@@ -2,7 +2,7 @@
#include <iostream>
#include <string>
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <ITAPortaudioInterface.h>
static double dSampleRate = 44.1e3;
......
#include <ITADatasourceUtils.h>
#include <ITADataSourceUtils.h>
#include <ITAPortaudioInterface.h>
#include <ITAStreamProbe.h>
#include <ITAFileDataSource.h>
......
#include <iostream>
#include <ITADatasource.h>
#include <ITAFileDatasource.h>
#include <ITAFileDatasink.h>
#include <ITAException.h>
#include <ITADatasourceUtils.h>