I am working on something part of a much larger project but to make things easier I want to make a simple CLI program that takes argv[1] and plays the file using PortAudio as the playback library and the necessary library to decode the file. In this case, it is Vorbis.
I have written the code as close to the PortAudio tutorials say to do so but I do not want to generate tones or anything, just play what is in the buffer until EOF of the Ogg file. I have no idea what to pass to PortAudio in order to make audio output. And I am very new to concepts like FIFO and ring buffer.
My current code for this app is here:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <vorbis/vorbisfile.h>
#define INPUTCHANNELS 0
#define BYTES_TO_READ 4096
typedef struct {
struct OggVorbis_File file;
struct vorbis_info *info;
double length;
} oggStructure;
oggStructure data;
int oggCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData ) {
oggStructure *data = (oggStructure*)userData;
float *out = (float*)outputBuffer;
unsigned long i;
int finished = 0;
(void)inputBuffer;
for ( i = 0; i < framesPerBuffer; i++ ) {
}
return finished;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <ogg file>n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *ogg;
bool streamFailure = false;
char *buffer;
int bitstream = 0;
long bytesRead;
PaError err; /* PortAudio types */
PaStream *stream;
if ((err = Pa_Initialize()) != paNoError) {
fprintf(stderr, "Pa_Initialize() returned an error: %sn", Pa_GetErrorText(err));
exit(EXIT_FAILURE);
}
ogg = fopen(argv[1], "rb");
if (ov_open(ogg, &data.file, NULL, 0) < 0) {
fprintf(stderr, "Error decoding %s.n", argv[1]);
exit(EXIT_FAILURE);
}
data.info = ov_info(&data.file, -1); /* Information about Ogg file */
data.length = ov_time_total(&data.file, -1);
#ifdef __DEBUG__
fprintf(stdout, "Ogg filename: %sn", argv[1]);
fprintf(stdout, "Sample rate: %ldn", data.info->rate);
fprintf(stdout, "Number of channels: %dn", data.info->channels);
fprintf(stdout, "Lenght: %f secondsn", data.length);
#endif
ov_pcm_seek(&data.file, 0);
#ifdef __DEBUG__
fprintf(stdout, "Seeked file to position 0.n");
#endif
while (bytesRead != 0 && bitstream == 0) {
bytesRead = ov_read(&data.file, buffer, BYTES_TO_READ, 0, 2, 1, &bitstream);
if (bytesRead < 0) {
fprintf(stderr, "Error reading file.n");
break;
}
}
err = Pa_OpenDefaultStream(&stream, INPUTCHANNELS, data.info->channels, paFloat32, data.info->rate, BYTES_TO_READ, oggCallback, &data);
if (err != paNoError) {
fprintf(stderr, "Pa_OpenDefaultStream() returned an error: %sn", Pa_GetErrorText(err));
streamFailure = true;
}
ov_clear(&data.file);
if (streamFailure)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
If you use gcc, you can compile with:
gcc -g -D__DEBUG__ -o portogg -Wall -ansi -lvorbisfile -lportaudio portogg.c
or similar.
Any help would be appreciated greatly.