mod_portaudio: initialize read/write endpoint timers per call
fix pablio multiplexing
This commit is contained in:
parent
739ff9d35a
commit
3814eb13df
|
@ -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;
|
||||
|
|
|
@ -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,21 +288,26 @@ 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);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
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);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
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) {
|
||||
/* If we are writing data, make sure we play everything written. */
|
||||
if (byteSize > 0) {
|
||||
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]);
|
||||
while (bytesEmpty < byteSize) {
|
||||
Pa_Sleep(10);
|
||||
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]);
|
||||
|
||||
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[c]);
|
||||
while (bytesEmpty < byteSize) {
|
||||
Pa_Sleep(10);
|
||||
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);
|
||||
|
|
|
@ -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(). */
|
||||
|
|
Loading…
Reference in New Issue