Implementation of the portaudio playback for Linux

This commit is contained in:
Edouard Dupin 2012-06-28 10:08:07 +02:00
parent e188f085f6
commit ed5c0cb5c5
8 changed files with 196 additions and 187 deletions

View File

@ -11,12 +11,12 @@ LOCAL_VERSION_TAG_SHORT=$(shell cd $(LOCAL_PATH) ; git describe --tags --abbrev=
$(info $(LOCAL_MODULE) version TAG : $(LOCAL_VERSION_TAG))
# name of the dependency
LOCAL_STATIC_LIBRARIES := etk libfreetype tinyxml libzip libpng agg parsersvg lua
LOCAL_STATIC_LIBRARIES := etk libfreetype tinyxml libzip libpng agg parsersvg lua portaudio
LOCAL_C_INCLUDES := -I$(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_LDLIBS := -lGL -lGLU -lz -lX11 -lasound
LOCAL_EXPORT_LDLIBS := -lGL -lGLU -lz -lX11
ifeq ($(DEBUG),1)
LOCAL_CFLAGS := -D__PLATFORM__Linux \
@ -46,11 +46,11 @@ include $(LOCAL_PATH)/file.mk
LOCAL_SRC_FILES := \
ewol/base/guiX11.cpp \
ewol/Audio/audioAlsa.cpp \
ewol/Audio/interfacePortAudio.cpp \
$(FILE_LIST)
# Ewol Test Software :
LOCAL_LDLIBS := -lGL -lGLU -lz -lX11 -lasound
LOCAL_LDLIBS := -lGL -lGLU -lz -lX11
include $(BUILD_STATIC_LIBRARY)

View File

@ -39,7 +39,7 @@ static float effectsVolume = -5000;
static bool isInit = false;
#ifdef __PLATFORM__Linux
# include <ewol/Audio/audioAlsa.h>
# include <ewol/Audio/interfacePortAudio.h>
#endif
void ewol::audio::Init(void)
@ -54,7 +54,7 @@ void ewol::audio::Init(void)
musicFadingTime = 100;
isInit = true;
#ifdef __PLATFORM__Linux
ewol::audioAlsa::Init();
ewol::portAudio::Init();
#endif
}
@ -66,7 +66,7 @@ void ewol::audio::UnInit(void)
return;
}
#ifdef __PLATFORM__Linux
ewol::audioAlsa::UnInit();
ewol::portAudio::UnInit();
#endif
musicMute = true;
musicVolume = -5000;
@ -83,20 +83,10 @@ void ewol::audio::GetData(int16_t * bufferInterlace, int32_t nbSample, int32_t n
EWOL_ERROR("TODO : Support the signal mono or more tha stereo ...");
return;
}
// reset the current buffer
memset(bufferInterlace, 0, nbSample*sizeof(int16_t)*nbChannels);
static int32_t maxValue = 0;
maxValue +=10;
if (maxValue > 16000) {
maxValue = 0;
}
for (int iii = 0; iii<nbSample ; iii++) {
bufferInterlace[iii*2] = (float)maxValue * sin(angle/180.0 * M_PI);
bufferInterlace[iii*2+1] = bufferInterlace[iii*2];
angle+=0.9;
if (angle>=360) {
angle -= 360.0;
}
}
// get background music :
ewol::audio::music::GetData(bufferInterlace, nbSample, nbChannels);
// add effects :
ewol::audio::effects::GetData(bufferInterlace, nbSample, nbChannels);
}
@ -207,6 +197,10 @@ void ewol::audio::music::MuteSet(bool newMute)
}
void ewol::audio::music::GetData(int16_t * bufferInterlace, int32_t nbSample, int32_t nbChannels)
{
}
@ -220,7 +214,7 @@ class EffectsLoaded {
{
m_file = file;
m_requestedTime = 1;
m_nbSamples = 12000; // 0.25s
m_nbSamples = 6000; // 0.25s
m_data = (int16_t*)malloc(sizeof(int16_t)*m_nbSamples);
if (NULL == m_data) {
EWOL_CRITICAL("MEM allocation error ...");

View File

@ -55,6 +55,7 @@ namespace ewol {
void VolumeSet(float newVolume);
bool MuteGet(void);
void MuteSet(bool newMute);
void GetData(int16_t * bufferInterlace, int32_t nbSample, int32_t nbChannels);
};
// note effect is loaded in memory (then don't create long effect) and unload only when requested

View File

@ -1,160 +0,0 @@
/**
*******************************************************************************
* @file ewol/Audio/audioAlsa.cpp
* @brief Alsa ewol Audio interface (Sources)
* @author Edouard DUPIN
* @date 26/06/2012
* @par Project
* ewol
*
* @par Copyright
* Copyright 2011 Edouard DUPIN, all right reserved
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY.
*
* Licence summary :
* You can modify and redistribute the sources code and binaries.
* You can send me the bug-fix
*
* Term of the licence in in the file licence.txt.
*
*******************************************************************************
*/
#include <etk/Types.h>
#include <etk/UString.h>
#include <ewol/Debug.h>
#include <ewol/Audio/audioAlsa.h>
#include <ewol/Audio/audio.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <poll.h>
#include <math.h>
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
static pthread_t audioHandleThread;
static pthread_attr_t audioHandleThreadAttr;
static bool g_stopRequested=false;
static void* audioThread(void* param)
{
EWOL_DEBUG("==> Init audioAlsa Thread (START)");
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
int32_t frequency = 48000;
int32_t nbChan = 2;
int32_t frameSize = 32;
// Open PCM device name "default" to play audio on it ...
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
EWOL_ERROR("AUDIO : unable to open pcm device: " << (char*)snd_strerror(rc));
// stop the thread ...
pthread_exit(NULL);
return NULL;
}
// Allocate a hardware parameters object.
snd_pcm_hw_params_alloca(&params);
// Fill it in with default values.
snd_pcm_hw_params_any(handle, params);
// Set the desired hardware parameters.
// Interleaved mode
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
// Signed 16-bit little-endian format
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
// number of channel : 2 (stereo) ==> might never need more for simple game
snd_pcm_hw_params_set_channels(handle, params, nbChan);
// Frequency : 48000 Hz
val = frequency;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
// Set pushing data frameRate : 32 frames. ==> might be a little small ???
frames = frameSize;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
// Write the parameters to the driver ==> and hope it work corectly ...
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
EWOL_ERROR("AUDIO : unable to set hw parameters: " << (char*)snd_strerror(rc));
// stop the thread ...
pthread_exit(NULL);
return NULL;
}
EWOL_DEBUG("AUDIO : Audio Properties : nbChan=" << nbChan << ", freg=" << frequency << "Hz, frameRate=" << frameSize);
// Use a buffer large enough to hold one period
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * sizeof(int16_t) * nbChan;
buffer = (char *) malloc(size);
EWOL_DEBUG("AUDIO : Buffer size= " << size);
// request the period time to display it ...
snd_pcm_hw_params_get_period_time(params, &val, &dir);
EWOL_DEBUG("AUDIO : periode time = " << (float)((float)val/1000.0) << "ms" );
//FILE * fileSYS = fopen("/home/edupin/export.raw", "w");
EWOL_DEBUG("==> Init audioAlsa Thread (END)");
while (g_stopRequested==false) {
//request data from the standard system generation ...
ewol::audio::GetData((int16_t*)buffer, frames, nbChan);
//fwrite(buffer,2,frames*nbChan, fileSYS);
// write it to ALSA system
rc = snd_pcm_writei(handle, buffer, frames);
if (rc == -EPIPE) {
EWOL_ERROR("underrun occurred");
// restart the Audio system
snd_pcm_prepare(handle);
} else if (rc < 0) {
EWOL_ERROR("error from writei: " << (char*)snd_strerror(rc));
} else if (rc != (int)frames) {
EWOL_ERROR("short write, write " << rc << " frames");
}
}
EWOL_DEBUG("==> Un-Init audioAlsa Thread (START)");
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
EWOL_DEBUG("==> Un-Init audioAlsa Thread (END)");
pthread_exit(NULL);
return NULL;
}
void ewol::audioAlsa::Init(void)
{
EWOL_DEBUG("Create Audio Thread...");
g_stopRequested=false;
// create th thread ...
pthread_setname_np(audioHandleThread, "ewol_audio_thread");
pthread_create(&audioHandleThread, &audioHandleThreadAttr, audioThread, NULL);
pthread_attr_init(&audioHandleThreadAttr);
pthread_attr_setdetachstate(&audioHandleThreadAttr, PTHREAD_CREATE_JOINABLE);
EWOL_DEBUG("Create Audio Thread ... might have start");
}
void ewol::audioAlsa::UnInit(void)
{
g_stopRequested=true;
// destroy the thread ...
EWOL_DEBUG("Wait end of the thread ...");
// Wait end of the thread
pthread_join(audioHandleThread, NULL);
EWOL_DEBUG("Create Audio Thread ... might have stop");
}

View File

@ -0,0 +1,123 @@
/**
*******************************************************************************
* @file ewol/Audio/intefacePortAudio.cpp
* @brief poratudio ewol Audio interface (Sources)
* @author Edouard DUPIN
* @date 28/06/2012
* @par Project
* ewol
*
* @par Copyright
* Copyright 2011 Edouard DUPIN, all right reserved
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY.
*
* Licence summary :
* You can modify and redistribute the sources code and binaries.
* You can send me the bug-fix
*
* Term of the licence in in the file licence.txt.
*
*******************************************************************************
*/
#include <etk/Types.h>
#include <etk/UString.h>
#include <ewol/Debug.h>
#include <ewol/Audio/interfacePortAudio.h>
#include <ewol/Audio/audio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <poll.h>
#include <math.h>
extern "C" {
#include <portaudio/portaudio.h>
}
typedef struct
{
int32_t sampleRate;
int32_t nbChanelsInput;
int32_t nbChanelsOutput;
int32_t frameSize;
} userOutputData;
userOutputData data;
PaStream *stream;
/* This routine will be called by the PortAudio engine when audio is needed.
It may called at interrupt level on some machines so don't do anything
that could mess up the system like calling malloc() or free().
*/
static int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
/* Cast data passed through stream to our structure. */
userOutputData *data = (userOutputData*)userData;
// no use of the input buffer ... (mightt be NULL)
(void) inputBuffer;
ewol::audio::GetData((int16_t*)outputBuffer, framesPerBuffer, data->nbChanelsOutput);
return 0;
}
#define SAMPLE_RATE (44100)
void ewol::portAudio::Init(void)
{
PaError err;
EWOL_DEBUG("Create Audio Thread...");
err = Pa_Initialize();
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
data.sampleRate = 48000;
data.nbChanelsInput = 0;
data.nbChanelsOutput = 2;
data.frameSize = 256;
/* Open an audio I/O stream. */
err = Pa_OpenDefaultStream( &stream, data.nbChanelsInput, data.nbChanelsOutput,
paInt16, data.sampleRate, data.frameSize,
patestCallback, &data );
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
err = Pa_StartStream( stream );
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
EWOL_DEBUG("Create Audio Thread ... might have start");
}
void ewol::portAudio::UnInit(void)
{
PaError err;
// destroy the thread ...
EWOL_DEBUG("Wait end of the thread ...");
err = Pa_StopStream( stream );
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
err = Pa_CloseStream( stream );
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
err = Pa_Terminate();
if( err != paNoError ) {
EWOL_ERROR("PortAudio error: " << (char*)Pa_GetErrorText(err) );
return;
}
EWOL_DEBUG("Create Audio Thread ... might have stop");
}

