Skip to content

Commit

Permalink
Callback-based sound system access
Browse files Browse the repository at this point in the history
  • Loading branch information
ondracek-lukas committed Mar 3, 2021
1 parent 8e3c71a commit 02be569
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 114 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -15,9 +15,9 @@ server: server.c *.h
gcc $< -o $@ $(CFLAGS) $(LDFLAGS) $(LDFLAGS-client)

%32.exe: %.c *.h
i686-w64-mingw32-gcc $< -o $@ -mthreads -lws2_32 $(LDFLAGS) $(LDFLAGS-client)
i686-w64-mingw32-gcc $< -o $@ -mthreads -lws2_32 $(LDFLAGS) $(LDFLAGS-client) -Lportaudio -Iportaudio/include
%64.exe: %.c *.h
x86_64-w64-mingw32-gcc $< -o $@ -mthreads -lws2_32 $(LDFLAGS) $(LDFLAGS-client)
x86_64-w64-mingw32-gcc $< -o $@ -mthreads -lws2_32 $(LDFLAGS) $(LDFLAGS-client) -Lportaudio -Iportaudio/include

clean:
rm -f client server client32.exe client64.exe
4 changes: 2 additions & 2 deletions audioBuffer.h
Expand Up @@ -242,7 +242,7 @@ sample_t *bufferReadNext(struct audioBuffer *buf) {
}

