Browse Source

Remove the debugging code.

The debugging code is done inconsistently, mainly to trace the
event and audio output logic. This makes it harder to understand
the code flow for logic that is not enabled by default.

As such the debugging code makes the code harder to maintain.
master
Reece H. Dunn 9 years ago
parent
commit
e69c936329

+ 0
- 1
Makefile.am View File

@@ -89,7 +89,6 @@ src_libespeak_ng_la_SOURCES = \
src/libespeak-ng/compiledata.c \
src/libespeak-ng/compiledict.c \
src/libespeak-ng/compilembrola.c \
src/libespeak-ng/debug.c \
src/libespeak-ng/dictionary.c \
src/libespeak-ng/ieee80.c \
src/libespeak-ng/intonation.c \

+ 0
- 76
src/libespeak-ng/debug.c View File

@@ -1,76 +0,0 @@
/*
* Copyright (C) 2007 by Jonathan Duddington
* email: [email protected]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see: <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <stdio.h>
#include <stdarg.h>
#include "speech.h"
#include "debug.h"

#ifdef DEBUG_ENABLED
#include <sys/time.h>
#include <unistd.h>

static FILE *fd_log = NULL;
static const char *FILENAME = "/tmp/espeak.log";

void debug_init()
{
if ((fd_log = fopen(FILENAME, "a")) != NULL)
setvbuf(fd_log, NULL, _IONBF, 0);
}

void debug_enter(const char *text)
{
struct timeval tv;

gettimeofday(&tv, NULL);

if (!fd_log)
debug_init();

if (fd_log)
fprintf(fd_log, "%03d.%03dms > ENTER %s\n", (int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}


void debug_show(const char *format, ...)
{
va_list args;
va_start(args, format);
if (!fd_log)
debug_init();
if (fd_log)
vfprintf(fd_log, format, args);
va_end(args);
}

void debug_time(const char *text)
{
struct timeval tv;

gettimeofday(&tv, NULL);

if (!fd_log)
debug_init();
if (fd_log)
fprintf(fd_log, "%03d.%03dms > %s\n", (int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}

#endif

+ 0
- 51
src/libespeak-ng/debug.h View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2007 to 2009 by Jonathan Duddington
* email: [email protected]
* Copyright (C) 2015 Reece H. Dunn
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see: <http://www.gnu.org/licenses/>.
*/

#ifndef DEBUG_H
#define DEBUG_H

#ifdef __cplusplus
extern "C"
{
#endif

#ifdef DEBUG_ENABLED
#define ENTER(text) debug_enter(text)
#define SHOW(format, ...) debug_show(format, __VA_ARGS__);
#define SHOW_TIME(text) debug_time(text);
extern void debug_enter(const char *text);
extern void debug_show(const char *format, ...);
extern void debug_time(const char *text);

#else

#ifdef NO_VARIADIC_MACROS
#define SHOW(format) // VC6 doesn't allow "..."
#else
#define SHOW(format, ...)
#endif
#define SHOW_TIME(text)
#define ENTER(text)
#endif

#ifdef __cplusplus
}
#endif

#endif

+ 1
- 122
src/libespeak-ng/espeak_command.c View File

@@ -25,13 +25,10 @@
#include <assert.h>
#include <wchar.h>

#include "debug.h"

static unsigned int my_current_text_id = 0;

t_espeak_command *create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void *user_data)
{
ENTER("create_espeak_text");
int a_error = 1;
void *a_text = NULL;
t_espeak_text *data = NULL;
@@ -58,8 +55,6 @@ t_espeak_command *create_espeak_text(const void *text, size_t size, unsigned int
data->user_data = user_data;
a_error = 0;

SHOW("ET_TEXT malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier);

text_error:
if (a_error) {
if (a_text)
@@ -69,14 +64,11 @@ text_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_terminated_msg(unsigned int unique_identifier, void *user_data)
{
ENTER("create_espeak_terminated_msg");
int a_error = 1;
t_espeak_terminated_msg *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
@@ -91,8 +83,6 @@ t_espeak_command *create_espeak_terminated_msg(unsigned int unique_identifier, v
data->user_data = user_data;
a_error = 0;

SHOW("ET_TERMINATED_MSG command=%x (uid=%d, user_data=0x%x)\n", a_command, unique_identifier, (int)user_data);

msg_error:
if (a_error) {
if (a_command)
@@ -100,15 +90,12 @@ msg_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;

}

t_espeak_command *create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void *user_data)
{
ENTER("create_espeak_mark");
int a_error = 1;
void *a_text = NULL;
char *a_index_mark = NULL;
@@ -148,14 +135,11 @@ mark_error:
free(a_index_mark);
}

SHOW("ET_MARK malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier);

return a_command;
}

t_espeak_command *create_espeak_key(const char *key_name, void *user_data)
{
ENTER("create_espeak_key");
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));

@@ -176,14 +160,11 @@ key_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_char(wchar_t character, void *user_data)
{
ENTER("create_espeak_char");
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
if (!a_command)
@@ -203,14 +184,11 @@ char_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative)
{
ENTER("create_espeak_parameter");
int a_error = 1;
t_espeak_parameter *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
@@ -232,14 +210,11 @@ param_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_punctuation_list(const wchar_t *punctlist)
{
ENTER("create_espeak_punctuation_list");
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));

@@ -263,15 +238,11 @@ list_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_voice_name(const char *name)
{
ENTER("create_espeak_voice_name");

int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));

@@ -290,14 +261,11 @@ name_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

t_espeak_command *create_espeak_voice_spec(espeak_VOICE *voice)
{
ENTER("create_espeak_voice_spec");
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));

@@ -328,23 +296,18 @@ spec_error:
a_command = NULL;
}

SHOW("command=0x%x\n", a_command);

return a_command;
}

int delete_espeak_command(t_espeak_command *the_command)
{
ENTER("delete_espeak_command");
int a_status = 0;
if (the_command) {
switch (the_command->type)
{
case ET_TEXT:
if (the_command->u.my_text.text) {
SHOW("delete_espeak_command > ET_TEXT free text=%x, command=%x, uid=%d\n", the_command->u.my_text.text, the_command, the_command->u.my_text.unique_identifier);
if (the_command->u.my_text.text)
free(the_command->u.my_text.text);
}
break;
case ET_MARK:
if (the_command->u.my_mark.text)
@@ -361,7 +324,6 @@ int delete_espeak_command(t_espeak_command *the_command)
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);
if (the_command->state == CS_PENDING) {
the_command->state = CS_PROCESSED;
SHOW("delete_espeak_command > ET_TERMINATED_MSG callback (command=0x%x, uid=%d) \n", the_command, data->unique_identifier);
sync_espeak_terminated_msg(data->unique_identifier, data->user_data);
}
}
@@ -399,7 +361,6 @@ int delete_espeak_command(t_espeak_command *the_command)
default:
assert(0);
}
SHOW("delete_espeak_command > free command=0x%x\n", the_command);
free(the_command);
a_status = 1;
}
@@ -408,10 +369,6 @@ int delete_espeak_command(t_espeak_command *the_command)

void process_espeak_command(t_espeak_command *the_command)
{
ENTER("process_espeak_command");

SHOW("command=0x%x\n", the_command);

if (the_command == NULL)
return;

@@ -482,81 +439,3 @@ void process_espeak_command(t_espeak_command *the_command)
break;
}
}

void display_espeak_command(t_espeak_command *the_command)
{
ENTER("display_espeak_command");
#ifdef DEBUG_ENABLED
if (the_command == NULL) {
SHOW("display_espeak_command > command=%s\n", "NULL");
return;
}

SHOW("display_espeak_command > state=%d\n", the_command->state);

switch (the_command->type)
{
case ET_TEXT:
{
t_espeak_text *data = &(the_command->u.my_text);
SHOW("display_espeak_command > (0x%x) uid=%d, TEXT=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data));
}
break;
case ET_MARK:
{
t_espeak_mark *data = &(the_command->u.my_mark);
SHOW("display_espeak_command > (0x%x) uid=%d, MARK=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data));
}
break;
case ET_KEY:
{
const char *data = the_command->u.my_key.key_name;
SHOW("display_espeak_command > (0x%x) KEY=%c\n", the_command, data);
}
break;
case ET_TERMINATED_MSG:
{
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);

SHOW("display_espeak_command > (0x%x) TERMINATED_MSG uid=%d, user_data=0x%x, state=%d\n",
the_command, data->unique_identifier, data->user_data,
the_command->state);
}
break;
case ET_CHAR:
{
const wchar_t data = the_command->u.my_char.character;
SHOW("display_espeak_command > (0x%x) CHAR=%c\n", the_command, (char)data);
}
break;
case ET_PARAMETER:
{
t_espeak_parameter *data = &(the_command->u.my_param);
SHOW("display_espeak_command > (0x%x) PARAMETER=%d, value=%d, relative=%d\n",
the_command, data->parameter, data->value, data->relative);
}
break;
case ET_PUNCTUATION_LIST:
{
const wchar_t *data = the_command->u.my_punctuation_list;
sync_espeak_SetPunctuationList(data);
SHOW("display_espeak_command > (0x%x) PUNCTLIST=%s\n", the_command, (char *)data);
}
break;
case ET_VOICE_NAME:
{
const char *data = the_command->u.my_voice_name;
SHOW("display_espeak_command > (0x%x) VOICE_NAME=%s\n", the_command, data);
}
break;
case ET_VOICE_SPEC:
{
SHOW("display_espeak_command > (0x%x) VOICE_SPEC", the_command);
}
break;
default:
assert(0);
break;
}
#endif
}

+ 0
- 3
src/libespeak-ng/espeak_command.h View File

@@ -133,9 +133,6 @@ void process_espeak_command(t_espeak_command *the_command);

int delete_espeak_command(t_espeak_command *the_command);

void display_espeak_command(t_espeak_command *the_command);


espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void *user_data);

