forked from mia/Aegisub
Supplant the portaudio player with the portaudio2 player. This still doesn't handle some of the issues that happen on linux, that will be fixed in a later commit, updates #876.
Originally committed to SVN as r3043.
This commit is contained in:
parent
17f1ccac06
commit
1b9f38747b
8 changed files with 168 additions and 571 deletions
|
@ -21,8 +21,7 @@ m4_define([libswscale_required_version], [0.7.1]) # (r18642)
|
||||||
|
|
||||||
m4_define([lua_auto3_required_version], [5.0])
|
m4_define([lua_auto3_required_version], [5.0])
|
||||||
m4_define([lua_auto4_required_version], [5.1])
|
m4_define([lua_auto4_required_version], [5.1])
|
||||||
m4_define([portaudio_required_version], [1])
|
m4_define([portaudio_required_version], [19])
|
||||||
m4_define([portaudio2_required_version], [19])
|
|
||||||
m4_define([pulseaudio_required_version], [0.5])
|
m4_define([pulseaudio_required_version], [0.5])
|
||||||
|
|
||||||
m4_define([fontconfig_required_version], [2.4])
|
m4_define([fontconfig_required_version], [2.4])
|
||||||
|
@ -450,74 +449,18 @@ AM_CONDITIONAL([HAVE_ALSA], [test "$with_alsa" != "no"])
|
||||||
AC_SUBST(ALSA_LDFLAGS)
|
AC_SUBST(ALSA_LDFLAGS)
|
||||||
|
|
||||||
|
|
||||||
###################
|
|
||||||
## PortAudio2 (v19)
|
|
||||||
###################
|
|
||||||
|
|
||||||
AC_ARG_WITH(portaudio2,[ --without-portaudio2 build without PortAudio v19 audio provider.
|
|
||||||
(default: auto)], pulseaudio2_disabled="(disabled)")
|
|
||||||
if test "$with_portaudio2" != "no"; then
|
|
||||||
PKG_CHECK_MODULES(PORTAUDIO2, portaudio-2.0 >= portaudio2_required_version, [with_portaudio2="yes"], [with_portaudio2="no"])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$with_portaudio2" != "no"; then
|
|
||||||
AC_AGI_COMPILE([PortAudio2], [portaudio2], [$PORTAUDIO2_CFLAGS], [$PORTAUDIO2_LIBS],[
|
|
||||||
#include <portaudio.h>
|
|
||||||
int main(void) {
|
|
||||||
PaError err = Pa_Initialize();
|
|
||||||
if (err != paNoError) return 1;
|
|
||||||
return 0;
|
|
||||||
} ])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$agi_cv_with_portaudio2" = "no" && test "$with_portaudio2" = "yes"; then
|
|
||||||
AC_MSG_WARN([PortAudio2 detected, but it doesn't work...])
|
|
||||||
with_portaudio2="no"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$agi_cv_with_portaudio2" = "yes" && test "$with_portaudio2" = "yes"; then
|
|
||||||
AC_DEFINE(WITH_PORTAUDIO2, 1, [Enable PortAudio v19 support])
|
|
||||||
found_audio_player="yes"
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL([HAVE_PORTAUDIO2], [test "$with_portaudio2" != "no"])
|
|
||||||
|
|
||||||
|
|
||||||
############
|
############
|
||||||
## PortAudio
|
## PortAudio
|
||||||
############
|
############
|
||||||
AC_ARG_WITH(portaudio,[ --without-portaudio build without PortAudio audio provider.
|
|
||||||
(default: auto)], portaudio_disabled="(disabled)")
|
|
||||||
|
|
||||||
if test "$with_portaudio2" = "yes"; then
|
|
||||||
with_portaudio="no"
|
|
||||||
portaudio_disabled="(disabled by v19)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$PORTAUDIO_LDFLAGS"; then
|
|
||||||
PORTAUDIO_LDFLAGS="$LDFLAGS -lportaudio"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$PORTAUDIO_CFLAGS"; then
|
|
||||||
PORTAUDIO_CFLAGS="$PTHREAD_CFLAGS $PTHREAD_LIBS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
AC_ARG_WITH(portaudio,[ --without-portaudio build without PortAudio v19 audio provider.
|
||||||
|
(default: auto)], pulseaudio_disabled="(disabled)")
|
||||||
if test "$with_portaudio" != "no"; then
|
if test "$with_portaudio" != "no"; then
|
||||||
aegisub_save_CPPFLAGS="$CPPFLAGS"
|
PKG_CHECK_MODULES(PORTAUDIO, portaudio-2.0 >= portaudio_required_version, [with_portaudio="yes"], [with_portaudio="no"])
|
||||||
aegisub_save_LDFLAGS="$LDFLAGS"
|
|
||||||
CPPFLAGS="$PORTAUDIO_CFLAGS"
|
|
||||||
LDFLAGS="$LDFLAGS $PORTAUDIO_LDFLAGS"
|
|
||||||
AC_CHECK_LIB([portaudio], [Pa_Initialize], [with_portaudio="yes"], [with_portaudio="no"])
|
|
||||||
AC_CHECK_LIB([portaudio], [Pa_GetStreamTime], [
|
|
||||||
AC_DEFINE(HAVE_PA_GETSTREAMTIME, 1, [Define to 1 if Pa_GetStreamTime is available in PortAudio])
|
|
||||||
], [])
|
|
||||||
CPPFLAGS="$aegisub_save_CPPFLAGS"
|
|
||||||
LDFLAGS="$aegisub_save_LDFLAGS"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$with_portaudio" != "no"; then
|
if test "$with_portaudio" != "no"; then
|
||||||
AC_AGI_COMPILE([PortAudio], [portaudio], [$PORTAUDIO_CFLAGS], [$PORTAUDIO_LDFLAGS],[
|
AC_AGI_COMPILE([PortAudio], [portaudio], [$PORTAUDIO_CFLAGS], [$PORTAUDIO_LIBS],[
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
int main(void) {
|
int main(void) {
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
|
@ -531,14 +474,12 @@ if test "$agi_cv_with_portaudio" = "no" && test "$with_portaudio" = "yes"; then
|
||||||
with_portaudio="no"
|
with_portaudio="no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$with_portaudio" = "yes" && test "$agi_cv_with_portaudio" = "yes"; then
|
if test "$agi_cv_with_portaudio" = "yes" && test "$with_portaudio" = "yes"; then
|
||||||
|
AC_DEFINE(WITH_PORTAUDIO, 1, [Enable PortAudio v19 support])
|
||||||
found_audio_player="yes"
|
found_audio_player="yes"
|
||||||
AC_DEFINE(WITH_PORTAUDIO, 1, [Enable PortAudio Audio Provider])
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL([HAVE_PORTAUDIO], [test "$with_portaudio" != "no"])
|
AM_CONDITIONAL([HAVE_PORTAUDIO], [test "$with_portaudio" != "no"])
|
||||||
AC_SUBST(PORTAUDIO_LDFLAGS)
|
|
||||||
AC_SUBST(PORTAUDIO_CFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
#############
|
#############
|
||||||
|
@ -1420,7 +1361,6 @@ Audio Players
|
||||||
ALSA: $with_alsa $alsa_disabled
|
ALSA: $with_alsa $alsa_disabled
|
||||||
OpenAL: $with_openal $openal_disabled
|
OpenAL: $with_openal $openal_disabled
|
||||||
PortAudio: $with_portaudio $portaudio_disabled
|
PortAudio: $with_portaudio $portaudio_disabled
|
||||||
PortAudio2 (v19): $with_portaudio2 $portaudio2_disabled
|
|
||||||
PulseAudio: $with_pulseaudio $pulseaudio_disabled
|
PulseAudio: $with_pulseaudio $pulseaudio_disabled
|
||||||
|
|
||||||
A/V Support
|
A/V Support
|
||||||
|
|
|
@ -33,7 +33,7 @@ endif
|
||||||
if FOUND_AUDIO_PLAYER
|
if FOUND_AUDIO_PLAYER
|
||||||
noinst_LIBRARIES += libaudio_player.a
|
noinst_LIBRARIES += libaudio_player.a
|
||||||
libaudio_player_a_SOURCES = audio_player.cpp
|
libaudio_player_a_SOURCES = audio_player.cpp
|
||||||
libaudio_player_a_CPPFLAGS = @ALSA_CFLAGS@ @PORTAUDIO_CFLAGS@ @PORTAUDIO2_CFLAGS@ @LIBPULSE_CFLAGS@ @OPENAL_CFLAGS@
|
libaudio_player_a_CPPFLAGS = @ALSA_CFLAGS@ @PORTAUDIO_CFLAGS@ @LIBPULSE_CFLAGS@ @OPENAL_CFLAGS@
|
||||||
aegisub_2_1_LDADD += libaudio_player.a
|
aegisub_2_1_LDADD += libaudio_player.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -48,18 +48,10 @@ if HAVE_PORTAUDIO
|
||||||
noinst_LIBRARIES += libaudio_portaudio.a
|
noinst_LIBRARIES += libaudio_portaudio.a
|
||||||
libaudio_portaudio_a_SOURCES = audio_player_portaudio.cpp
|
libaudio_portaudio_a_SOURCES = audio_player_portaudio.cpp
|
||||||
libaudio_portaudio_a_CPPFLAGS = @PORTAUDIO_CFLAGS@
|
libaudio_portaudio_a_CPPFLAGS = @PORTAUDIO_CFLAGS@
|
||||||
aegisub_2_1_LDFLAGS += @PORTAUDIO_LDFLAGS@
|
aegisub_2_1_LDFLAGS += @PORTAUDIO_LIBS@
|
||||||
aegisub_2_1_LDADD += libaudio_portaudio.a
|
aegisub_2_1_LDADD += libaudio_portaudio.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if HAVE_PORTAUDIO2
|
|
||||||
noinst_LIBRARIES += libaudio_portaudio2.a
|
|
||||||
libaudio_portaudio2_a_SOURCES = audio_player_portaudio2.cpp
|
|
||||||
libaudio_portaudio2_a_CPPFLAGS = @PORTAUDIO2_CFLAGS@
|
|
||||||
aegisub_2_1_LDFLAGS += @PORTAUDIO2_LIBS@
|
|
||||||
aegisub_2_1_LDADD += libaudio_portaudio2.a
|
|
||||||
endif
|
|
||||||
|
|
||||||
if HAVE_PULSEAUDIO
|
if HAVE_PULSEAUDIO
|
||||||
noinst_LIBRARIES += libaudio_pulseaudio.a
|
noinst_LIBRARIES += libaudio_pulseaudio.a
|
||||||
libaudio_pulseaudio_a_SOURCES = audio_player_pulse.cpp
|
libaudio_pulseaudio_a_SOURCES = audio_player_pulse.cpp
|
||||||
|
@ -193,7 +185,6 @@ EXTRA_aegisub_2_1_SOURCES = \
|
||||||
audio_player_dsound.cpp \
|
audio_player_dsound.cpp \
|
||||||
audio_player_dsound2.cpp \
|
audio_player_dsound2.cpp \
|
||||||
audio_player_portaudio.cpp \
|
audio_player_portaudio.cpp \
|
||||||
audio_player_portaudio2.cpp \
|
|
||||||
audio_player_pulse.cpp \
|
audio_player_pulse.cpp \
|
||||||
audio_provider_avs.cpp \
|
audio_provider_avs.cpp \
|
||||||
audio_provider_lavc.cpp \
|
audio_provider_lavc.cpp \
|
||||||
|
|
|
@ -54,9 +54,6 @@
|
||||||
#ifdef WITH_PORTAUDIO
|
#ifdef WITH_PORTAUDIO
|
||||||
#include "audio_player_portaudio.h"
|
#include "audio_player_portaudio.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_PORTAUDIO2
|
|
||||||
#include "audio_player_portaudio2.h"
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_PULSEAUDIO
|
#ifdef WITH_PULSEAUDIO
|
||||||
#include "audio_player_pulse.h"
|
#include "audio_player_pulse.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -172,9 +169,6 @@ void AudioPlayerFactoryManager::RegisterProviders() {
|
||||||
#ifdef WITH_PORTAUDIO
|
#ifdef WITH_PORTAUDIO
|
||||||
RegisterFactory(new PortAudioPlayerFactory(),_T("PortAudio"));
|
RegisterFactory(new PortAudioPlayerFactory(),_T("PortAudio"));
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_PORTAUDIO2
|
|
||||||
RegisterFactory(new PortAudioPlayerFactory(),_T("PortAudio2"));
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_PULSEAUDIO
|
#ifdef WITH_PULSEAUDIO
|
||||||
RegisterFactory(new PulseAudioPlayerFactory(),_T("PulseAudio"));
|
RegisterFactory(new PulseAudioPlayerFactory(),_T("PulseAudio"));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,20 +43,11 @@
|
||||||
// Headers
|
// Headers
|
||||||
#include "audio_player_portaudio.h"
|
#include "audio_player_portaudio.h"
|
||||||
#include "audio_provider_manager.h"
|
#include "audio_provider_manager.h"
|
||||||
|
#include "options.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#ifdef HAVE_PA_GETSTREAMTIME
|
// Uncomment to enable debug features.
|
||||||
#define Pa_StreamTime Pa_GetStreamTime /* PortAudio v19 */
|
//#define PORTAUDIO_DEBUG
|
||||||
#define PaTimestamp PaTime
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Library
|
|
||||||
#if __VISUALC__ >= 1200
|
|
||||||
#pragma comment(lib,"portaudio.lib")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// Reference counter
|
// Reference counter
|
||||||
|
@ -69,11 +60,13 @@ PortAudioPlayer::PortAudioPlayer() {
|
||||||
// Initialize portaudio
|
// Initialize portaudio
|
||||||
if (!pa_refcount) {
|
if (!pa_refcount) {
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
|
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
static wchar_t errormsg[2048];
|
static wchar_t errormsg[2048];
|
||||||
swprintf(errormsg, 2048, L"Failed opening PortAudio: %s", Pa_GetErrorText(err));
|
swprintf(errormsg, 2048, L"Failed opening PortAudio: %s", Pa_GetErrorText(err));
|
||||||
throw (const wchar_t *)errormsg;
|
throw (const wchar_t *)errormsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_refcount++;
|
pa_refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,82 +85,100 @@ PortAudioPlayer::~PortAudioPlayer() {
|
||||||
if (!--pa_refcount) Pa_Terminate();
|
if (!--pa_refcount) Pa_Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// PortAudio callback
|
|
||||||
#ifndef HAVE_PA_GETSTREAMTIME
|
|
||||||
int PortAudioPlayer::paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) {
|
|
||||||
#else
|
|
||||||
int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer,
|
|
||||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timei,
|
|
||||||
PaStreamCallbackFlags flags, void *userData) {
|
|
||||||
#endif
|
|
||||||
// Get provider
|
|
||||||
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
|
||||||
AudioProvider *provider = player->GetProvider();
|
|
||||||
int end = 0;
|
|
||||||
|
|
||||||
// Calculate how much left
|
///////////////
|
||||||
int64_t lenAvailable = player->endPos - player->playPos;
|
// Open stream
|
||||||
uint64_t avail = 0;
|
void PortAudioPlayer::OpenStream() {
|
||||||
if (lenAvailable > 0) {
|
// Open stream
|
||||||
avail = lenAvailable;
|
PaStreamParameters pa_output_p;
|
||||||
if (avail > framesPerBuffer) {
|
|
||||||
lenAvailable = framesPerBuffer;
|
int pa_config_default = Options.AsInt(_T("Audio PortAudio Device"));
|
||||||
avail = lenAvailable;
|
PaDeviceIndex pa_device;
|
||||||
|
|
||||||
|
if (pa_config_default < 0) {
|
||||||
|
pa_device = Pa_GetDefaultOutputDevice();
|
||||||
|
wxLogDebug(_T("PortAudioPlayer::OpenStream Using Default Output Device: %d"), pa_device);
|
||||||
|
} else {
|
||||||
|
pa_device = pa_config_default;
|
||||||
|
wxLogDebug(_T("PortAudioPlayer::OpenStream Using Config Device: %d"), pa_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_output_p.device = pa_device;
|
||||||
|
pa_output_p.channelCount = provider->GetChannels();
|
||||||
|
pa_output_p.sampleFormat = paInt16;
|
||||||
|
pa_output_p.suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultLowOutputLatency;
|
||||||
|
pa_output_p.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
|
wxLogDebug(_T("PortAudioPlayer::OpenStream Output channels: %d, Latency: %f Sample Rate: %ld\n"),
|
||||||
|
pa_output_p.channelCount, pa_output_p.suggestedLatency, pa_output_p.sampleFormat);
|
||||||
|
|
||||||
|
PaError err = Pa_OpenStream(&stream, NULL, &pa_output_p, provider->GetSampleRate(), 256, paPrimeOutputBuffersUsingStreamCallback, paCallback, this);
|
||||||
|
|
||||||
|
if (err != paNoError) {
|
||||||
|
|
||||||
|
const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo();
|
||||||
|
if (pa_err->errorCode != 0) {
|
||||||
|
wxLogDebug(_T("PortAudioPlayer::OpenStream HostError: API: %d, %s (%ld)\n"), pa_err->hostApiType, pa_err->errorText, pa_err->errorCode);
|
||||||
}
|
}
|
||||||
|
throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal));
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
lenAvailable = 0;
|
|
||||||
avail = 0;
|
|
||||||
|
///////////////
|
||||||
|
// Close stream
|
||||||
|
void PortAudioPlayer::CloseStream() {
|
||||||
|
try {
|
||||||
|
Stop(false);
|
||||||
|
Pa_CloseStream(stream);
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the callback has finished.
|
||||||
|
void PortAudioPlayer::paStreamFinishedCallback(void *userData) {
|
||||||
|
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
||||||
|
|
||||||
|
player->playing = false;
|
||||||
|
|
||||||
|
if (player->displayTimer) {
|
||||||
|
player->displayTimer->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play something
|
wxLogDebug(_T("PortAudioPlayer::paStreamFinishedCallback Stopping stream."));
|
||||||
if (lenAvailable > 0) {
|
|
||||||
provider->GetAudio(outputBuffer,player->playPos,lenAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set volume
|
|
||||||
short *output = (short*) outputBuffer;
|
|
||||||
for (unsigned int i=0;i<avail;i++) output[i] = MID(-(1<<15),int(output[i] * player->GetVolume()),(1<<15)-1);
|
|
||||||
|
|
||||||
// Fill rest with blank
|
|
||||||
for (unsigned int i=avail;i<framesPerBuffer;i++) output[i]=0;
|
|
||||||
|
|
||||||
// Set play position (and real one)
|
|
||||||
player->playPos += framesPerBuffer;
|
|
||||||
#ifndef __APPLE__
|
|
||||||
player->realPlayPos = (int64_t)(Pa_StreamTime(player->stream) - player->paStart) + player->startPos;
|
|
||||||
#else
|
|
||||||
// AudioDeviceGetCurrentTime(), used by Pa_StreamTime() on OS X, is buggered, so use playPos for now
|
|
||||||
player->realPlayPos = player->playPos;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Cap to start if lower
|
|
||||||
return end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////
|
////////
|
||||||
// Play
|
// Play
|
||||||
void PortAudioPlayer::Play(int64_t start,int64_t count) {
|
void PortAudioPlayer::Play(int64_t start,int64_t count) {
|
||||||
|
PaError err;
|
||||||
|
|
||||||
// Stop if it's already playing
|
// Stop if it's already playing
|
||||||
wxMutexLocker locker(PAMutex);
|
wxMutexLocker locker(PAMutex);
|
||||||
|
|
||||||
// Set values
|
// Set values
|
||||||
endPos = start + count;
|
endPos = start + count;
|
||||||
playPos = start;
|
playPos = start;
|
||||||
realPlayPos = start;
|
|
||||||
startPos = start;
|
startPos = start;
|
||||||
|
|
||||||
// Start playing
|
// Start playing
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
PaError err = Pa_StartStream(stream);
|
|
||||||
|
err = Pa_SetStreamFinishedCallback(stream, paStreamFinishedCallback);
|
||||||
|
|
||||||
|
if (err != paNoError) {
|
||||||
|
wxLogDebug(_T("PortAudioPlayer::Play Could not set FinishedCallback\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Pa_StartStream(stream);
|
||||||
|
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
playing = true;
|
playing = true;
|
||||||
paStart = Pa_StreamTime(stream);
|
paStart = Pa_GetStreamTime(stream);
|
||||||
|
|
||||||
// Update timer
|
// Update timer
|
||||||
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
||||||
|
@ -191,30 +202,82 @@ void PortAudioPlayer::Stop(bool timerToo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
//////////////////////
|
||||||
// Open stream
|
/// PortAudio callback
|
||||||
void PortAudioPlayer::OpenStream() {
|
int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
|
||||||
// Open stream
|
|
||||||
PaError err = Pa_OpenDefaultStream(&stream,0,provider->GetChannels(),paInt16,provider->GetSampleRate(),256,
|
// Get provider
|
||||||
#ifndef HAVE_PA_GETSTREAMTIME
|
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
||||||
16, /* Pa v19 doesn't have a numberOfBuffers parameter */
|
AudioProvider *provider = player->GetProvider();
|
||||||
|
|
||||||
|
#ifdef PORTAUDIO_DEBUG
|
||||||
|
printf("paCallBack: playPos: %lld startPos: %lld paStart: %f Pa_GetStreamTime: %f AdcTime: %f DacTime: %f framesPerBuffer: %lu CPU: %f\n",
|
||||||
|
player->playPos, player->startPos, player->paStart, Pa_GetStreamTime(player->stream),
|
||||||
|
timeInfo->inputBufferAdcTime, timeInfo->outputBufferDacTime, framesPerBuffer, Pa_GetStreamCpuLoad(player->stream));
|
||||||
#endif
|
#endif
|
||||||
paCallback,this);
|
|
||||||
|
|
||||||
if (err != paNoError) {
|
// Calculate how much left
|
||||||
throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal));
|
int64_t lenAvailable = (player->endPos - player->playPos) > 0 ? framesPerBuffer : 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Play something
|
||||||
|
if (lenAvailable > 0) {
|
||||||
|
provider->GetAudioWithVolume(outputBuffer, player->playPos, lenAvailable, player->GetVolume());
|
||||||
|
|
||||||
|
// Set play position
|
||||||
|
player->playPos += framesPerBuffer;
|
||||||
|
|
||||||
|
// Continue as normal
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abort stream and stop the callback.
|
||||||
|
return paAbort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
/// Get current stream position.
|
||||||
|
int64_t PortAudioPlayer::GetCurrentPosition()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!playing) return 0;
|
||||||
|
|
||||||
|
const PaStreamInfo* streamInfo = Pa_GetStreamInfo(stream);
|
||||||
|
|
||||||
|
#ifdef PORTAUDIO_DEBUG
|
||||||
|
PaTime pa_getstream = Pa_GetStreamTime(stream);
|
||||||
|
int64_t real = ((pa_getstream - paStart) * streamInfo->sampleRate) + startPos;
|
||||||
|
printf("GetCurrentPosition: Pa_GetStreamTime: %f startPos: %lld playPos: %lld paStart: %f real: %lld diff: %f\n",
|
||||||
|
pa_getstream, startPos, playPos, paStart, real, pa_getstream-paStart);
|
||||||
|
|
||||||
|
return real;
|
||||||
|
#else
|
||||||
|
return ((Pa_GetStreamTime(stream) - paStart) * streamInfo->sampleRate) + startPos;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Close stream
|
/// Return a list of available output devices.
|
||||||
void PortAudioPlayer::CloseStream() {
|
/// @param Setting from config file.
|
||||||
try {
|
wxArrayString PortAudioPlayer::GetOutputDevices(wxString favorite) {
|
||||||
Stop(false);
|
wxArrayString list;
|
||||||
Pa_CloseStream(stream);
|
int devices = Pa_GetDeviceCount();
|
||||||
} catch (...) {}
|
int i;
|
||||||
}
|
|
||||||
|
|
||||||
|
if (devices < 0) {
|
||||||
|
// some error here
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<devices; i++) {
|
||||||
|
const PaDeviceInfo *dev_info = Pa_GetDeviceInfo(i);
|
||||||
|
wxString name(dev_info->name, wxConvUTF8);
|
||||||
|
list.Insert(name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // WITH_PORTAUDIO
|
#endif // WITH_PORTAUDIO
|
||||||
|
|
|
@ -47,6 +47,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// Portaudio player
|
// Portaudio player
|
||||||
class PortAudioPlayer : public AudioPlayer {
|
class PortAudioPlayer : public AudioPlayer {
|
||||||
|
@ -62,17 +63,19 @@ private:
|
||||||
volatile int64_t startPos;
|
volatile int64_t startPos;
|
||||||
volatile int64_t endPos;
|
volatile int64_t endPos;
|
||||||
void *stream;
|
void *stream;
|
||||||
PaTimestamp paStart;
|
PaTime paStart;
|
||||||
volatile int64_t realPlayPos;
|
|
||||||
|
|
||||||
#ifndef HAVE_PA_GETSTREAMTIME
|
static int paCallback(
|
||||||
static int paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData);
|
const void *inputBuffer,
|
||||||
#else
|
void *outputBuffer,
|
||||||
static int paCallback(const void *inputBuffer, void *outputBuffer,
|
|
||||||
unsigned long framesPerBuffer,
|
unsigned long framesPerBuffer,
|
||||||
const PaStreamCallbackTimeInfo *timei,
|
const PaStreamCallbackTimeInfo*
|
||||||
PaStreamCallbackFlags flags, void *userData);
|
timeInfo,
|
||||||
#endif
|
PaStreamCallbackFlags
|
||||||
|
statusFlags,
|
||||||
|
void *userData);
|
||||||
|
|
||||||
|
static void paStreamFinishedCallback(void *userData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PortAudioPlayer();
|
PortAudioPlayer();
|
||||||
|
@ -87,13 +90,14 @@ public:
|
||||||
|
|
||||||
int64_t GetStartPosition() { return startPos; }
|
int64_t GetStartPosition() { return startPos; }
|
||||||
int64_t GetEndPosition() { return endPos; }
|
int64_t GetEndPosition() { return endPos; }
|
||||||
int64_t GetCurrentPosition() { return realPlayPos; }
|
int64_t GetCurrentPosition();
|
||||||
void SetEndPosition(int64_t pos) { endPos = pos; }
|
void SetEndPosition(int64_t pos) { endPos = pos; }
|
||||||
void SetCurrentPosition(int64_t pos) { playPos = pos; realPlayPos = pos; }
|
void SetCurrentPosition(int64_t pos) { playPos = pos; }
|
||||||
|
|
||||||
void SetVolume(double vol) { volume = vol; }
|
void SetVolume(double vol) { volume = vol; }
|
||||||
double GetVolume() { return volume; }
|
double GetVolume() { return volume; }
|
||||||
|
|
||||||
|
wxArrayString GetOutputDevices(wxString favorite);
|
||||||
wxMutex *GetMutex() { return &PAMutex; }
|
wxMutex *GetMutex() { return &PAMutex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,4 +109,4 @@ public:
|
||||||
AudioPlayer *CreatePlayer() { return new PortAudioPlayer(); }
|
AudioPlayer *CreatePlayer() { return new PortAudioPlayer(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif //ifdef WITH_PORTAUDIO
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
// Copyright (c) 2005-2007, Rodrigo Braz Monteiro
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
||||||
// may be used to endorse or promote products derived from this software
|
|
||||||
// without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// AEGISUB
|
|
||||||
//
|
|
||||||
// Website: http://aegisub.cellosoft.com
|
|
||||||
// Contact: mailto:zeratul@cellosoft.com
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#ifdef WITH_PORTAUDIO2
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "audio_player_portaudio2.h"
|
|
||||||
#include "audio_provider_manager.h"
|
|
||||||
#include "options.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Uncomment to enable debug features.
|
|
||||||
//#define PORTAUDIO2_DEBUG
|
|
||||||
|
|
||||||
/////////////////////
|
|
||||||
// Reference counter
|
|
||||||
int PortAudioPlayer::pa_refcount = 0;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
|
||||||
// Constructor
|
|
||||||
PortAudioPlayer::PortAudioPlayer() {
|
|
||||||
// Initialize portaudio
|
|
||||||
if (!pa_refcount) {
|
|
||||||
PaError err = Pa_Initialize();
|
|
||||||
|
|
||||||
if (err != paNoError) {
|
|
||||||
static wchar_t errormsg[2048];
|
|
||||||
swprintf(errormsg, 2048, L"Failed opening PortAudio: %s", Pa_GetErrorText(err));
|
|
||||||
throw (const wchar_t *)errormsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_refcount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables
|
|
||||||
playing = false;
|
|
||||||
stopping = false;
|
|
||||||
volume = 1.0f;
|
|
||||||
paStart = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////
|
|
||||||
// Destructor
|
|
||||||
PortAudioPlayer::~PortAudioPlayer() {
|
|
||||||
// Deinit portaudio
|
|
||||||
if (!--pa_refcount) Pa_Terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
|
||||||
// Open stream
|
|
||||||
void PortAudioPlayer::OpenStream() {
|
|
||||||
// Open stream
|
|
||||||
PaStreamParameters pa_output_p;
|
|
||||||
|
|
||||||
int pa_config_default = Options.AsInt(_T("Audio PortAudio Device"));
|
|
||||||
PaDeviceIndex pa_device;
|
|
||||||
|
|
||||||
if (pa_config_default < 0) {
|
|
||||||
pa_device = Pa_GetDefaultOutputDevice();
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::OpenStream Using Default Output Device: %d"), pa_device);
|
|
||||||
} else {
|
|
||||||
pa_device = pa_config_default;
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::OpenStream Using Config Device: %d"), pa_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_output_p.device = pa_device;
|
|
||||||
pa_output_p.channelCount = provider->GetChannels();
|
|
||||||
pa_output_p.sampleFormat = paInt16;
|
|
||||||
pa_output_p.suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultLowOutputLatency;
|
|
||||||
pa_output_p.hostApiSpecificStreamInfo = NULL;
|
|
||||||
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::OpenStream Output channels: %d, Latency: %f Sample Rate: %ld\n"),
|
|
||||||
pa_output_p.channelCount, pa_output_p.suggestedLatency, pa_output_p.sampleFormat);
|
|
||||||
|
|
||||||
PaError err = Pa_OpenStream(&stream, NULL, &pa_output_p, provider->GetSampleRate(), 256, paPrimeOutputBuffersUsingStreamCallback, paCallback, this);
|
|
||||||
|
|
||||||
if (err != paNoError) {
|
|
||||||
|
|
||||||
const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo();
|
|
||||||
if (pa_err->errorCode != 0) {
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::OpenStream HostError: API: %d, %s (%ld)\n"), pa_err->hostApiType, pa_err->errorText, pa_err->errorCode);
|
|
||||||
}
|
|
||||||
throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
|
||||||
// Close stream
|
|
||||||
void PortAudioPlayer::CloseStream() {
|
|
||||||
try {
|
|
||||||
Stop(false);
|
|
||||||
Pa_CloseStream(stream);
|
|
||||||
} catch (...) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the callback has finished.
|
|
||||||
void PortAudioPlayer::paStreamFinishedCallback(void *userData) {
|
|
||||||
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
|
||||||
|
|
||||||
player->playing = false;
|
|
||||||
|
|
||||||
if (player->displayTimer) {
|
|
||||||
player->displayTimer->Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::paStreamFinishedCallback Stopping stream."));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////
|
|
||||||
// Play
|
|
||||||
void PortAudioPlayer::Play(int64_t start,int64_t count) {
|
|
||||||
PaError err;
|
|
||||||
|
|
||||||
// Stop if it's already playing
|
|
||||||
wxMutexLocker locker(PAMutex);
|
|
||||||
|
|
||||||
// Set values
|
|
||||||
endPos = start + count;
|
|
||||||
playPos = start;
|
|
||||||
startPos = start;
|
|
||||||
|
|
||||||
// Start playing
|
|
||||||
if (!playing) {
|
|
||||||
|
|
||||||
err = Pa_SetStreamFinishedCallback(stream, paStreamFinishedCallback);
|
|
||||||
|
|
||||||
if (err != paNoError) {
|
|
||||||
wxLogDebug(_T("PortAudioPlayer::Play Could not set FinishedCallback\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Pa_StartStream(stream);
|
|
||||||
|
|
||||||
if (err != paNoError) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
playing = true;
|
|
||||||
paStart = Pa_GetStreamTime(stream);
|
|
||||||
|
|
||||||
// Update timer
|
|
||||||
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////
|
|
||||||
// Stop
|
|
||||||
void PortAudioPlayer::Stop(bool timerToo) {
|
|
||||||
//wxMutexLocker locker(PAMutex);
|
|
||||||
//softStop = false;
|
|
||||||
|
|
||||||
// Stop stream
|
|
||||||
playing = false;
|
|
||||||
Pa_StopStream (stream);
|
|
||||||
|
|
||||||
// Stop timer
|
|
||||||
if (timerToo && displayTimer) {
|
|
||||||
displayTimer->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
/// PortAudio callback
|
|
||||||
int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
|
|
||||||
|
|
||||||
// Get provider
|
|
||||||
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
|
||||||
AudioProvider *provider = player->GetProvider();
|
|
||||||
|
|
||||||
#ifdef PORTAUDIO2_DEBUG
|
|
||||||
printf("paCallBack: playPos: %lld startPos: %lld paStart: %f Pa_GetStreamTime: %f AdcTime: %f DacTime: %f framesPerBuffer: %lu CPU: %f\n",
|
|
||||||
player->playPos, player->startPos, player->paStart, Pa_GetStreamTime(player->stream),
|
|
||||||
timeInfo->inputBufferAdcTime, timeInfo->outputBufferDacTime, framesPerBuffer, Pa_GetStreamCpuLoad(player->stream));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calculate how much left
|
|
||||||
int64_t lenAvailable = (player->endPos - player->playPos) > 0 ? framesPerBuffer : 0;
|
|
||||||
|
|
||||||
|
|
||||||
// Play something
|
|
||||||
if (lenAvailable > 0) {
|
|
||||||
provider->GetAudioWithVolume(outputBuffer, player->playPos, lenAvailable, player->GetVolume());
|
|
||||||
|
|
||||||
// Set play position
|
|
||||||
player->playPos += framesPerBuffer;
|
|
||||||
|
|
||||||
// Continue as normal
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abort stream and stop the callback.
|
|
||||||
return paAbort;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
/// Get current stream position.
|
|
||||||
int64_t PortAudioPlayer::GetCurrentPosition()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!playing) return 0;
|
|
||||||
|
|
||||||
const PaStreamInfo* streamInfo = Pa_GetStreamInfo(stream);
|
|
||||||
|
|
||||||
#ifdef PORTAUDIO2_DEBUG
|
|
||||||
PaTime pa_getstream = Pa_GetStreamTime(stream);
|
|
||||||
int64_t real = ((pa_getstream - paStart) * streamInfo->sampleRate) + startPos;
|
|
||||||
printf("GetCurrentPosition: Pa_GetStreamTime: %f startPos: %lld playPos: %lld paStart: %f real: %lld diff: %f\n",
|
|
||||||
pa_getstream, startPos, playPos, paStart, real, pa_getstream-paStart);
|
|
||||||
|
|
||||||
return real;
|
|
||||||
#else
|
|
||||||
return ((Pa_GetStreamTime(stream) - paStart) * streamInfo->sampleRate) + startPos;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
|
||||||
/// Return a list of available output devices.
|
|
||||||
/// @param Setting from config file.
|
|
||||||
wxArrayString PortAudioPlayer::GetOutputDevices(wxString favorite) {
|
|
||||||
wxArrayString list;
|
|
||||||
int devices = Pa_GetDeviceCount();
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (devices < 0) {
|
|
||||||
// some error here
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0; i<devices; i++) {
|
|
||||||
const PaDeviceInfo *dev_info = Pa_GetDeviceInfo(i);
|
|
||||||
wxString name(dev_info->name, wxConvUTF8);
|
|
||||||
list.Insert(name, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WITH_PORTAUDIO2
|
|
|
@ -1,112 +0,0 @@
|
||||||
// Copyright (c) 2005-2007, Rodrigo Braz Monteiro
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
||||||
// may be used to endorse or promote products derived from this software
|
|
||||||
// without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// AEGISUB
|
|
||||||
//
|
|
||||||
// Website: http://aegisub.cellosoft.com
|
|
||||||
// Contact: mailto:zeratul@cellosoft.com
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_PORTAUDIO2
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "include/aegisub/audio_player.h"
|
|
||||||
#include "include/aegisub/audio_provider.h"
|
|
||||||
#include "utils.h"
|
|
||||||
extern "C" {
|
|
||||||
#include <portaudio.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// Portaudio player
|
|
||||||
class PortAudioPlayer : public AudioPlayer {
|
|
||||||
private:
|
|
||||||
static int pa_refcount;
|
|
||||||
wxMutex PAMutex;
|
|
||||||
volatile bool stopping;
|
|
||||||
//bool softStop;
|
|
||||||
bool playing;
|
|
||||||
float volume;
|
|
||||||
|
|
||||||
volatile int64_t playPos;
|
|
||||||
volatile int64_t startPos;
|
|
||||||
volatile int64_t endPos;
|
|
||||||
void *stream;
|
|
||||||
PaTime paStart;
|
|
||||||
|
|
||||||
static int paCallback(
|
|
||||||
const void *inputBuffer,
|
|
||||||
void *outputBuffer,
|
|
||||||
unsigned long framesPerBuffer,
|
|
||||||
const PaStreamCallbackTimeInfo*
|
|
||||||
timeInfo,
|
|
||||||
PaStreamCallbackFlags
|
|
||||||
statusFlags,
|
|
||||||
void *userData);
|
|
||||||
|
|
||||||
static void paStreamFinishedCallback(void *userData);
|
|
||||||
|
|
||||||
public:
|
|
||||||
PortAudioPlayer();
|
|
||||||
~PortAudioPlayer();
|
|
||||||
|
|
||||||
void OpenStream();
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
void Play(int64_t start,int64_t count);
|
|
||||||
void Stop(bool timerToo=true);
|
|
||||||
bool IsPlaying() { return playing; }
|
|
||||||
|
|
||||||
int64_t GetStartPosition() { return startPos; }
|
|
||||||
int64_t GetEndPosition() { return endPos; }
|
|
||||||
int64_t GetCurrentPosition();
|
|
||||||
void SetEndPosition(int64_t pos) { endPos = pos; }
|
|
||||||
void SetCurrentPosition(int64_t pos) { playPos = pos; }
|
|
||||||
|
|
||||||
void SetVolume(double vol) { volume = vol; }
|
|
||||||
double GetVolume() { return volume; }
|
|
||||||
|
|
||||||
wxArrayString GetOutputDevices(wxString favorite);
|
|
||||||
wxMutex *GetMutex() { return &PAMutex; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Factory
|
|
||||||
class PortAudioPlayerFactory : public AudioPlayerFactory {
|
|
||||||
public:
|
|
||||||
AudioPlayer *CreatePlayer() { return new PortAudioPlayer(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -131,7 +131,7 @@
|
||||||
#pragma comment(lib, "ffms2.lib")
|
#pragma comment(lib, "ffms2.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_PORTAUDIO2
|
#ifdef WITH_PORTAUDIO
|
||||||
#pragma comment(lib,"portaudio_x86.lib")
|
#pragma comment(lib,"portaudio_x86.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue