OpenAL Ogg Vorbis problem with C

Started by
9 comments, last by CoderGuy 18 years, 1 month ago
Hi everyone. I'm doing my program in C,SDL,OpenGL, and OpenAL using Ogg Vorbis for audio. Following Lesson 8 and converting it to C, I got a small Ogg file to play. I'm now trying to use a larger file and using Lesson 9 at devmaster.net so I can stream the Ogg files. When I use the function open in main, it plays a small ogg file, but when I use open2, it crashes. I know I have to use a malloc instead of new for "a.dataPtr = malloc(sizeof(sizeOfFile)); //new char[sizeOfFile];", but do it as a char. Here's the code.

#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <gl/glu.h>
#include <ogg/ogg.h>
#include <vorbis/vorbisfile.h>
#include <al/alut.h>
#include <al/al.h>
#include <al/alc.h>
#include <stdio.h>

#define BUFFER_SIZE 4096

void thisIsEmpty();
void doCheck();
char *errorString(int);
void open(char*);
void open2(char*);

FILE *fp;
char *oggFile = "Water.ogg";
OggVorbis_File oggStream;
vorbis_info*    vorbisInfo;
vorbis_comment* vorbisComment;
ALuint buffers[2];
//char* alBuffer; //data for the buffer
//ALenum alFormatBuffer; //for the buffer format
//ALsizei alFreqBuffer; //for the frequency of the buffer
//long alBufferLen; //the bit depth
//ALboolean alLoop; //looped
ALuint alSampleSet;
ALuint alSource; //buffer source
ALenum format;
ov_callbacks	vorbisCallbacks;
// Struct that contains the pointer to our file in memory
typedef struct SggFile
{
	char*		dataPtr;			// Pointer to the data in memoru
	int			dataSize;			// Sizeo fo the data

	int			dataRead;			// How much data we have read so far
}SOggFile;



size_t VorbisRead(void *ptr			/* ptr to the data that the vorbis files need*/, 
				  size_t byteSize	/* how big a byte is*/, 
				  size_t sizeToRead /* How much we can read*/, 
				  void *datasource	/* this is a pointer to the data we passed into ov_open_callbacks (our SOggFile struct*/)
{
	size_t				spaceToEOF;			// How much more we can read till we hit the EOF marker
	size_t				actualSizeToRead;	// How much data we are actually going to read from memory
	SOggFile*			vorbisData;			// Our vorbis data, for the typecast

	// Get the data in the right format
	vorbisData = (SOggFile*)datasource;

	// Calculate how much we need to read.  This can be sizeToRead*byteSize or less depending on how near the EOF marker we are
	spaceToEOF = vorbisData->dataSize - vorbisData->dataRead;
	if ((sizeToRead*byteSize) < spaceToEOF)
		actualSizeToRead = (sizeToRead*byteSize);
	else
		actualSizeToRead = spaceToEOF;	
	
	// A simple copy of the data from memory to the datastruct that the vorbis libs will use
	if (actualSizeToRead)
	{
		// Copy the data from the start of the file PLUS how much we have already read in
		memcpy(ptr, (char*)vorbisData->dataPtr + vorbisData->dataRead, actualSizeToRead);
		// Increase by how much we have read by
		vorbisData->dataRead += (actualSizeToRead);
	}

	// Return how much we read (in the same way fread would)
	return actualSizeToRead;
}