+ 3
- 122
src/libespeak-ng/event.c View File

@@ -36,7 +36,6 @@
#include "speak_lib.h"
#include "event.h"
#include "wave.h"
#include "debug.h"

// my_mutex: protects my_thread_is_talking,
static pthread_mutex_t my_mutex;
@@ -76,8 +75,6 @@ void event_set_callback(t_espeak_callback *SynthCallback)

void event_init(void)
{
ENTER("event_init");

my_event_is_running = 0;

// security
@@ -101,43 +98,8 @@ void event_init(void)
pthread_attr_destroy(&a_attrib);
}

static void event_display(espeak_EVENT *event)
{
ENTER("event_display");

#ifdef DEBUG_ENABLED
if (event == NULL)
SHOW("event_display > event=%s\n", "NULL");
else {
static const char *label[] = {
"LIST_TERMINATED",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??"
};

SHOW("event_display > event=0x%x\n", event);
SHOW("event_display > type=%s\n", label[event->type]);
SHOW("event_display > uid=%d\n", event->unique_identifier);
SHOW("event_display > text_position=%d\n", event->text_position);
SHOW("event_display > length=%d\n", event->length);
SHOW("event_display > audio_position=%d\n", event->audio_position);
SHOW("event_display > sample=%d\n", event->sample);
SHOW("event_display > user_data=0x%x\n", event->user_data);
}
#endif
}

static espeak_EVENT *event_copy(espeak_EVENT *event)
{
ENTER("event_copy");

if (event == NULL)
return NULL;

@@ -158,8 +120,6 @@ static espeak_EVENT *event_copy(espeak_EVENT *event)
}
}

event_display(a_event);

return a_event;
}

@@ -174,7 +134,6 @@ static espeak_EVENT *event_copy(espeak_EVENT *event)

