Newbie to audio programming; using PortAudio to decode Ogg

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.

Hi Tatsh,

I’m facing the same problem…

Can you please suggest me what solution did you found?
Can you please provide a code snippet/sample application for the same.

Thank you.