//---------------------------------------------------------------------------------
// Function	: VorbisSeek
// Purpose	: Callback for the Vorbis seek function
// Info		: 
//---------------------------------------------------------------------------------
int VorbisSeek(void *datasource		/*this is a pointer to the data we passed into ov_open_callbacks (our SOggFile struct*/, 
			   ogg_int64_t offset	/*offset from the point we wish to seek to*/, 
			   int whence			/*where we want to seek to*/)
{
	size_t				spaceToEOF;		// How much more we can read till we hit the EOF marker
	ogg_int64_t			actualOffset;	// How much we can actually offset it by
	SOggFile*			vorbisData;		// The data we passed in (for the typecast)

	// Get the data in the right format
	vorbisData = (SOggFile*)datasource;

	// Goto where we wish to seek to
	switch (whence)
	{
	case SEEK_SET: // Seek to the start of the data file
		// Make sure we are not going to the end of the file
		if (vorbisData->dataSize >= offset)
			actualOffset = offset;
		else
			actualOffset = vorbisData->dataSize;
		// Set where we now are
		vorbisData->dataRead = (int)actualOffset;
		break;
	case SEEK_CUR: // Seek from where we are
		// Make sure we dont go past the end
		spaceToEOF = vorbisData->dataSize - vorbisData->dataRead;
		if (offset < spaceToEOF)
			actualOffset = (offset);
		else
			actualOffset = spaceToEOF;	
		// Seek from our currrent location
		vorbisData->dataRead += actualOffset;
		break;
	case SEEK_END: // Seek from the end of the file
		vorbisData->dataRead = vorbisData->dataSize+1;
		break;
	default:
		printf("*** ERROR *** Unknown seek command in VorbisSeek\n");
		break;
	};

	return 0;
}

//---------------------------------------------------------------------------------
// Function	: VorbisClose
// Purpose	: Callback for the Vorbis close function
// Info		: 
//---------------------------------------------------------------------------------
int VorbisClose(void *datasource /*this is a pointer to the data we passed into ov_open_callbacks (our SOggFile struct*/)
{
	// This file is called when we call ov_close.  If we wanted, we could free our memory here, but
	// in this case, we will free the memory in the main body of the program, so dont do anything
	return 1;
}

//---------------------------------------------------------------------------------
// Function	: VorbisTell
// Purpose	: Classback for the Vorbis tell function
// Info		: 
//---------------------------------------------------------------------------------
long VorbisTell(void *datasource /*this is a pointer to the data we passed into ov_open_callbacks (our SOggFile struct*/)
{
	SOggFile*	vorbisData;

	// Get the data in the right format
	vorbisData = (SOggFile*)datasource;

	// We just want to tell the vorbis libs how much we have read so far
	return vorbisData->dataRead;
}


void open(char *path)
{
    int result;
    
    if(!(fp = fopen(path, "rb")))
        printf("Could not open Ogg file.");
    
    if((result = ov_open(fp, &oggStream, NULL, 0)) < 0)
    {
        fclose(fp);
        exit(0);
        fprintf(stderr,"Could not Open for playing!",SDL_GetError());
    }

    vorbisInfo = ov_info(&oggStream, -1);
    vorbisComment = ov_comment(&oggStream, -1);

    if(vorbisInfo->channels == 1)
        format = AL_FORMAT_MONO16;
    else
        format = AL_FORMAT_STEREO16;
        
    printf("this is just before the genbuffers!\n");   
    alGenBuffers(2, buffers);
    printf("this is just before the doCheck!\n");
    doCheck();
    printf("this is just after the doCheck!\n");
    alGenSources(1, &alSource);
    doCheck();
    
    alSource3f(alSource, AL_POSITION,        0.0, 0.0, 0.0);
    alSource3f(alSource, AL_VELOCITY,        0.0, 0.0, 0.0);
    alSource3f(alSource, AL_DIRECTION,       0.0, 0.0, 0.0);
    alSourcef (alSource, AL_ROLLOFF_FACTOR,  0.0          );
    alSourcei (alSource, AL_SOURCE_RELATIVE, AL_TRUE      );
}