static void event_notify(espeak_EVENT *event)
{
ENTER("event_notify");
static unsigned int a_old_uid = 0;

espeak_EVENT events[2];
@@ -183,8 +142,6 @@ static void event_notify(espeak_EVENT *event)
events[1].type = espeakEVENT_LIST_TERMINATED; // ... terminated by an event type=0

if (event && my_callback) {
event_display(event);

switch (event->type)
{
case espeakEVENT_SENTENCE:
@@ -218,10 +175,6 @@ static void event_notify(espeak_EVENT *event)

static int event_delete(espeak_EVENT *event)
{
ENTER("event_delete");

event_display(event);

if (event == NULL)
return 0;

@@ -245,10 +198,6 @@ static int event_delete(espeak_EVENT *event)

espeak_ERROR event_declare(espeak_EVENT *event)
{
ENTER("event_declare");

event_display(event);

if (!event)
return EE_INTERNAL_ERROR;

@@ -256,16 +205,13 @@ espeak_ERROR event_declare(espeak_EVENT *event)
espeak_ERROR a_error = EE_OK;

if (!a_status) {
SHOW_TIME("event_declare > locked\n");
espeak_EVENT *a_event = event_copy(event);
a_error = push(a_event);
if (a_error != EE_OK)
event_delete(a_event);
SHOW_TIME("event_declare > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

SHOW_TIME("event_declare > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);

if (a_status != 0)
@@ -276,42 +222,31 @@ espeak_ERROR event_declare(espeak_EVENT *event)

espeak_ERROR event_clear_all()
{
ENTER("event_clear_all");

int a_status = pthread_mutex_lock(&my_mutex);
int a_event_is_running = 0;

SHOW_TIME("event_stop > locked\n");
if (a_status != 0)
return EE_INTERNAL_ERROR;

if (my_event_is_running) {
SHOW_TIME("event_stop > post my_sem_stop_is_required\n");
sem_post(&my_sem_stop_is_required);
a_event_is_running = 1;
} else
init(); // clear pending events
SHOW_TIME("event_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
return EE_INTERNAL_ERROR;

if (a_event_is_running) {
SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler
SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n");
}

SHOW_TIME("LEAVE event_stop\n");

return EE_OK;
}

static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
{
ENTER("sleep_until_timeout_or_stop_request");

int a_stop_is_required = 0;
struct timespec ts;
struct timeval tv;
@@ -319,30 +254,16 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)

clock_gettime2(&ts);

#ifdef DEBUG_ENABLED
struct timespec to;
to.tv_sec = ts.tv_sec;
to.tv_nsec = ts.tv_nsec;
#endif

add_time_in_ms(&ts, time_in_ms);

SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);

while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1
&& errno == EINTR)
continue; // Restart when interrupted by handler

assert(gettimeofday(&tv, NULL) != -1);
SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n",
tv.tv_sec, tv.tv_usec*1000);

if (err == 0) {
SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n", "stop required!");
if (err == 0)
a_stop_is_required = 1; // stop required
}
return a_stop_is_required;
}

@@ -352,8 +273,6 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)

static int get_remaining_time(uint32_t sample, uint32_t *time_in_ms, int *stop_is_required)
{
ENTER("get_remaining_time");

int err = 0;
*stop_is_required = 0;
int i = 0;
@@ -388,35 +307,23 @@ static int get_remaining_time(uint32_t sample, uint32_t *time_in_ms, int *stop_i

static void *polling_thread(void *p)
{
ENTER("polling_thread");

while (1) {
int a_stop_is_required = 0;

SHOW_TIME("polling_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked (my_event_is_running = 0)\n");
my_event_is_running = 0;
pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n");

SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n");

while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler

SHOW_TIME("polling_thread > get my_sem_start_is_required\n");

a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked (my_event_is_running = 1)\n");
my_event_is_running = 1;
pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n");

a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
@@ -424,7 +331,6 @@ static void *polling_thread(void *p)

// In this loop, my_event_is_running = 1
while (head && (a_stop_is_required <= 0)) {
SHOW_TIME("polling_thread > check head\n");
while (0 == sem_trywait(&my_sem_start_is_required))
;

@@ -440,12 +346,9 @@ static void *polling_thread(void *p)
break;
else if (err != 0) {
// No available time: the event is deleted.
SHOW("polling_thread > %s\n", "audio device down");
a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked\n");
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n");
} else if (time_in_ms == 0) { // the event is already reached.
if (my_callback) {
event_notify(event);
@@ -456,16 +359,13 @@ static void *polling_thread(void *p)
}

a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked\n");
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n");

a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);

if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
@@ -475,15 +375,12 @@ static void *polling_thread(void *p)
}

a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked\n");

SHOW_TIME("polling_thread > my_event_is_running = 0\n");
my_event_is_running = 0;

if (a_stop_is_required <= 0) {
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
@@ -491,16 +388,13 @@ static void *polling_thread(void *p)
}

a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n");

if (a_stop_is_required > 0) {
SHOW("polling_thread > %s\n", "stop required!");
// no mutex required since the stop command is synchronous
// and waiting for my_sem_stop_is_acknowledged
init();

// acknowledge the stop request
SHOW_TIME("polling_thread > post my_sem_stop_is_acknowledged\n");
a_status = sem_post(&my_sem_stop_is_acknowledged);
}
}
@@ -512,19 +406,13 @@ enum { MAX_NODE_COUNTER = 1000 };

static espeak_ERROR push(void *the_data)
{
ENTER("event > push");

assert((!head && !tail) || (head && tail));

if (the_data == NULL) {
SHOW("event > push > event=0x%x\n", NULL);
if (the_data == NULL)
return EE_INTERNAL_ERROR;
}

if (node_counter >= MAX_NODE_COUNTER) {
SHOW("event > push > %s\n", "EE_BUFFER_FULL");
if (node_counter >= MAX_NODE_COUNTER)
return EE_BUFFER_FULL;
}

node *n = (node *)malloc(sizeof(node));
if (n == NULL)
@@ -542,14 +430,12 @@ static espeak_ERROR push(void *the_data)
tail->data = the_data;

node_counter++;
SHOW("event > push > counter=%d (uid=%d)\n", node_counter, ((espeak_EVENT *)the_data)->unique_identifier);

return EE_OK;
}

static void *pop()
{
ENTER("event > pop");
void *the_data = NULL;

assert((!head && !tail) || (head && tail));
@@ -560,7 +446,6 @@ static void *pop()
head = n->next;
free(n);
node_counter--;
SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n", the_data, node_counter, ((espeak_EVENT *)the_data)->unique_identifier);
}

if (head == NULL)
@@ -572,8 +457,6 @@ static void *pop()

static void init()
{
ENTER("event > init");

while (event_delete((espeak_EVENT *)pop()))
;

@@ -582,8 +465,6 @@ static void init()

void event_terminate()
{
ENTER("event_terminate");

if (thread_inited) {
pthread_cancel(my_thread);
pthread_join(my_thread, NULL);

+ 5
- 89
src/libespeak-ng/fifo.c View File

@@ -36,7 +36,6 @@
#include "speech.h"
#include "fifo.h"
#include "wave.h"
#include "debug.h"

// my_mutex: protects my_thread_is_talking,
// my_stop_is_required, and the command fifo
@@ -64,8 +63,6 @@ enum {

void fifo_init()
{
ENTER("fifo_init");

// security
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL);
init(0);
@@ -86,30 +83,23 @@ void fifo_init()
pthread_attr_destroy(&a_attrib);

// leave once the thread is actually started
SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler
SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
}

espeak_ERROR fifo_add_command(t_espeak_command *the_command)
{
ENTER("fifo_add_command");

int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;

if (!a_status) {
SHOW_TIME("fifo_add_command > locked\n");
a_error = push(the_command);
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

if (!a_status && !my_command_is_running && (a_error == EE_OK)) {
// quit when command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val = 1;
while (val > 0) {
@@ -121,35 +111,27 @@ espeak_ERROR fifo_add_command(t_espeak_command *the_command)
if (a_status != 0)
a_error = EE_INTERNAL_ERROR;

SHOW_TIME("LEAVE fifo_add_command");
return a_error;
}

espeak_ERROR fifo_add_commands(t_espeak_command *command1, t_espeak_command *command2)
{
ENTER("fifo_add_command");

int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;

if (!a_status) {
SHOW_TIME("fifo_add_commands > locked\n");

if (node_counter+1 >= MAX_NODE_COUNTER) {
SHOW("push > %s\n", "EE_BUFFER_FULL");
if (node_counter+1 >= MAX_NODE_COUNTER)
a_error = EE_BUFFER_FULL;
} else {
else {
push(command1);
push(command2);
}
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

if (!a_status && !my_command_is_running && (a_error == EE_OK)) {
// quit when one command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val = 1;
while (val > 0) {
@@ -161,53 +143,41 @@ espeak_ERROR fifo_add_commands(t_espeak_command *command1, t_espeak_command *com
if (a_status != 0)
a_error = EE_INTERNAL_ERROR;

SHOW_TIME("LEAVE fifo_add_commands");
return a_error;
}

espeak_ERROR fifo_stop()
{
ENTER("fifo_stop");

int a_command_is_running = 0;
int a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("fifo_stop > locked\n");
if (a_status != 0)
return EE_INTERNAL_ERROR;

if (my_command_is_running) {
a_command_is_running = 1;
my_stop_is_required = 1;
SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
}
SHOW_TIME("fifo_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
return EE_INTERNAL_ERROR;

if (a_command_is_running) {
SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler
SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
}

SHOW_TIME("fifo_stop > my_stop_is_required = 0\n");
my_stop_is_required = 0;
SHOW_TIME("LEAVE fifo_stop\n");

return EE_OK;
}

int fifo_is_busy()
{
SHOW("fifo_is_busy > aResult = %d\n", my_command_is_running);
return my_command_is_running;
}

static int sleep_until_start_request_or_inactivity()
{
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER");
int a_start_is_required = 0;

// Wait for the start request (my_sem_start_is_required).
@@ -229,37 +199,22 @@ static int sleep_until_start_request_or_inactivity()

clock_gettime2(&ts);

#ifdef DEBUG_ENABLED
struct timespec to;
to.tv_sec = ts.tv_sec;
to.tv_nsec = ts.tv_nsec;
#endif

add_time_in_ms(&ts, INACTIVITY_TIMEOUT);

SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);

while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1
&& errno == EINTR)
continue;

assert(gettimeofday(&tv, NULL) != -1);
SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err,
tv.tv_sec, tv.tv_usec*1000);

if (err == 0)
a_start_is_required = 1;
}
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > LEAVE");
return a_start_is_required;
}

static void close_stream()
{
SHOW_TIME("fifo > close_stream > ENTER\n");

// Warning: a wave_close can be already required by
// an external command (espeak_Cancel + fifo_stop), if so:
// my_stop_is_required = 1;
@@ -283,29 +238,20 @@ static void close_stream()

if (a_stop_is_required) {
// acknowledge the stop request
SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert(a_status != -1);
}
}

SHOW_TIME("fifo > close_stream > LEAVE\n");
}

static void *say_thread(void *p)
{
ENTER("say_thread");

SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");

// announce that thread is started
sem_post(&my_sem_stop_is_acknowledged);

int look_for_inactivity = 0;

while (1) {
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");

int a_start_is_required = 0;
if (look_for_inactivity) {
a_start_is_required = sleep_until_start_request_or_inactivity();
@@ -318,35 +264,24 @@ static void *say_thread(void *p)
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler
}
SHOW_TIME("say_thread > get my_sem_start_is_required\n");

SHOW_TIME("say_thread > my_command_is_running = 1\n");
my_command_is_running = 1;

while (my_command_is_running) {
SHOW_TIME("say_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex);
assert(!a_status);
t_espeak_command *a_command = (t_espeak_command *)pop();

if (a_command == NULL) {
SHOW_TIME("say_thread > text empty (talking=0) \n");
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > unlocked\n");
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
} else {
display_espeak_command(a_command);
// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while (0 == sem_trywait(&my_sem_start_is_required))
;

if (my_stop_is_required) {
SHOW_TIME("say_thread > my_command_is_running = 0\n");
if (my_stop_is_required)
my_command_is_running = 0;
}
SHOW_TIME("say_thread > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);

if (my_command_is_running)
@@ -361,17 +296,14 @@ static void *say_thread(void *p)
init(1);

// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while (0 == sem_trywait(&my_sem_start_is_required))
;

// acknowledge the stop request
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert(a_status != -1);
}
// and wait for the next start
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
}

return NULL;
@@ -379,7 +311,6 @@ static void *say_thread(void *p)

int fifo_is_command_enabled()
{
SHOW("ENTER fifo_is_command_enabled=%d\n", (int)(0 == my_stop_is_required));
return 0 == my_stop_is_required;
}

@@ -393,19 +324,13 @@ static node *tail = NULL;

static espeak_ERROR push(t_espeak_command *the_command)
{
ENTER("fifo > push");

assert((!head && !tail) || (head && tail));

if (the_command == NULL) {
SHOW("push > command=0x%x\n", NULL);
if (the_command == NULL)
return EE_INTERNAL_ERROR;
}

if (node_counter >= MAX_NODE_COUNTER) {
SHOW("push > %s\n", "EE_BUFFER_FULL");
if (node_counter >= MAX_NODE_COUNTER)
return EE_BUFFER_FULL;
}

node *n = (node *)malloc(sizeof(node));
if (n == NULL)
@@ -423,17 +348,14 @@ static espeak_ERROR push(t_espeak_command *the_command)
tail->data = the_command;

node_counter++;
SHOW("push > counter=%d\n", node_counter);

the_command->state = CS_PENDING;
display_espeak_command(the_command);

return EE_OK;
}

static t_espeak_command *pop()
{
ENTER("fifo > pop");
t_espeak_command *the_command = NULL;

assert((!head && !tail) || (head && tail));
@@ -444,21 +366,17 @@ static t_espeak_command *pop()
head = n->next;
free(n);
node_counter--;
SHOW("pop > command=0x%x (counter=%d)\n", the_command, node_counter);
}

if (head == NULL)
tail = NULL;

display_espeak_command(the_command);

return the_command;
}

static void init(int process_parameters)
{
t_espeak_command *c = NULL;
ENTER("fifo > init");
c = pop();
while (c != NULL) {
if (process_parameters && (c->type == ET_PARAMETER || c->type == ET_VOICE_NAME || c->type == ET_VOICE_SPEC))
@@ -471,8 +389,6 @@ static void init(int process_parameters)

void fifo_terminate()
{
ENTER("fifo_terminate");

pthread_cancel(my_thread);
pthread_join(my_thread, NULL);
pthread_mutex_destroy(&my_mutex);

+ 0
- 94
src/libespeak-ng/speak_lib.c View File

@@ -46,7 +46,6 @@
#include "synthesize.h"
#include "voice.h"
#include "translate.h"
#include "debug.h"

#include "fifo.h"
#include "event.h"
@@ -89,17 +88,8 @@ void WVoiceChanged(voice_t *wvoice)

static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event)
{
ENTER("dispatch_audio");

int a_wave_can_be_played = fifo_is_command_enabled();

#ifdef DEBUG_ENABLED
SHOW("*** dispatch_audio > uid=%d, [write=%p (%d bytes)], sample=%d, a_wave_can_be_played = %d\n",
(event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length,
(event) ? event->sample : 0,
a_wave_can_be_played);
#endif

switch (my_mode)
{
case AUDIO_OUTPUT_PLAYBACK:
@@ -143,7 +133,6 @@ static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event)
espeak_ERROR a_error = event_declare(event);
if (a_error != EE_BUFFER_FULL)
break;
SHOW_TIME("dispatch_audio > EE_BUFFER_FULL\n");
usleep(10000);
a_wave_can_be_played = fifo_is_command_enabled();
}
@@ -158,11 +147,6 @@ static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event)
break;
}

if (!a_wave_can_be_played)
SHOW_TIME("dispatch_audio > synth must be stopped!\n");

SHOW_TIME("LEAVE dispatch_audio\n");

return a_wave_can_be_played == 0; // 1 = stop synthesis, -1 = error
}

@@ -183,14 +167,8 @@ static int create_events(short *outbuf, int length, espeak_EVENT *event, uint32_
event = NULL;
else {
event = event_list + i;
#ifdef DEBUG_ENABLED
SHOW("Synthesize: event->sample(%d) + %d = %d\n", event->sample, the_write_pos, event->sample + the_write_pos);
#endif
event->sample += the_write_pos;
}
#ifdef DEBUG_ENABLED
SHOW("*** Synthesize: i=%d (event_list_ix=%d), length=%d\n", i, event_list_ix, length);
#endif
finished = dispatch_audio((short *)outbuf, length, event);
length = 0; // the wave data are played once.
i++;
@@ -200,8 +178,6 @@ static int create_events(short *outbuf, int length, espeak_EVENT *event, uint32_

int sync_espeak_terminated_msg(uint32_t unique_identifier, void *user_data)
{
ENTER("sync_espeak_terminated_msg");

int finished = 0;

memset(event_list, 0, 2*sizeof(espeak_EVENT));
@@ -218,7 +194,6 @@ int sync_espeak_terminated_msg(uint32_t unique_identifier, void *user_data)
espeak_ERROR a_error = event_declare(event_list);
if (a_error != EE_BUFFER_FULL)
break;
SHOW_TIME("sync_espeak_terminated_msg > EE_BUFFER_FULL\n");
usleep(10000);
}
} else {
@@ -373,12 +348,6 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
uint32_t a_write_pos = 0;
#endif

#ifdef DEBUG_ENABLED
ENTER("Synthesize");
if (text)
SHOW("Synthesize > uid=%d, flags=%d, >>>text=%s<<<\n", unique_identifier, flags, text);
#endif

if ((outbuf == NULL) || (event_list == NULL))
return EE_INTERNAL_ERROR; // espeak_Initialize() has not been called

@@ -421,9 +390,6 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
}

for (;;) {
#ifdef DEBUG_ENABLED
SHOW("Synthesize > %s\n", "for (next)");
#endif
out_ptr = outbuf;
out_end = &outbuf[outbuf_size];
event_list_ix = 0;
@@ -477,25 +443,9 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
return EE_OK;
}

#ifdef DEBUG_ENABLED
static const char *label[] = {
"END_OF_EVENT_LIST",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??"
};
#endif

void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr)
{
// type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end, 7=phoneme
ENTER("MarkerEvent");
espeak_EVENT *ep;
double time;

@@ -513,13 +463,6 @@ void MarkerEvent(int type, unsigned int char_position, int value, int value2, un
ep->audio_position = (int)time;
ep->sample = (count_samples + mbrola_delay + (out_ptr - out_start)/2);

#ifdef DEBUG_ENABLED
SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n", count_samples, out_ptr, out_start);
SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n",
label[ep->type], ep->unique_identifier, ep->text_position, ep->length,
ep->audio_position, ep->sample);
#endif

if ((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY))
ep->id.name = &namedata[value];
else if (type == espeakEVENT_PHONEME) {
@@ -535,11 +478,6 @@ espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text,
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void *user_data)
{
#ifdef DEBUG_ENABLED
ENTER("sync_espeak_Synth");
SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text);
#endif

espeak_ERROR aStatus;

InitText(flags);
@@ -572,7 +510,6 @@ espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text,
wave_flush(my_audio);
#endif

SHOW_TIME("LEAVE sync_espeak_Synth");
return aStatus;
}

@@ -595,7 +532,6 @@ espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *
end_character_position = end_position;

aStatus = Synthesize(unique_identifier, text, flags | espeakSSML);
SHOW_TIME("LEAVE sync_espeak_Synth_Mark");

return aStatus;
}
@@ -646,7 +582,6 @@ void sync_espeak_SetPunctuationList(const wchar_t *punctlist)

ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback *SynthCallback)
{
ENTER("espeak_SetSynthCallback");
synth_callback = SynthCallback;
#ifdef USE_ASYNC
event_set_callback(synth_callback);
@@ -655,7 +590,6 @@ ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback *SynthCallback)

ESPEAK_API void espeak_SetUriCallback(int (*UriCallback)(int, const char *, const char *))
{
ENTER("espeak_SetUriCallback");
uri_callback = UriCallback;
}

@@ -666,7 +600,6 @@ ESPEAK_API void espeak_SetPhonemeCallback(int (*PhonemeCallback)(const char *))

ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options)
{
ENTER("espeak_Initialize");
int param;

// It seems that the wctype functions don't work until the locale has been set
@@ -734,11 +667,6 @@ ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size,
unsigned int end_position, unsigned int flags,
unsigned int *unique_identifier, void *user_data)
{
#ifdef DEBUG_ENABLED
ENTER("espeak_Synth");
SHOW("espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text);
#endif

if (f_logespeak) {
fprintf(f_logespeak, "\nSYNTH posn %d %d %d flags 0x%x\n%s\n", position, end_position, position_type, flags, (const char *)text);
fflush(f_logespeak);
@@ -787,11 +715,6 @@ ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size,
unsigned int *unique_identifier,
void *user_data)
{
#ifdef DEBUG_ENABLED
ENTER("espeak_Synth_Mark");
SHOW("espeak_Synth_Mark > index_mark=%s, end_position=%d, flags=%d, text=%s\n", index_mark, end_position, flags, text);
#endif

espeak_ERROR a_error = EE_OK;
static unsigned int temp_identifier;

@@ -834,7 +757,6 @@ ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size,

ESPEAK_API espeak_ERROR espeak_Key(const char *key)
{
ENTER("espeak_Key");
// symbolic name, symbolicname_character - is there a system resource of symbolicnames per language

if (f_logespeak)
@@ -858,7 +780,6 @@ ESPEAK_API espeak_ERROR espeak_Key(const char *key)

ESPEAK_API espeak_ERROR espeak_Char(wchar_t character)
{
ENTER("espeak_Char");
// is there a system resource of character names per language?

if (f_logespeak)
@@ -885,21 +806,16 @@ ESPEAK_API espeak_ERROR espeak_Char(wchar_t character)

ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name)
{
ENTER("espeak_SetVoiceByName");

return SetVoiceByName(name);
}

ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector)
{
ENTER("espeak_SetVoiceByProperties");

return SetVoiceByProperties(voice_selector);
}

ESPEAK_API int espeak_GetParameter(espeak_PARAMETER parameter, int current)
{
ENTER("espeak_GetParameter");
// current: 0=default value, 1=current value
if (current)
return param_stack[0].parameter[parameter];
@@ -908,8 +824,6 @@ ESPEAK_API int espeak_GetParameter(espeak_PARAMETER parameter, int current)

ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative)
{
ENTER("espeak_SetParameter");

if (f_logespeak)
fprintf(f_logespeak, "SETPARAM %d %d %d\n", parameter, value, relative);
#ifdef USE_ASYNC
@@ -934,7 +848,6 @@ ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int valu

ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist)
{
ENTER("espeak_SetPunctuationList");
// Set the list of punctuation which are spoken for "some".

#ifdef USE_ASYNC
@@ -958,7 +871,6 @@ ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist)

ESPEAK_API void espeak_SetPhonemeTrace(int phonememode, FILE *stream)
{
ENTER("espeak_SetPhonemes");
/* phonememode: Controls the output of phoneme symbols for the text
bits 0-2:
value=0 No phoneme output (default)
@@ -993,20 +905,17 @@ ESPEAK_API const char *espeak_TextToPhonemes(const void **textptr, int textmode,

ESPEAK_API void espeak_CompileDictionary(const char *path, FILE *log, int flags)
{
ENTER("espeak_CompileDictionary");
CompileDictionary(path, dictionary_name, log, NULL, flags);
}

ESPEAK_API espeak_ERROR espeak_Cancel(void)
{
#ifdef USE_ASYNC
ENTER("espeak_Cancel");
fifo_stop();
event_clear_all();

if (my_mode == AUDIO_OUTPUT_PLAYBACK)
wave_close(my_audio);
SHOW_TIME("espeak_Cancel > LEAVE");
#endif
embedded_value[EMBED_T] = 0; // reset echo for pronunciation announcements

@@ -1032,12 +941,10 @@ ESPEAK_API espeak_ERROR espeak_Synchronize(void)
{
espeak_ERROR berr = err;
#ifdef USE_ASYNC
SHOW_TIME("espeak_Synchronize > ENTER");
while (espeak_IsPlaying())
usleep(20000);
#endif
err = EE_OK;
SHOW_TIME("espeak_Synchronize > LEAVE");
return berr;
}

@@ -1046,7 +953,6 @@ extern void FreeVoiceList(void);

ESPEAK_API espeak_ERROR espeak_Terminate(void)
{
ENTER("espeak_Terminate");
#ifdef USE_ASYNC
fifo_stop();
fifo_terminate();

+ 16
- 113
src/libespeak-ng/wave.c View File

@@ -40,7 +40,6 @@
#include <unistd.h>
#endif
#include "wave.h"
#include "debug.h"

#ifdef NEED_STRUCT_TIMESPEC
#define HAVE_STRUCT_TIMESPEC 1
@@ -254,7 +253,6 @@ static void init_buffer()
myRead = myBuffer;
memset(myBuffer, 0, BUFFER_LENGTH);
myReadPosition = myWritePosition = 0;
SHOW("init_buffer > myRead=0x%x, myWrite=0x%x, BUFFER_LENGTH=0x%x, myReadPosition = myWritePosition = 0\n", (int)myRead, (int)myWrite, BUFFER_LENGTH);
}

static unsigned int get_used_mem()
@@ -272,7 +270,6 @@ static unsigned int get_used_mem()
used = aWrite - aRead;
else
used = aWrite + BUFFER_LENGTH - aRead;
SHOW("get_used_mem > %d\n", used);

return used;
}
@@ -280,23 +277,17 @@ static unsigned int get_used_mem()
static void start_stream()
{
PaError err;
SHOW_TIME("start_stream");

my_stream_could_start = 0;
mInCallbackFinishedState = false;

err = Pa_StartStream(pa_stream);
SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));

#if USE_PORTAUDIO == 19
if (err == paStreamIsNotStopped) {
SHOW_TIME("start_stream > restart stream (begin)");
// not sure why we need this, but PA v19 seems to need it
err = Pa_StopStream(pa_stream);
SHOW("start_stream > Pa_StopStream=%d (%s)\n", err, Pa_GetErrorText(err));
err = Pa_StartStream(pa_stream);
SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
SHOW_TIME("start_stream > restart stream (end)");
}
#endif
}
@@ -319,14 +310,13 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer,
size_t n = out_channels*sizeof(uint16_t)*framesPerBuffer;

myReadPosition += framesPerBuffer;
SHOW("pa_callback > myReadPosition=%u, framesPerBuffer=%lu (n=0x%x) \n", (int)myReadPosition, framesPerBuffer, n);

if (aWrite >= myRead) {
if ((size_t)(aWrite - myRead) >= n) {
memcpy(outputBuffer, myRead, n);
myRead += n;
} else {
SHOW_TIME("pa_callback > underflow");
// underflow
aResult = 1; // paComplete;
mInCallbackFinishedState = true;
size_t aUsedMem = 0;
@@ -343,29 +333,23 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer,
myRead += n;
} else if ((size_t)(aWrite + BUFFER_LENGTH - myRead) >= n) {
int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
if (aTopMem) {
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n", (int)myRead, (int)aTopMem);
if (aTopMem)
memcpy(outputBuffer, myRead, aTopMem);
}
int aRest = n - aTopMem;
if (aRest) {
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n", (int)myRead, (int)aRest);
char *p = (char *)outputBuffer + aTopMem;
memcpy(p, myBuffer, aRest);
}
myRead = myBuffer + aRest;
} else {
SHOW_TIME("pa_callback > underflow");
// underflow
aResult = 1; // paComplete;

int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
if (aTopMem) {
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n", (int)myRead, (int)aTopMem);
if (aTopMem)
memcpy(outputBuffer, myRead, aTopMem);
}
int aRest = aWrite - myBuffer;
if (aRest) {
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n", (int)myRead, (int)aRest);
char *p = (char *)outputBuffer + aTopMem;
memcpy(p, myBuffer, aRest);
}
@@ -377,8 +361,6 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer,
}
}

SHOW("pa_callback > myRead=%x\n", (int)myRead);

#ifdef ARCH_BIG
// BIG-ENDIAN, swap the order of bytes in each sound sample in the portaudio buffer
int c;
@@ -399,16 +381,12 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer,

void wave_flush(void *theHandler)
{
ENTER("wave_flush");

if (my_stream_could_start)
start_stream();
}

static int wave_open_sound()
{
ENTER("wave_open_sound");

PaError err = paNoError;
PaError active;

@@ -419,7 +397,6 @@ static int wave_open_sound()
#endif

if (active == 1)
SHOW_TIME("wave_open_sound > already active");
return 0;
if (active < 0) {
out_channels = 1;
@@ -443,10 +420,7 @@ static int wave_open_sound()
paNoFlag,
pa_callback, (void *)userdata);

SHOW("wave_open_sound > Pa_OpenDefaultStream(1): err=%d (%s)\n", err, Pa_GetErrorText(err));

if (err == paInvalidChannelCount) {
SHOW_TIME("wave_open_sound > try stereo");
// failed to open with mono, try stereo
out_channels = 2;
PaError err = Pa_OpenStream(&pa_stream,
@@ -464,7 +438,6 @@ static int wave_open_sound()
wave_samplerate, FRAMES_PER_BUFFER, 0,
paNoFlag,
pa_callback, (void *)userdata);
SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n", err, Pa_GetErrorText(err));
err = 0; // avoid warning
}
mInCallbackFinishedState = false; // v18 only
@@ -493,7 +466,6 @@ static int wave_open_sound()
(void *)userdata);
}
if (err == paInvalidChannelCount) {
SHOW_TIME("wave_open_sound > try stereo");
// failed to open with mono, try stereo
out_channels = 2;
myOutputParameters.channelCount = out_channels;
@@ -510,8 +482,6 @@ static int wave_open_sound()
#endif
}

SHOW("wave_open_sound > %s\n", "LEAVE");

return err != paNoError;
}

@@ -527,17 +497,9 @@ static void update_output_parameters(int selectedDevice, const PaDeviceInfo *dev
// deviceInfo = Pa_GetDeviceInfo(selectedDevice);
if (deviceInfo) {
double aLatency = deviceInfo->defaultLowOutputLatency;
myOutputParameters.suggestedLatency = aLatency; // for faster response ?
SHOW("Device=%d, myOutputParameters.suggestedLatency=%f, aCoeff=%f\n",
selectedDevice,
myOutputParameters.suggestedLatency,
aCoeff);
} else {
myOutputParameters.suggestedLatency = aLatency; // for faster response ?
} else
myOutputParameters.suggestedLatency = (double)0.1; // 100ms
SHOW("Device=%d, myOutputParameters.suggestedLatency=%f (default)\n",
selectedDevice,
myOutputParameters.suggestedLatency);
}

myOutputParameters.hostApiSpecificStreamInfo = NULL;
}
@@ -545,14 +507,10 @@ static void update_output_parameters(int selectedDevice, const PaDeviceInfo *dev

static void select_device(const char *the_api)
{
ENTER("select_device");

#if (USE_PORTAUDIO == 19)
int numDevices = Pa_GetDeviceCount();
if (numDevices < 0) {
SHOW("ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
if (numDevices < 0)
assert(0);
}

PaDeviceIndex i = 0, selectedIndex = 0, defaultAlsaIndex = numDevices;
const PaDeviceInfo *deviceInfo = NULL;
@@ -578,7 +536,6 @@ static void select_device(const char *the_api)
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(defaultAlsaIndex);
update_output_parameters(defaultAlsaIndex, deviceInfo);
if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) {
SHOW("select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex);
selectedIndex = defaultAlsaIndex;
selectedDeviceInfo = deviceInfo;
break;
@@ -587,13 +544,10 @@ static void select_device(const char *the_api)

// if the default output device does not match,
// look for the device with the highest number of output channels
SHOW("select_device > ALSA, i=%d (numDevices=%d)\n", i, numDevices);

update_output_parameters(i, deviceInfo);

if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) {
SHOW("select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i);

if (!selectedDeviceInfo
|| (selectedDeviceInfo->maxOutputChannels < deviceInfo->maxOutputChannels)) {
selectedIndex = i;
@@ -622,7 +576,6 @@ void wave_set_callback_is_output_enabled(t_wave_callback *cb)

int wave_init(int srate)
{
ENTER("wave_init");
PaError err;

pa_stream = NULL;
@@ -633,14 +586,11 @@ int wave_init(int srate)
// PortAudio sound output library
err = Pa_Initialize();
pa_init_err = err;
if (err != paNoError)
SHOW_TIME("wave_init > Failed to initialise the PortAudio sound");
return err == paNoError;
}

void *wave_open(const char *the_api)
{
ENTER("wave_open");
static int once = 0;

if (!once) {
@@ -660,11 +610,9 @@ static size_t copyBuffer(char *dest, char *src, const size_t theSizeInBytes)
if ((src != NULL) && dest != NULL) {
// copy for one channel (mono)?
if (out_channels == 1) {
SHOW("copyBuffer > 1 channel > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
memcpy(dest, src, theSizeInBytes);
bytes_written = theSizeInBytes;
} else { // copy for 2 channels (stereo)
SHOW("copyBuffer > 2 channels > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
i = 0;
a_dest = (uint16_t *)dest;
a_src = (uint16_t *)src;
@@ -682,18 +630,14 @@ static size_t copyBuffer(char *dest, char *src, const size_t theSizeInBytes)

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
ENTER("wave_write");
size_t bytes_written = 0;
// space in ringbuffer for the sample needed: 1x mono channel but 2x for 1 stereo channel
size_t bytes_to_write = (out_channels == 1) ? theSize : theSize*2;
my_stream_could_start = 0;

if (pa_stream == NULL) {
SHOW_TIME("wave_write > wave_open_sound\n");
if (0 != wave_open_sound()) {
SHOW_TIME("wave_write > wave_open_sound fails!");
if (0 != wave_open_sound())
return 0;
}
my_stream_could_start = 1;
} else if (!wave_is_busy(NULL))
my_stream_could_start = 1;
@@ -704,13 +648,10 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz

size_t aTotalFreeMem = 0;
char *aRead = myRead;
SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);

while (1) {
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled()))
return 0;
}

aRead = myRead;

@@ -729,8 +670,6 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
if (aTotalFreeMem >= bytes_to_write)
break;

SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem);
SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
usleep(10000);
}

@@ -738,7 +677,6 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz

// write pointer is ahead the read pointer?
if (myWrite >= aRead) {
SHOW_TIME("wave_write > myWrite >= aRead");
// determine remaining free memory to the end of the ringbuffer
size_t aFreeMem = myBuffer + BUFFER_LENGTH - myWrite;
// is enough linear space available (regardless 1 or 2 channels)?
@@ -759,10 +697,8 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem);
}
}
} else { // read pointer is ahead the write pointer
SHOW_TIME("wave_write > myWrite <= aRead");
} else // read pointer is ahead the write pointer
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
}

bytes_written = bytes_to_write;
myWritePosition += theSize/sizeof(uint16_t); // add number of samples
@@ -770,46 +706,32 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
start_stream();

SHOW_TIME("wave_write > LEAVE");

return bytes_written;
}

int wave_close(void *theHandler)
{
SHOW_TIME("wave_close > ENTER");

static int aStopStreamCount = 0;

#if (USE_PORTAUDIO == 19)
if (pa_stream == NULL) {
SHOW_TIME("wave_close > LEAVE (NULL stream)");
if (pa_stream == NULL)
return 0;
}

if (Pa_IsStreamStopped(pa_stream)) {
SHOW_TIME("wave_close > LEAVE (stopped)");
if (Pa_IsStreamStopped(pa_stream))
return 0;
}
#else
if (pa_stream == NULL) {
SHOW_TIME("wave_close > LEAVE (NULL stream)");
if (pa_stream == NULL)
return 0;
}

if (Pa_StreamActive(pa_stream) == false && mInCallbackFinishedState == false) {
SHOW_TIME("wave_close > LEAVE (not active)");
if (Pa_StreamActive(pa_stream) == false && mInCallbackFinishedState == false)
return 0;
}
#endif

// 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)");
if (aStopStreamCount != 1)
return 0;
}

// Comment from Audacity-1.2.4b adapted to the eSpeak context.
//
@@ -841,10 +763,8 @@ int wave_close(void *theHandler)
#if (USE_PORTAUDIO == 19)
if (pa_stream) {
Pa_AbortStream(pa_stream);
SHOW_TIME("wave_close > Pa_AbortStream (end)");

Pa_CloseStream(pa_stream);
SHOW_TIME("wave_close > Pa_CloseStream (end)");
pa_stream = NULL;
mInCallbackFinishedState = false;
}
@@ -852,13 +772,10 @@ int wave_close(void *theHandler)
if (pa_stream) {
if (mInCallbackFinishedState) {
Pa_StopStream(pa_stream);
SHOW_TIME("wave_close > Pa_StopStream (end)");
} else {
Pa_AbortStream(pa_stream);
SHOW_TIME("wave_close > Pa_AbortStream (end)");
}
Pa_CloseStream(pa_stream);
SHOW_TIME("wave_close > Pa_CloseStream (end)");

pa_stream = NULL;
mInCallbackFinishedState = false;
@@ -867,7 +784,6 @@ int wave_close(void *theHandler)
init_buffer();

aStopStreamCount = 0; // last action
SHOW_TIME("wave_close > LEAVE");
return 0;
}

@@ -875,8 +791,6 @@ int wave_is_busy(void *theHandler)
{
PaError active = 0;

SHOW_TIME("wave_is_busy");

if (pa_stream) {
#if USE_PORTAUDIO == 18
active = Pa_StreamActive(pa_stream)
@@ -887,27 +801,21 @@ int wave_is_busy(void *theHandler)
#endif
}

SHOW("wave_is_busy: %d\n", active);

return active == 1;
}

void wave_terminate()
{
ENTER("wave_terminate");

Pa_Terminate();
}

uint32_t wave_get_read_position(void *theHandler)
{
SHOW("wave_get_read_position > myReadPosition=%u\n", myReadPosition);
return myReadPosition;
}

uint32_t wave_get_write_position(void *theHandler)
{
SHOW("wave_get_write_position > myWritePosition=%u\n", myWritePosition);
return myWritePosition;
}

@@ -915,10 +823,8 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{
double a_time = 0;

if (!time || !pa_stream) {
SHOW("event get_remaining_time> %s\n", "audio device not available");
if (!time || !pa_stream)
return -1;
}

if (sample > myReadPosition) {
// TBD: take in account time suplied by portaudio V18 API
@@ -927,8 +833,6 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
} else
a_time = 0;

SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time);

*time = (uint32_t)a_time;

return 0;
@@ -1023,7 +927,6 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)

uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) {
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;
}

+ 22
- 110
src/libespeak-ng/wave_pulse.c View File

@@ -46,7 +46,6 @@
#include <unistd.h>
#endif
#include "wave.h"
#include "debug.h"

enum { ONE_BILLION = 1000000000 };

@@ -124,7 +123,7 @@ static int wave_samplerate;
!context || pa_context_get_state(context) != PA_CONTEXT_READY || \
!stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \
if (warn) \
SHOW("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
fprintf(stderr, "Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
goto label; \
} \
} while (0);
@@ -136,13 +135,11 @@ static int wave_samplerate;

#define CHECK_CONNECTED_NO_RETVAL(id) \
do { \
if (!connected) { SHOW("CHECK_CONNECTED_NO_RETVAL: !pulse_connected\n", ""); return; } \
if (!connected) { return; } \
} while (0);

static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata)
{
ENTER(__FUNCTION__);

assert(c);

if (!stream ||
@@ -154,7 +151,6 @@ static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t

static void context_state_cb(pa_context *c, void *userdata)
{
ENTER(__FUNCTION__);
assert(c);

switch (pa_context_get_state(c))
@@ -174,7 +170,6 @@ static void context_state_cb(pa_context *c, void *userdata)

static void stream_state_cb(pa_stream *s, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

switch (pa_stream_get_state(s))
@@ -192,7 +187,6 @@ static void stream_state_cb(pa_stream *s, void *userdata)

static void stream_success_cb(pa_stream *s, int success, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

if (userdata)
@@ -203,7 +197,6 @@ static void stream_success_cb(pa_stream *s, int success, void *userdata)

static void context_success_cb(pa_context *c, int success, void *userdata)
{
ENTER(__FUNCTION__);
assert(c);

if (userdata)
@@ -214,7 +207,6 @@ static void context_success_cb(pa_context *c, int success, void *userdata)

static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

pa_threaded_mainloop_signal(mainloop, 0);
@@ -229,62 +221,51 @@ static void stream_latency_update_cb(pa_stream *s, void *userdata)

static int pulse_free(void)
{
ENTER(__FUNCTION__);
size_t l = 0;
pa_operation *o = NULL;

CHECK_CONNECTED(0);

SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop_lock");
pa_threaded_mainloop_lock(mainloop);
CHECK_DEAD_GOTO(fail, 1);

if ((l = pa_stream_writable_size(stream)) == (size_t)-1) {
SHOW("pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(context)));
l = 0;
goto fail;
}

SHOW("pulse_free: %s (ret=%d)\n", "pa_stream_writable_size", l);

/* If this function is called twice with no pulse_write() call in
* between this means we should trigger the playback */
if (do_trigger) {
int success = 0;

SHOW("pulse_free: %s (call)\n", "pa_stream_trigger");
if (!(o = pa_stream_trigger(stream, stream_success_cb, &success))) {
SHOW("pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context)));
goto fail;
}

SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop");
while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
CHECK_DEAD_GOTO(fail, 1);
pa_threaded_mainloop_wait(mainloop);
}
SHOW("pulse_free: %s (ret)\n", "pa_threaded_main_loop");

if (!success)
SHOW("pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context)));
}

fail:
SHOW("pulse_free: %s (call)\n", "pa_operation_unref");
if (o)
pa_operation_unref(o);

SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop_unlock");
pa_threaded_mainloop_unlock(mainloop);

do_trigger = !!l;
SHOW("pulse_free: %d (ret)\n", (int)l);
return (int)l;
}

static int pulse_playing(const pa_timing_info *the_timing_info)
{
ENTER(__FUNCTION__);
int r = 0;
const pa_timing_info *i;

@@ -300,7 +281,7 @@ static int pulse_playing(const pa_timing_info *the_timing_info)
if ((i = pa_stream_get_timing_info(stream)))
break;
if (pa_context_errno(context) != PA_ERR_NODATA) {
SHOW("pa_stream_get_timing_info() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_get_timing_info() failed: %s", pa_strerror(pa_context_errno(context)));
goto fail;
}

@@ -318,17 +299,13 @@ fail:

static void pulse_write(void *ptr, int length)
{
ENTER(__FUNCTION__);

SHOW("pulse_write > length=%d\n", length);

CHECK_CONNECTED_NO_RETVAL();

pa_threaded_mainloop_lock(mainloop);
CHECK_DEAD_GOTO(fail, 1);

if (pa_stream_write(stream, ptr, length, NULL, PA_SEEK_RELATIVE, (pa_seek_mode_t)0) < 0) {
SHOW("pa_stream_write() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_write() failed: %s", pa_strerror(pa_context_errno(context)));
goto fail;
}

@@ -344,45 +321,36 @@ static int drain(void)
int success = 0;
int ret = PULSE_ERROR;

ENTER(__FUNCTION__);

CHECK_CONNECTED(ret);

pa_threaded_mainloop_lock(mainloop);
CHECK_DEAD_GOTO(fail, 0);

SHOW_TIME("pa_stream_drain (call)");
if (!(o = pa_stream_drain(stream, stream_success_cb, &success))) {
SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
goto fail;
}

SHOW_TIME("pa_threaded_mainloop_wait (call)");
while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
CHECK_DEAD_GOTO(fail, 1);
pa_threaded_mainloop_wait(mainloop);
}
SHOW_TIME("pa_threaded_mainloop_wait (ret)");

if (!success)
SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
else
ret = PULSE_OK;
fail:
SHOW_TIME("pa_operation_unref (call)");
if (o)
pa_operation_unref(o);

pa_threaded_mainloop_unlock(mainloop);
SHOW_TIME("drain (ret)");

return ret;
}

static void pulse_close(void)
{
ENTER(__FUNCTION__);

drain();

connected = 0;
@@ -393,24 +361,19 @@ static void pulse_close(void)
connected = 0;

if (context) {
SHOW_TIME("pa_context_disconnect (call)");
pa_context_disconnect(context);
pa_context_unref(context);
context = NULL;
}

if (mainloop) {
SHOW_TIME("pa_threaded_mainloop_free (call)");
pa_threaded_mainloop_free(mainloop);
mainloop = NULL;
}
SHOW_TIME("pulse_close (ret)");

}

static int pulse_open()
{
ENTER(__FUNCTION__);
pa_sample_spec ss;
pa_operation *o = NULL;
int success;
@@ -430,51 +393,39 @@ static int pulse_open()
if (!pa_sample_spec_valid(&ss))
return false;

SHOW_TIME("pa_threaded_mainloop_new (call)");
if (!(mainloop = pa_threaded_mainloop_new())) {
SHOW("Failed to allocate main loop\n", "");
if (!(mainloop = pa_threaded_mainloop_new()))
goto fail;
}

pa_threaded_mainloop_lock(mainloop);

SHOW_TIME("pa_context_new (call)");
if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak"))) {
SHOW("Failed to allocate context\n", "");
if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak")))
goto unlock_and_fail;
}

pa_context_set_state_callback(context, context_state_cb, NULL);
pa_context_set_subscribe_callback(context, subscribe_cb, NULL);

SHOW_TIME("pa_context_connect (call)");
if (pa_context_connect(context, NULL, (pa_context_flags_t)0, NULL) < 0) {
SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
ret = PULSE_NO_CONNECTION;
goto unlock_and_fail;
}

SHOW_TIME("pa_threaded_mainloop_start (call)");
if (pa_threaded_mainloop_start(mainloop) < 0) {
SHOW("Failed to start main loop", "");
if (pa_threaded_mainloop_start(mainloop) < 0)
goto unlock_and_fail;
}

// Wait until the context is ready
SHOW_TIME("pa_threaded_mainloop_wait");
pa_threaded_mainloop_wait(mainloop);

if (pa_context_get_state(context) != PA_CONTEXT_READY) {
SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
ret = PULSE_NO_CONNECTION;
if (mainloop)
pa_threaded_mainloop_stop(mainloop);
goto unlock_and_fail;
}

SHOW_TIME("pa_stream_new");
if (!(stream = pa_stream_new(context, "unknown", &ss, NULL))) {
SHOW("Failed to create stream: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "Failed to create stream: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}

@@ -490,30 +441,26 @@ static int pulse_open()
a_attr.minreq = MINREQ;
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), NULL, NULL) < 0) {
SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}

// Wait until the stream is ready
SHOW_TIME("pa_threaded_mainloop_wait");
pa_threaded_mainloop_wait(mainloop);

if (pa_stream_get_state(stream) != PA_STREAM_READY) {
SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}

// Now subscribe to events
SHOW_TIME("pa_context_subscribe");
if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) {
SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}

success = 0;
SHOW_TIME("pa_threaded_mainloop_wait");
while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
CHECK_DEAD_GOTO(fail, 1);
pa_threaded_mainloop_wait(mainloop);
@@ -522,7 +469,7 @@ static int pulse_open()
pa_operation_unref(o);

if (!success) {
SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
fprintf(stderr, "pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
goto unlock_and_fail;
}

@@ -533,7 +480,6 @@ static int pulse_open()
connected = 1;

pa_threaded_mainloop_unlock(mainloop);
SHOW_TIME("pulse_open (ret true)");

return PULSE_OK;
unlock_and_fail:
@@ -544,28 +490,23 @@ unlock_and_fail:
fail:
if (ret == PULSE_NO_CONNECTION) {
if (context) {
SHOW_TIME("pa_context_disconnect (call)");
pa_context_disconnect(context);
pa_context_unref(context);
context = NULL;
}

if (mainloop) {
SHOW_TIME("pa_threaded_mainloop_free (call)");
pa_threaded_mainloop_free(mainloop);
mainloop = NULL;
}
} else
pulse_close();

SHOW_TIME("pulse_open (ret false)");

return ret;
}

void wave_flush(void *theHandler)
{
ENTER("wave_flush");
}

void wave_set_callback_is_output_enabled(t_wave_callback *cb)
@@ -575,8 +516,6 @@ void wave_set_callback_is_output_enabled(t_wave_callback *cb)

int wave_init(int srate)
{
ENTER("wave_init");

stream = NULL;
wave_samplerate = srate;

@@ -585,13 +524,11 @@ int wave_init(int srate)

void *wave_open(const char *the_api)
{
ENTER("wave_open");
return (void *)1;
}

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
ENTER("wave_write");
size_t bytes_to_write = theSize;
char *aBuffer = theMono16BitsWaveBuffer;

@@ -604,23 +541,18 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
while (1) {
if (my_callback_is_output_enabled
&& (0 == my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
theSize = 0;
goto terminate;
}

aTotalFreeMem = pulse_free();
if (aTotalFreeMem >= bytes_to_write) {
SHOW("wave_write > aTotalFreeMem(%d) >= bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write);
if (aTotalFreeMem >= bytes_to_write)
break;
}

// TBD: check if really helpful
if (aTotalFreeMem >= MAXLENGTH*2)
aTotalFreeMem = MAXLENGTH*2;

SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write);

// 500: threshold for avoiding too many calls to pulse_write
if (aTotalFreeMem > 500) {
pulse_write(aBuffer, aTotalFreeMem);
@@ -634,27 +566,21 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
pulse_write(aBuffer, bytes_to_write);
terminate:
pthread_mutex_unlock(&pulse_mutex);
SHOW("wave_write: theSize=%d", theSize);
SHOW_TIME("wave_write > LEAVE");
return theSize;
}

int wave_close(void *theHandler)
{
SHOW_TIME("wave_close > ENTER");
static int aStopStreamCount = 0;

// 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)");
if (aStopStreamCount != 1)
return 0;
}

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;
}
@@ -662,7 +588,6 @@ int wave_close(void *theHandler)
drain();

pthread_mutex_unlock(&pulse_mutex);
SHOW_TIME("wave_close (ret)");

aStopStreamCount = 0; // last action
return PULSE_OK;
@@ -670,18 +595,13 @@ int wave_close(void *theHandler)

int wave_is_busy(void *theHandler)
{
SHOW_TIME("wave_is_busy");

pa_timing_info a_timing_info;
int active = pulse_playing(&a_timing_info);
SHOW("wave_is_busy: %d\n", active);
return active;
}

void wave_terminate()
{
ENTER("wave_terminate");

int a_status;
pthread_mutex_t *a_mutex = NULL;
a_mutex = &pulse_mutex;
@@ -689,7 +609,6 @@ void wave_terminate()

pulse_close();

SHOW_TIME("unlock mutex");
a_status = pthread_mutex_unlock(a_mutex);
pthread_mutex_destroy(a_mutex);
}
@@ -698,7 +617,6 @@ uint32_t wave_get_read_position(void *theHandler)
{
pa_timing_info a_timing_info;
pulse_playing(&a_timing_info);
SHOW("wave_get_read_position > %lx\n", a_timing_info.read_index);
return a_timing_info.read_index;
}

@@ -706,7 +624,6 @@ uint32_t wave_get_write_position(void *theHandler)
{
pa_timing_info a_timing_info;
pulse_playing(&a_timing_info);
SHOW("wave_get_read_position > %lx\n", a_timing_info.write_index);
return a_timing_info.write_index;
}

@@ -714,10 +631,8 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{
double a_time = 0;

if (!time || !stream) {
SHOW("event get_remaining_time> %s\n", "audio device not available");
if (!time || !stream)
return -1;
}

pa_timing_info a_timing_info;
pulse_playing(&a_timing_info);
@@ -729,8 +644,6 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
} else
a_time = 0;

SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time);

*time = (uint32_t)a_time;

return 0;
@@ -827,7 +740,6 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)

uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) {
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;
}

+ 8
- 43
src/libespeak-ng/wave_sada.c View File

@@ -34,7 +34,6 @@
#include <sys/audioio.h>

#include "wave.h"
#include "debug.h"

enum { ONE_BILLION = 1000000000 };
#define SAMPLE_RATE 22050
@@ -77,8 +76,6 @@ static uint32_t wave_samplerate;
//
int wave_init(int srate)
{
ENTER("wave_init");

audio_info_t ainfo;
char *audio_device = NULL;

@@ -87,32 +84,29 @@ int wave_init(int srate)
audio_device = getenv("AUDIODEV");
if (audio_device != NULL) {
if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
audio_device, sun_audio_fd);
fprintf(stderr, "wave_init() could not open: %s (%d)\n",
audio_device, sun_audio_fd);
}
}

if (sun_audio_fd < 0) {
if ((sun_audio_fd = open(sun_audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
sun_audio_device, sun_audio_fd);
fprintf(stderr, "wave_init() could not open: %s (%d)\n",
sun_audio_device, sun_audio_fd);
}
}

SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);

if (sun_audio_fd < 0)
return 0;

ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size);
ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
ainfo.play.channels = 1;
ainfo.play.sample_rate = wave_samplerate;
ainfo.play.precision = SAMPLE_SIZE;

if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
SHOW("wave_init() failed to set audio params: %s\n", strerror(errno));
fprintf(stderr, "wave_init() failed to set audio params: %s\n", strerror(errno));
close(sun_audio_fd);
return 0;
}
@@ -143,7 +137,6 @@ int wave_init(int srate)
//
void *wave_open(const char *the_api)
{
ENTER("wave_open");
return (void *)sun_audio_fd;
}

@@ -178,11 +171,8 @@ size_t wave_write(void *theHandler,
size_t theSize)
{
size_t num;
ENTER("wave_write");
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled()))
return 0;
}

#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
// BIG-ENDIAN, swap the order of bytes in each sound sample
@@ -207,12 +197,6 @@ size_t wave_write(void *theHandler,
//
total_samples_sent += num / 2;

if (num < theSize)
SHOW("ERROR: wave_write only wrote %d of %d bytes\n", num, theSize);
else
SHOW("wave_write wrote %d bytes\n", theSize);

SHOW_TIME("wave_write > LEAVE");
return num;
}

@@ -248,10 +232,8 @@ int wave_close(void *theHandler)
int ret;
audio_info_t ainfo;
int audio_fd = (int)theHandler;
if (!audio_fd) {
if (!audio_fd)
audio_fd = sun_audio_fd;
}
ENTER("wave_close");
// [[[WDW: maybe do a pause/resume ioctl???]]]
ret = ioctl(audio_fd, I_FLUSH, FLUSHRW);
ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
@@ -265,7 +247,6 @@ int wave_close(void *theHandler)
last_play_position = ainfo.play.samples;
total_samples_skipped = total_samples_sent - last_play_position;
}
SHOW_TIME("wave_close > LEAVE");
return ret;
}

@@ -310,10 +291,8 @@ int wave_is_busy(void *theHandler)
//
void wave_terminate()
{
ENTER("wave_terminate");
close(sun_audio_fd);
sun_audio_fd = -1;
SHOW_TIME("wave_terminate > LEAVE");
}

// wave_flush
@@ -333,8 +312,6 @@ void wave_terminate()
//
void wave_flush(void *theHandler)
{
ENTER("wave_flush");
SHOW_TIME("wave_flush > LEAVE");
}

// wave_set_callback_is_output_enabled
@@ -392,10 +369,7 @@ void *wave_test_get_write_buffer()
uint32_t wave_get_read_position(void *theHandler)
{
audio_info_t ainfo;
ENTER("wave_get_read_position");
ioctl((int)theHandler, AUDIO_GETINFO, &ainfo);
SHOW("wave_get_read_position: %d\n", ainfo.play.samples);
SHOW_TIME("wave_get_read_position > LEAVE");
return ainfo.play.samples;
}

@@ -427,9 +401,6 @@ uint32_t wave_get_read_position(void *theHandler)
//
uint32_t wave_get_write_position(void *theHandler)
{
ENTER("wave_get_write_position");
SHOW("wave_get_write_position: %d\n", total_samples_sent);
SHOW_TIME("wave_get_write_position > LEAVE");
return total_samples_sent;
}

@@ -466,11 +437,8 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
uint32_t actual_index;

audio_info_t ainfo;
ENTER("wave_get_remaining_time");
if (!time) {
if (!time)
return -1;
SHOW_TIME("wave_get_remaining_time > LEAVE");
}

ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);

@@ -485,8 +453,6 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
*time = (uint32_t)a_time;
}
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time);
SHOW_TIME("wave_get_remaining_time > LEAVE");
return 0;
}

@@ -574,7 +540,6 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)

uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) {
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;
}

Loading…
Cancel
Save