View File

@ -1,9 +1,9 @@
/**
*******************************************************************************
* @file ewol/Audio/audioAlsa.h
* @brief Alsa ewol Audio interface (header)
* @file ewol/Audio/intefacePortAudio.h
* @brief poratudio ewol Audio interface (header)
* @author Edouard DUPIN
* @date 26/06/2012
* @date 28/06/2012
* @par Project
* ewol
*
@ -22,13 +22,13 @@
*******************************************************************************
*/
#ifndef __EWOL_ALSA_AUDIO_H__
#define __EWOL_ALSA_AUDIO_H__
#ifndef __EWOL_PORT_AUDIO_H__
#define __EWOL_PORT_AUDIO_H__
#include <etk/Types.h>
namespace ewol {
namespace audioAlsa {
namespace portAudio {
void Init(void);
void UnInit(void);
};

View File

@ -0,0 +1,37 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# name of the librairy
LOCAL_MODULE := portaudio
# name of the dependency
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES := -I$(LOCAL_PATH) \
-I$(LOCAL_PATH)/portaudio/ \
-I$(LOCAL_PATH)/portaudio/common \
-I$(LOCAL_PATH)/portaudio/os/unix
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_LDLIBS := -lasound
ifeq ($(DEBUG),1)
LOCAL_CFLAGS := -D__PLATFORM__Linux \
-DPORTAUDIO_DEBUG_LEVEL=3 \
-DPA_USE_ALSA \
-DPORTAUDIO_VERSION_TAG_NAME="\"v19-debug\""
else
LOCAL_CFLAGS := -D__PLATFORM__Linux \
-DPORTAUDIO_DEBUG_LEVEL=3 \
-DPA_USE_ALSA \
-DPORTAUDIO_VERSION_TAG_NAME="\"v19-release\""
endif
# load the common sources file of the platform
include $(LOCAL_PATH)/file.mk
LOCAL_SRC_FILES := $(FILE_LIST)
LOCAL_LDLIBS := -lasound
include $(BUILD_STATIC_LIBRARY)

View File

@ -0,0 +1,14 @@
FILE_LIST = portaudio/hostapi/alsa/pa_linux_alsa.c \
portaudio/os/unix/pa_unix_hostapis.c \
portaudio/os/unix/pa_unix_util.c \
portaudio/common/pa_ringbuffer.c \
portaudio/common/pa_process.c \
portaudio/common/pa_dither.c \
portaudio/common/pa_front.c \
portaudio/common/pa_converters.c \
portaudio/common/pa_cpuload.c \
portaudio/common/pa_allocation.c \
portaudio/common/pa_debugprint.c \
portaudio/common/pa_stream.c \
portaudio/common/pa_trace.c