void open2(char *path)
{



	/************************************************************************************************************************
		Heres a total bodge, just to get the file into memory.  Normally, the file would have been loaded into memory
		for a specific reason e.g. loading it from a pak file or similar.  I just want to get the file into memory for
		the sake of the tutorial.
	************************************************************************************************************************/

	FILE*   tempOggFile;
	int		sizeOfFile; 
	char	tempChar;
	int		tempArray;
    SOggFile a;
    
    printf("Before fopen\n");
    if(!(tempOggFile = fopen(path, "rb")))
        printf("Could not open Ogg file.");
        printf("AFter fopen\n");
	// Find out how big the file is
	sizeOfFile = 0;
	while (!feof(tempOggFile))
	{
		tempChar = getc(tempOggFile);
		sizeOfFile++;
	}

	// Save the data into memory
	printf("Before a.dataPtr\n");
	a.dataPtr = malloc(sizeof(sizeOfFile));    //new char[sizeOfFile];
    	printf("After a.dataPtr\n");
	rewind(tempOggFile);
	tempArray = 0;
	while (!feof(tempOggFile))
	{
		a.dataPtr[tempArray] = getc(tempOggFile);
		tempArray++;
	}

	// Close the ogg file
	fclose(tempOggFile);

	// Save the data in the ogg memory file because we need this when we are actually reading in the data
	// We havnt read anything yet
	a.dataRead = 0;
	// Save the size so we know how much we need to read
	a.dataSize = sizeOfFile;	

	/************************************************************************************************************************ 
		End of nasty 'just stick it in memory' bodge...
	************************************************************************************************************************/



	// This is really the only thing that is different from the original lesson 8 file...

	// Now we have our file in memory (how ever it got there!), we need to let the vorbis libs know how to read it
	// To do this, we provide callback functions that enable us to do the reading.  the Vorbis libs just want the result
	// of the read.  They dont actually do it themselves
	// Save the function pointersof our read files...
	vorbisCallbacks.read_func = VorbisRead;
	vorbisCallbacks.close_func = VorbisClose;
	vorbisCallbacks.seek_func = VorbisSeek;
	vorbisCallbacks.tell_func = VorbisTell;

	// Open the file from memory.  We need to pass it a pointer to our data (in this case our SOggFile structure),
	// a pointer to our ogg stream (which the vorbis libs will fill up for us), and our callbacks
	if (ov_open_callbacks(&a, &oggStream, NULL, 0, vorbisCallbacks) != 0)
		printf("Could not read Ogg file from memory");



	/************************************************************************************************************************
		From now on, the code is exactly the same as in Jesse Maurais's lesson 8
	************************************************************************************************************************/
    
    vorbisInfo = ov_info(&oggStream, -1);
    vorbisComment = ov_comment(&oggStream, -1);

    if(vorbisInfo->channels == 1)
        format = AL_FORMAT_MONO16;
    else
        format = AL_FORMAT_STEREO16;
        
        
    alGenBuffers(2, buffers);
    doCheck();
    alGenSources(1, &alSource);
    doCheck();
    
    alSource3f(alSource, AL_POSITION,        0.0, 0.0, 0.0);
    alSource3f(alSource, AL_VELOCITY,        0.0, 0.0, 0.0);
    alSource3f(alSource, AL_DIRECTION,       0.0, 0.0, 0.0);
    alSourcef (alSource, AL_ROLLOFF_FACTOR,  0.0          );
    alSourcei (alSource, AL_SOURCE_RELATIVE, AL_TRUE      );
}

void release()
{
    alSourceStop(alSource);
    thisIsEmpty();
    alDeleteSources(1, &alSource);
    doCheck();
    alDeleteBuffers(1, buffers);
    doCheck();

    ov_clear(&oggStream);
}
/*
void display()
{
    int i;
    
    printf("version         ", vorbisInfo->version);
    printf("\n");
    printf("channels        ", vorbisInfo->channels);
    printf("\n");  
    printf("rate (hz)       ", vorbisInfo->rate);
    printf("\n");   
    printf("bitrate upper   ", vorbisInfo->bitrate_upper);
    printf("\n"); 
    printf("bitrate nominal ", vorbisInfo->bitrate_nominal);
    printf("\n");
    printf("bitrate lower   ", vorbisInfo->bitrate_lower);
    printf("\n");
    printf("bitrate window  ", vorbisInfo->bitrate_window);
    printf("\n");
    printf("\n");
    printf("vendor ", vorbisComment->vendor);
    printf("\n");
        
    for(i = 0; i < vorbisComment->comments; i++)
    {
        printf("    ", vorbisComment->user_comments);
        printf("\n");
    }
    
    printf("\n");
}
*/

