mod_portaudio: initialize read/write endpoint timers per call

fix pablio multiplexing
This commit is contained in:
Moises Silva 2011-03-19 23:43:40 -04:00
parent 739ff9d35a
commit 3814eb13df
3 changed files with 106 additions and 47 deletions

View File

@ -1136,6 +1136,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
}
if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint"))) {
int timer_ms = -1;
int samples_per_packet = -1;
audio_endpoint_t *endpoint = NULL;
char *endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
endpoint_name = strchr(endpoint_name, '/');
@ -1155,6 +1157,34 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
retcause = SWITCH_CAUSE_USER_BUSY;
goto error;
}
timer_ms = endpoint->in_stream ? endpoint->in_stream->codec_ms : endpoint->out_stream->codec_ms;
samples_per_packet = endpoint->in_stream ?
STREAM_SAMPLES_PER_PACKET(endpoint->in_stream) : STREAM_SAMPLES_PER_PACKET(endpoint->out_stream);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Setting up timer for endpoint '%s' with %dms and %d samples per packet\n", endpoint->name, timer_ms, samples_per_packet);
/* only setup read timer if we'll be reading */
if (endpoint->in_stream && switch_core_timer_init(&endpoint->read_timer,
globals.timer_name, timer_ms,
samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name);
switch_mutex_unlock(endpoint->mutex);
goto error;
}
/* The write timer must be setup regardless */
if (switch_core_timer_init(&endpoint->write_timer,
globals.timer_name, timer_ms,
samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name);
if (endpoint->in_stream) {
switch_core_timer_destroy(&endpoint->read_timer);
}
switch_mutex_unlock(endpoint->mutex);
goto error;
}
/* try to acquire the stream */
if (take_stream_channel(endpoint->in_stream, endpoint->inchan, 1)) {
switch_mutex_unlock(endpoint->mutex);
@ -1520,21 +1550,6 @@ static switch_status_t load_endpoints(switch_xml_t endpoints)
"Incomatible input and output streams for endpoint '%s'\n", endpoint_name);
continue;
}
if (switch_core_timer_init(&endpoint->read_timer,
globals.timer_name, endpoint->in_stream->codec_ms,
STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name);
continue;
}
if (switch_core_timer_init(&endpoint->write_timer,
globals.timer_name, endpoint->out_stream->codec_ms,
STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name);
continue;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
"Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name,
endpoint->in_stream ? endpoint->in_stream->name : "(none)",
@ -1642,14 +1657,6 @@ static switch_status_t load_config(void)
}
}
if ((streams = switch_xml_child(cfg, "streams"))) {
load_streams(streams);
}
if ((endpoints = switch_xml_child(cfg, "endpoints"))) {
load_endpoints(endpoints);
}
if (!globals.dialplan) {
set_global_dialplan("XML");
}
@ -1701,6 +1708,16 @@ static switch_status_t load_config(void)
}
}
/* streams and endpoints must be last, some initialization depend on globals defaults */
if ((streams = switch_xml_child(cfg, "streams"))) {
load_streams(streams);
}
if ((endpoints = switch_xml_child(cfg, "endpoints"))) {
load_endpoints(endpoints);
}
switch_xml_free(xml);
return status;

View File

