summaryrefslogtreecommitdiff
path: root/navit/support/espeak/wave_pulse.c
diff options
context:
space:
mode:
Diffstat (limited to 'navit/support/espeak/wave_pulse.c')
-rw-r--r--[-rwxr-xr-x]navit/support/espeak/wave_pulse.c141
1 files changed, 70 insertions, 71 deletions
diff --git a/navit/support/espeak/wave_pulse.c b/navit/support/espeak/wave_pulse.c
index d5fbc8c1e..1bcb593a7 100755..100644
--- a/navit/support/espeak/wave_pulse.c
+++ b/navit/support/espeak/wave_pulse.c
@@ -75,21 +75,52 @@ static t_wave_callback* my_callback_is_output_enabled=NULL;
#define MINREQ 880
#define FRAGSIZE 0
+#ifdef USE_PORTAUDIO
+// rename functions to be wrapped
+#define wave_init wave_pulse_init
+#define wave_open wave_pulse_open
+#define wave_write wave_pulse_write
+#define wave_close wave_pulse_close
+#define wave_is_busy wave_pulse_is_busy
+#define wave_terminate wave_pulse_terminate
+#define wave_get_read_position wave_pulse_get_read_position
+#define wave_get_write_position wave_pulse_get_write_position
+#define wave_flush wave_pulse_flush
+#define wave_set_callback_is_output_enabled wave_pulse_set_callback_is_output_enabled
+#define wave_test_get_write_buffer wave_pulse_test_get_write_buffer
+#define wave_get_remaining_time wave_pulse_get_remaining_time
+
+// check whether we can connect to PulseAudio
+#include <pulse/simple.h>
+int is_pulse_running()
+{
+ pa_sample_spec ss;
+ ss.format = ESPEAK_FORMAT;
+ ss.rate = SAMPLE_RATE;
+ ss.channels = ESPEAK_CHANNEL;
+
+ pa_simple *s = pa_simple_new(NULL, "eSpeak", PA_STREAM_PLAYBACK, NULL, "is_pulse_running", &ss, NULL, NULL, NULL);
+ if (s) {
+ pa_simple_free(s);
+ return 1;
+ } else
+ return 0;
+}
+#endif // USE_PORTAUDIO
+
static pthread_mutex_t pulse_mutex;
static pa_context *context = NULL;
static pa_stream *stream = NULL;
static pa_threaded_mainloop *mainloop = NULL;
-static pa_cvolume volume;
-static int volume_valid = 0;
-
static int do_trigger = 0;
static uint64_t written = 0;
static int time_offset_msec = 0;
static int just_flushed = 0;
static int connected = 0;
+static int wave_samplerate;
#define CHECK_DEAD_GOTO(label, warn) do { \
if (!mainloop || \
@@ -131,20 +162,7 @@ do { \
// SHOW("ti> read_index=0x%lx\n",the_time->read_index);
// }
-
-static void info_cb(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
- ENTER(__FUNCTION__);
- assert(c);
-
- if (!i)
- return;
-
- volume = i->volume;
- volume_valid = 1;
-}
-
static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) {
- pa_operation *o;
ENTER(__FUNCTION__);
assert(c);
@@ -154,13 +172,6 @@ static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t
(t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)))
return;
-
- if (!(o = pa_context_get_sink_input_info(c, index, info_cb, NULL))) {
- SHOW("pa_context_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(c)));
- return;
- }
-
- pa_operation_unref(o);
}
static void context_state_cb(pa_context *c, void *userdata) {
@@ -367,7 +378,7 @@ static void pulse_write(void* ptr, int length) {
SHOW("pulse_write > length=%d\n", length);
- CHECK_CONNECTED();
+ CHECK_CONNECTED_NO_RETVAL();
pa_threaded_mainloop_lock(mainloop);
CHECK_DEAD_GOTO(fail, 1);
@@ -475,18 +486,12 @@ static int pulse_open()
pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL);
ss.format = ESPEAK_FORMAT;
- ss.rate = SAMPLE_RATE;
+ ss.rate = wave_samplerate;
ss.channels = ESPEAK_CHANNEL;
if (!pa_sample_spec_valid(&ss))
return false;
-/* if (!volume_valid) { */
- pa_cvolume_reset(&volume, ss.channels);
- volume_valid = 1;
-/* } else if (volume.channels != ss.channels) */
-/* pa_cvolume_set(&volume, ss.channels, pa_cvolume_avg(&volume)); */
-
SHOW_TIME("pa_threaded_mainloop_new (call)");
if (!(mainloop = pa_threaded_mainloop_new())) {
SHOW("Failed to allocate main loop\n","");
@@ -539,8 +544,6 @@ static int pulse_open()
pa_stream_set_write_callback(stream, stream_request_cb, NULL);
pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
-
-
pa_buffer_attr a_attr;
a_attr.maxlength = MAXLENGTH;
@@ -550,7 +553,7 @@ static int pulse_open()
a_attr.fragsize = 0;
SHOW_TIME("pa_connect_playback");
- if (pa_stream_connect_playback(stream, NULL, &a_attr, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE), &volume, NULL) < 0) {
+ if (pa_stream_connect_playback(stream, NULL, &a_attr, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL) < 0) {
SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}
@@ -578,44 +581,24 @@ static int pulse_open()
pa_threaded_mainloop_wait(mainloop);
}
- if (!success) {
- SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
- goto unlock_and_fail;
- }
-
pa_operation_unref(o);
- /* Now request the initial stream info */
- if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) {
- SHOW("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context)));
+ if (!success) {
+ SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}
-
- SHOW_TIME("pa_threaded_mainloop_wait 2");
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(fail, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
-/* if (!volume_valid) { */
-/* SHOW("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); */
-/* goto unlock_and_fail; */
-/* } */
do_trigger = 0;
written = 0;
time_offset_msec = 0;
just_flushed = 0;
connected = 1;
- // volume_time_event = NULL;
pa_threaded_mainloop_unlock(mainloop);
SHOW_TIME("pulse_open (ret true)");
- // return true;
return PULSE_OK;
-
unlock_and_fail:
if (o)
@@ -677,13 +660,14 @@ void wave_set_callback_is_output_enabled(t_wave_callback* cb)
//>
//<wave_init
-void wave_init()
+int wave_init(int srate)
{
ENTER("wave_init");
stream = NULL;
+ wave_samplerate = srate;
- pulse_open();
+ return pulse_open() == PULSE_OK;
}
//>
@@ -761,19 +745,32 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
int wave_close(void* theHandler)
{
SHOW_TIME("wave_close > ENTER");
+ static int aStopStreamCount = 0;
- int a_status = pthread_mutex_lock(&pulse_mutex);
- if (a_status) {
- SHOW("Error: pulse_mutex lock=%d (%s)\n", a_status, __FUNCTION__);
- return PULSE_ERROR;
- }
-
- drain();
+ // Avoid race condition by making sure this function only
+ // gets called once at a time
+ aStopStreamCount++;
+ if (aStopStreamCount != 1)
+ {
+ SHOW_TIME("wave_close > LEAVE (stopStreamCount)");
+ return 0;
+ }
- pthread_mutex_unlock(&pulse_mutex);
- SHOW_TIME("wave_close (ret)");
+ int a_status = pthread_mutex_lock(&pulse_mutex);
+ if (a_status)
+ {
+ SHOW("Error: pulse_mutex lock=%d (%s)\n", a_status, __FUNCTION__);
+ aStopStreamCount = 0; // last action
+ return PULSE_ERROR;
+ }
+
+ drain();
+
+ pthread_mutex_unlock(&pulse_mutex);
+ SHOW_TIME("wave_close (ret)");
- return PULSE_OK;
+ aStopStreamCount = 0; // last action
+ return PULSE_OK;
}
//>
@@ -846,7 +843,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time)
{
// TBD: take in account time suplied by portaudio V18 API
a_time = sample - a_timing_info.read_index;
- a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE;
+ a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
}
else
{
@@ -873,7 +870,7 @@ void *wave_test_get_write_buffer()
// notdef USE_PULSEAUDIO
-void wave_init() {}
+int wave_init(return 1;) {}
void* wave_open(const char* the_api) {return (void *)1;}
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;}
int wave_close(void* theHandler) {return 0;}
@@ -893,8 +890,9 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time)
return 0;
}
-#endif // of USE_PORTAUDIO
+#endif // of USE_PULSEAUDIO
+#ifndef USE_PORTAUDIO
//>
//<clock_gettime2, add_time_in_ms
@@ -928,6 +926,7 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)
}
ts->tv_nsec = (long int)t_ns;
}
+#endif // ifndef USE_PORTAUDIO
#endif // USE_ASYNC