int playback()
{
    if(playing())
    {
        printf("it returns 1 at playback\n");
        //return 1;
    }   
        
    if(!stream(buffers[0]))
        return 0;
        
    if(!stream(buffers[1]))
        return 0;
    
    alSourceQueueBuffers(alSource, 2, buffers);
    printf("just before the alSourcePlay!\n");
    alSourcePlay(alSource);
    printf("just after the alSourcePlay!\n");
    
    return 1;
}

int playing()
{
    ALenum state;
    //printf("I should be playing now!\n");
    alGetSourcei(alSource, AL_SOURCE_STATE, &state);
    //printf("This is the state: %d\n\n", state);
    if(state == AL_PLAYING)
    {
        //printf("this is playing\n");
        return 1;
    }
    else
    {
        printf("I am not playing...\n");
        
    }
    return 0;
}

int update()
{
    int processed;
    int active = 1;

    alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
    doCheck();
    
    while(processed--)
    {
        ALuint buffer;
        
        alSourceUnqueueBuffers(alSource, 1, &buffer);
        doCheck();

        active = stream(buffer);
        doCheck();
        
        alSourceQueueBuffers(alSource, 1, &buffer);
        doCheck();
    }

    return active;
}

int stream(ALuint buffer)
{
    char pcm[BUFFER_SIZE];
    int  size = 0;
    int  section;
    int  result;

    while(size < BUFFER_SIZE)
    {
        result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, &section);
    
        if(result > 0)
            size += result;
        else
            if(result < 0)
                printf("%s", errorString(result));
            else
                break;
    }
    
    if(size == 0)
        return 0;
        
    alBufferData(buffer, format, pcm, size, vorbisInfo->rate);
    doCheck();
    
    return 1;
}

void thisIsEmpty()
{
    int queued;
    
    alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
    
    while(queued--)
    {
        ALuint buffer;
    
        alSourceUnqueueBuffers(alSource, 1, &buffer);
        doCheck();
    }
}

void doCheck()
{
	int error = alGetError();

	if(error != AL_NO_ERROR)
		printf("OpenAL error was raised. %d\n",error);
}

char *errorString(int code)
{
    char *stringError = "";
    switch(code)
    {
        case OV_EREAD:
            stringError = "Read from media.";
        case OV_ENOTVORBIS:
            stringError = "Not Vorbis data.";
        case OV_EVERSION:
            stringError = "Vorbis version mismatch.";
        case OV_EBADHEADER:
            stringError = "Invalid Vorbis header.";
        case OV_EFAULT:
            stringError = "Internal logic fault (bug or heap/stack corruption.";
        default:
            stringError = "Unknown Ogg error.";
    }
    return stringError;
}
    
int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_SetVideoMode(800, 600, 0, SDL_OPENGL | SDL_HWSURFACE );
    

    SDL_Event event;
    SDL_Rect showRect;
    SDL_Surface *screen;

    
    ALCcontext *Context;
    ALCdevice *Device;

    Device = alcOpenDevice((ALubyte*)"DirectSound3D");
    //Device = alcOpenDevice((ALubyte*)"DirectSound3D");
    
    if (Device == NULL)
    {
        printf("this isn't working!");
        exit(-1);
    }

    printf("device is not null!\n");
    
    //Create context(s)
    Context=alcCreateContext(Device,NULL);

    //Set active context
    alcMakeContextCurrent(Context);

    // Clear Error Code
    alGetError();

    open(oggFile);

    //display();
    
    //play the sound
    if(!playback())
            printf("Ogg refused to play.\n");
    //playback(); 
    
    while(update())
    {
        while(SDL_PollEvent(&event))
        {
            switch( event.type )
            {
                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym)
                    {
                        case SDLK_ESCAPE:
                        break;
                    }
                break;
                
                case SDL_QUIT:
                   exit (0);
                   break;
            }
            
        }
        if(!playing())
        {
            if(!playback())
                fprintf(stderr,"Ogg abruptly stopped.\n",SDL_GetError());
            else
                fprintf(stderr,"Ogg stream was interrupted.\n",SDL_GetError());
        }
        
    }
        
    release();
    
    #if 1
    //delete our source
    /*alDeleteSources(1,&alSource);
    
    //delete our buffer
    alDeleteBuffers(1,&alSampleSet);*/
    
    //Get active context
    Context=alcGetCurrentContext();
    
    //Get device for active context
    Device=alcGetContextsDevice(Context);
    
    //Disable context
    alcMakeContextCurrent(NULL);
    
    //Release context(s)
    alcDestroyContext(Context);
    
    //Close device
    alcCloseDevice(Device);
    #endif

    SDL_Quit();   
   
    return(0);
}