@ -78,14 +78,23 @@ static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf);
static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
int c = 0, i = 0, j = 0;
PABLIO_Stream *data = (PABLIO_Stream *) userData;
long numBytes = data->bytesPerFrame * framesPerBuffer;
const int16_t *inputSamples = inputBuffer;
int16_t *chanSamples = (int16_t*)data->iobuff;
/* This may get called with NULL inputBuffer during initial setup. */
if (inputBuffer != NULL) {
if (PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes) != numBytes) {
PaUtil_FlushRingBuffer(&data->inFIFOs[0]);
PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes);
/* retrieve the data for each channel and put it in the ring buffer */
for (c = 0; c < data->channelCount; c++) {
for (i = 0, j = c; i < framesPerBuffer; j += data->channelCount, i++) {
chanSamples[i] = inputSamples[j];
}
if (PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes) != numBytes) {
PaUtil_FlushRingBuffer(&data->inFIFOs[c]);
PaUtil_WriteRingBuffer(&data->inFIFOs[c], inputBuffer, numBytes);
}
}
}
@ -97,13 +106,21 @@ static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
{
PABLIO_Stream *data = (PABLIO_Stream *) userData;
long numBytes = data->bytesPerFrame * framesPerBuffer;
int16_t *outputSamples = outputBuffer;
int16_t *chanSamples = (short *)data->iobuff;
int c = 0, i = 0, j = 0;
if (outputBuffer != NULL) {
int i;
int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[0], outputBuffer, numBytes);
/* Zero out remainder of buffer if we run out of data. */
for (i = numRead; i < numBytes; i++) {
((char *) outputBuffer)[i] = 0;
for (c = 0; c < data->channelCount; c++) {
int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[c], chanSamples, numBytes);
numRead = numRead / sizeof(int16_t);
for (i = 0, j = c; i < framesPerBuffer; j += data->channelCount, i++) {
if (i < numRead) {
outputSamples[j] = chanSamples[i];
} else {
outputSamples[j] = 0;
}
}
}
}
@ -251,6 +268,7 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
PABLIO_Stream *aStream;
long numFrames;
//long numBytes;
int c = 0;
int channels = 1;
if (!(inputParameters || outputParameters)) {
@ -270,22 +288,27 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
aStream->bytesPerFrame = bytesPerSample;
aStream->channelCount = channels;
/* Initialize Ring Buffers */
if (inputParameters) {
err = PABLIO_InitFIFO(&aStream->inFIFOs[0], numFrames, aStream->bytesPerFrame);
for (c = 0; c < channels; c++) {
err = PABLIO_InitFIFO(&aStream->inFIFOs[c], numFrames, aStream->bytesPerFrame);
if (err != paNoError) {
goto error;
}
}
aStream->has_in = 1;
}
if (outputParameters) {
err = PABLIO_InitFIFO(&aStream->outFIFOs[0], numFrames, aStream->bytesPerFrame);
for (c = 0; c < channels; c++) {
err = PABLIO_InitFIFO(&aStream->outFIFOs[c], numFrames, aStream->bytesPerFrame);
if (err != paNoError) {
goto error;
}
}
aStream->has_out = 1;
}
@ -353,17 +376,21 @@ PaError CloseAudioStream(PABLIO_Stream * aStream)
{
int bytesEmpty;
int byteSize;
int c = 0;
byteSize = aStream->outFIFOs[0].bufferSize;
if (aStream->has_out) {
for (c = 0; c < aStream->channelCount; c++) {
byteSize = aStream->outFIFOs[c].bufferSize;
/* If we are writing data, make sure we play everything written. */
if (byteSize > 0) {
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]);
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]);
while (bytesEmpty < byteSize) {
Pa_Sleep(10);
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]);
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]);
}
}
}
}
@ -399,11 +426,15 @@ PaError CloseAudioStream(PABLIO_Stream * aStream)
}
if (aStream->has_in) {
PABLIO_TermFIFO(&aStream->inFIFOs[0]);
for (c = 0; c < aStream->channelCount; c++) {
PABLIO_TermFIFO(&aStream->inFIFOs[c]);
}
}
if (aStream->has_out) {
PABLIO_TermFIFO(&aStream->outFIFOs[0]);
for (c = 0; c < aStream->channelCount; c++) {
PABLIO_TermFIFO(&aStream->outFIFOs[c]);
}
}
free(aStream);

View File

@ -56,7 +56,17 @@ extern "C" {
#include <string.h>
/*! Maximum number of channels per stream */
#define MAX_IO_CHANNELS 2
/*! Maximum numer of milliseconds per packet */
#define MAX_IO_MS 100
/*! Maximum sampling rate (48Khz) */
#define MAX_SAMPLING_RATE 48000
/* Maximum size of a read */
#define MAX_IO_BUFFER (((MAX_IO_MS * MAX_SAMPLING_RATE)/1000)*sizeof(int16_t))
typedef struct {
PaStream *istream;
PaStream *ostream;
@ -68,6 +78,7 @@ typedef struct {
PaUtilRingBuffer inFIFOs[MAX_IO_CHANNELS];
PaUtilRingBuffer outFIFOs[MAX_IO_CHANNELS];
int channelCount;
char iobuff[MAX_IO_BUFFER];
} PABLIO_Stream;
/* Values for flags for OpenAudioStream(). */