// tmpData[i] = retData[i] * bufferFade(i); XXX
bool bufferWrite(struct audioBuffer *buf, bindex_t pos, sample_t *data, bool add) { // TODO fadeIn, fadeOut
bool bufferWrite(struct audioBuffer *buf, bindex_t pos, const sample_t *data, bool add) { // TODO fadeIn, fadeOut
if (buf->writeLastPos < pos) {
do {
buf->blockState[++buf->writeLastPos % BUFFER_BLOCKS] = BLOCK_EMPTY;
Expand All @@ -269,7 +269,7 @@ bool bufferWrite(struct audioBuffer *buf, bindex_t pos, sample_t *data, bool add
return true;
}

bool bufferWriteNext(struct audioBuffer *buf, sample_t *data, bool add) {
bool bufferWriteNext(struct audioBuffer *buf, const sample_t *data, bool add) {
return bufferWrite(buf, buf->writeLastPos + 1, data, add);
}

Expand Down
30 changes: 8 additions & 22 deletions audioIO.h
Expand Up @@ -10,7 +10,7 @@
#include <pa_win_wasapi.h>
#endif

bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {
bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream, bool forceDefault, PaStreamCallback *inputCallback, PaStreamCallback *outputCallback) {
PaError err;


Expand All @@ -23,7 +23,7 @@ bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {
.size = sizeof(PaWasapiStreamInfo),
.hostApiType = paWASAPI,
.version = 1,
.flags = paWinWasapiExclusive | paWinWasapiThreadPriority,
.flags = paWinWasapiExclusive | paWinWasapiThreadPriority | paWinWasapiExplicitSampleFormat | paWinWasapiPolling,
.channelMask = 0,
.hostProcessorOutput = NULL,
.hostProcessorInput = NULL,
Expand All @@ -33,8 +33,8 @@ bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {
struct {} wasapiInfo;
#endif

printf("[space] default settings [c] custom settings\n");
if (ttyReadKey() != 'c') {
if (!forceDefault) printf("[space] default settings [c] custom settings\n");
if (forceDefault || (ttyReadKey() != 'c')) {
inputIndex = Pa_GetDefaultInputDevice();
outputIndex = Pa_GetDefaultOutputDevice();
inputSuggLat = 0;
Expand Down Expand Up @@ -105,19 +105,17 @@ bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {

}



const PaStreamParameters inputParameters = {
.device = inputIndex,
.channelCount = 2,
.sampleFormat = paInt16,
.suggestedLatency = inputSuggLat/1000,
.suggestedLatency = 0,
.hostApiSpecificStreamInfo = (useWasapiExclusive ? &wasapiInfo : NULL)};

err = Pa_OpenStream( paInputStream,
&inputParameters, NULL,
SAMPLE_RATE, MONO_BLOCK_SIZE, paNoFlag,
NULL, NULL);
inputCallback, NULL);

if (err != paNoError) {
printf("%s\n", Pa_GetErrorText(err));
Expand All @@ -128,13 +126,13 @@ bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {
.device = outputIndex,
.channelCount = 2,
.sampleFormat = paInt16,
.suggestedLatency = outputSuggLat/1000,
.suggestedLatency = 0,
.hostApiSpecificStreamInfo = (useWasapiExclusive ? &wasapiInfo : NULL)};

err = Pa_OpenStream( paOutputStream,
NULL, &outputParameters,
SAMPLE_RATE, MONO_BLOCK_SIZE, paNoFlag,
NULL, NULL);
outputCallback, NULL);

if (err != paNoError) {
printf("%s\n", Pa_GetErrorText(err));
Expand All @@ -146,18 +144,6 @@ bool aioConnectAudio(PaStream **paInputStream, PaStream **paOutputStream) {
Pa_StartStream(*paInputStream);


/*
{
const PaStreamInfo *inputStreamInfo = Pa_GetStreamInfo(*paInputStream);
const PaStreamInfo *outputStreamInfo = Pa_GetStreamInfo(*paOutputStream);
printf("\ninput latency: %f ms\noutput latency: %f ms\ninput sample rate: %f\noutput sample rate: %f\n\n",
inputStreamInfo->inputLatency * 1000,
outputStreamInfo->outputLatency * 1000,
inputStreamInfo->sampleRate,
outputStreamInfo->sampleRate);
}
*/
return true;
}

Expand Down
178 changes: 91 additions & 87 deletions client.c
Expand Up @@ -18,7 +18,7 @@
struct stereoBuffer outputBuffer;
PaStream *paInputStream = NULL, *paOutputStream = NULL;
int udpSocket = -1;
pthread_t inputThread, outputThread, udpThread;
pthread_t udpThread;
uint8_t clientID;
float aioLat = 0;
float dBAdj = 20;
Expand Down Expand Up @@ -51,106 +51,115 @@ volatile enum udpState {
UDP_CLOSED
} udpState;

static void *outputWorker(void *none) {
while (outputMode != OUTPUT_END) {
__sync_synchronize();
sample_t *blockStereo = NULL;
if (outputMode == OUTPUT_NULL) {
blockStereo = sbufferRead(&outputBuffer, 0, true, true);
} else {
blockStereo = sbufferReadNext(&outputBuffer);

int outputCallback(const sample_t *input, sample_t *output, unsigned long frameCount, PaStreamCallbackTimeInfo *timeinfo, PaStreamCallbackFlags statusFlags, void *userData) {
sample_t *blockStereo;
__sync_synchronize();
if (frameCount != MONO_BLOCK_SIZE) {
printf("Error: Wrong output frameCount %d\n", frameCount);
exit(1);
}
if ((outputMode == OUTPUT_NULL) || (outputMode == OUTPUT_END)) {
blockStereo = sbufferRead(&outputBuffer, 0, true, true);
} else {
blockStereo = sbufferReadNext(&outputBuffer);
}
memcpy(output, blockStereo, STEREO_BLOCK_SIZE * sizeof(sample_t));

// Pa_WriteStream(paOutputStream, blockStereo, MONO_BLOCK_SIZE);
if ((outputMode == OUTPUT_PASS_STAT) && (outputBuffer.readPos % BLOCKS_PER_STAT == 0)) {
float dBAvg, dBPeak;
sbufferOutputStats(&outputBuffer, &dBAvg, &dBPeak);
if (dBAvg + dBAdj > -20) {
dBAdj = -20 - dBAvg;
}
Pa_WriteStream(paOutputStream, blockStereo, MONO_BLOCK_SIZE);
if ((outputMode == OUTPUT_PASS_STAT) && (outputBuffer.readPos % BLOCKS_PER_STAT == 0)) {
float dBAvg, dBPeak;
sbufferOutputStats(&outputBuffer, &dBAvg, &dBPeak);
if (dBAvg + dBAdj > -20) {
dBAdj = -20 - dBAvg;
}

char str[200];
char *s = str;
char str[200];
char *s = str;

s += sprintf(s, "%-22s ", "system level:");
ttyFormatSndLevel(&s, dBAvg, dBPeak);
*s++ = '\n';
s += sprintf(s, "%-22s ", "adjusted level:");
ttyFormatSndLevel(&s, dBAvg + dBAdj, dBPeak + dBAdj);
s += sprintf(s, "%-22s ", "system level:");
ttyFormatSndLevel(&s, dBAvg, dBPeak);
*s++ = '\n';
s += sprintf(s, "%-22s ", "adjusted level:");
ttyFormatSndLevel(&s, dBAvg + dBAdj, dBPeak + dBAdj);

ttyResetStatus();
ttyUpdateStatus(str, 0);
ttyPrintStatus();
}
ttyResetStatus();
ttyUpdateStatus(str, 0);
ttyPrintStatus();
}
return NULL;
return outputMode == OUTPUT_END ? paComplete : paContinue;
}

static void *inputWorker(void *none) {
bindex_t blockIndex = 0;
enum inputMode lastMode = INPUT_END;
struct packetClientData packet = {};
int inputCallback(const sample_t *blockStereo, const sample_t *output, unsigned long frameCount, PaStreamCallbackTimeInfo *timeinfo, PaStreamCallbackFlags statusFlags, void *userData) {
static bindex_t blockIndex = 0;
static enum inputMode lastMode = INPUT_END;
static struct packetClientData packet = {};
packet.type = PACKET_DATA;
sample_t *blockMono = packet.block;
sample_t blockStereo[STEREO_BLOCK_SIZE];

while (inputMode != INPUT_END) {
Pa_ReadStream(paInputStream, blockStereo, MONO_BLOCK_SIZE);
for (size_t i = 0; i < MONO_BLOCK_SIZE; i++) {
blockMono[i] = blockStereo[2 * i];
}
if (inputMode != lastMode) {
__sync_synchronize();
switch (inputMode) {
case INPUT_TO_OUTPUT:
//sbufferClear(&outputBuffer, 0);
break;
case INPUT_MEASURE_LATENCY:
//sbufferClear(&outputBuffer, 0);
aioLatReset();
break;
case INPUT_SEND:
if (lastMode != INPUT_SEND_MUTE) {
blockIndex = 0;
packet.clientID = clientID;
}
break;
default: break;
}
lastMode = inputMode;
}
if (frameCount != MONO_BLOCK_SIZE) {
printf("Error: Wrong input frameCount %d\n", frameCount);
exit(1);
}

// Pa_ReadStream(paInputStream, blockStereo, MONO_BLOCK_SIZE);
for (size_t i = 0; i < MONO_BLOCK_SIZE; i++) {
blockMono[i] = blockStereo[2 * i];
}
if (inputMode != lastMode) {
__sync_synchronize();
switch (inputMode) {
case INPUT_SEND:
packet.blockIndex = blockIndex++;
packet.playBlockIndex = outputBuffer.readPos;
send(udpSocket, (void *)&packet, sizeof(packet), 0);
break;
case INPUT_TO_OUTPUT:
sbufferWriteNext(&outputBuffer, blockStereo, false);
//sbufferClear(&outputBuffer, 0);
break;
case INPUT_MEASURE_LATENCY:
//sbufferClear(&outputBuffer, 0);
aioLatReset();
break;
case INPUT_NULL_TO_OUTPUT:
case INPUT_SEND:
if (lastMode != INPUT_SEND_MUTE) {
blockIndex = 0;
packet.clientID = clientID;
}
break;
default: break;
}
lastMode = inputMode;
}
switch (inputMode) {
case INPUT_SEND:
packet.blockIndex = blockIndex++;
packet.playBlockIndex = outputBuffer.readPos;
send(udpSocket, (void *)&packet, sizeof(packet), 0);
break;
case INPUT_TO_OUTPUT:
sbufferWriteNext(&outputBuffer, blockStereo, false);
break;
case INPUT_NULL_TO_OUTPUT:
{
sample_t blockStereo[STEREO_BLOCK_SIZE];
memset(blockStereo, 0, sizeof(sample_t) * STEREO_BLOCK_SIZE);
sbufferWriteNext(&outputBuffer, blockStereo, false);
break;
case INPUT_MEASURE_LATENCY:
aioLatBlock(blockMono, outputBuffer.writeLastPos + 1 - outputBuffer.readPos);
}
break;
case INPUT_MEASURE_LATENCY:
aioLatBlock(blockMono, outputBuffer.writeLastPos + 1 - outputBuffer.readPos);
{
sample_t blockStereo[STEREO_BLOCK_SIZE];
for (size_t i = 0; i < MONO_BLOCK_SIZE; i++) {
blockStereo[2 * i] = blockStereo[2 * i + 1] = blockMono[i];
}
sbufferWriteNext(&outputBuffer, blockStereo, false);
break;
case INPUT_DISCARD:
case INPUT_SEND_MUTE:
case INPUT_END:
break;
}
__sync_synchronize();
/*
if (blockIndex % 1000 == 999) {
sbufferPrintStats(&outputBuffer);
}
*/
}
break;
case INPUT_DISCARD:
case INPUT_SEND_MUTE:
case INPUT_END:
break;
}
return NULL;
__sync_synchronize();

return inputMode == INPUT_END ? paAbort : paContinue;
}

static void *udpReceiver(void *none) {
Expand Down Expand Up @@ -294,10 +303,7 @@ int main() {
"and set sampling rate of both microphone and headphones to " STR(SAMPLE_RATE) " Hz.\n\n");
#endif
sbufferClear(&outputBuffer, 0);
aioConnectAudio(&paInputStream, &paOutputStream);

pthread_create(&inputThread, NULL, &inputWorker, NULL);
pthread_create(&outputThread, NULL, &outputWorker, NULL);
aioConnectAudio(&paInputStream, &paOutputStream, false, (PaStreamCallback *) &inputCallback, (PaStreamCallback *) &outputCallback);

printf("\n== 2/4 == MEASURE DELAY OF SOUND SYSTEM =======================================\n\n");

Expand Down Expand Up @@ -492,8 +498,6 @@ int main() {
// terminate
inputMode = INPUT_END;
outputMode = OUTPUT_END;
pthread_join(inputThread, NULL);
pthread_join(outputThread, NULL);
pthread_join(udpThread, NULL);
Pa_StopStream(paInputStream);
Pa_StopStream(paOutputStream);
Expand Down
2 changes: 1 addition & 1 deletion main.h
Expand Up @@ -3,7 +3,7 @@
#define _GNU_SOURCE

#define PROT_VERSION 4
#define APP_VERSION 1.0
#define APP_VERSION 1.1
#define UDP_PORT 64199
#define NAME_LEN 10
#define MAX_CLIENTS 100
Expand Down

0 comments on commit 02be569

Please sign in to comment.