[Edited by - CoderGuy on February 28, 2006 9:41:33 PM]
Advertisement
First thing that jumps out is that your malloc is wrong:-

(sizeof(sizeOfFile)) give yous the size of the variable (i.e. 4 bytes), not the contents of the variable.

remove the sizeof and it should be ok,

Paul
Ah, thanks for noticing that. I changed it to a.dataPtr = (char *)malloc(sizeOfFile), but now I hear the ogg file, and it plays just for a second and then I get a segmentation fault.
I thought there was an issue with the devmaster articles not working for larger files. Also you don't want the size of the file as its compressed? Just go nuts an allocate a few megs of RAM to test it.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Standard stuff:-
Do you have the callstack? What is it?
What is the actual error/exception message?

Paul
Error message:
Fatal signal: Segmentation Fault (SDL Parachute Deployed)

I changed the buffer size to be 1031072 now, but still nothing.

I do have the callstack, it's in the open2 function.

But where exactly in the open2 function?, the callstack should give you the exact location (down to the assembly memory address) of where the error occured.

And based on that assembly memory address it should tell you why it caused it to crash i.e. unaligned memory access, access to a NULL pointer and so forth.

If you can supply that info it would help us a lot

Paul
I did printf statements at the end of each callback function like

size_t VorbisRead(void *ptr			/* ptr to the data that the vorbis files need*/, 				  size_t byteSize	/* how big a byte is*/, 				  size_t sizeToRead /* How much we can read*/, 				  void *datasource	/* this is a pointer to the data we passed into ov_open_callbacks (our SOggFile struct*/){	size_t				spaceToEOF;			// How much more we can read till we hit the EOF marker	size_t				actualSizeToRead;	// How much data we are actually going to read from memory	SOggFile*			vorbisData;			// Our vorbis data, for the typecast	// Get the data in the right format	vorbisData = (SOggFile*)datasource;	// Calculate how much we need to read.  This can be sizeToRead*byteSize or less depending on how near the EOF marker we are	spaceToEOF = vorbisData->dataSize - vorbisData->dataRead;	if ((sizeToRead*byteSize) < spaceToEOF)		actualSizeToRead = (sizeToRead*byteSize);	else		actualSizeToRead = spaceToEOF;			// A simple copy of the data from memory to the datastruct that the vorbis libs will use	if (actualSizeToRead)	{		// Copy the data from the start of the file PLUS how much we have already read in		memcpy(ptr, (char*)vorbisData->dataPtr + vorbisData->dataRead, actualSizeToRead);		// Increase by how much we have read by		vorbisData->dataRead += (actualSizeToRead);	}	// Return how much we read (in the same way fread would)         printf("Reached end of VorbisRead\n");	return actualSizeToRead;}


which when ran, each function was reached.
? umm sorry I don't quite udnerstand, I mean does the debugger that you are running have the ability to show you the current callstack of the code when it crashed?

i.e.

callstack

Paul
Are you using the latest ogg/vorbis libs from xiph.org?

I had the same error message you did whenever I tried to call ov_open. Then it would blow up.

In the end I had to build the ogg/vorbis libs to match the runtime of the library I'm dropping them into (multithreaded DLL)..

hth,

This topic is closed to new replies.

Advertisement