Problem Streaming OGG using OpenAL in C++

TooMad
Unregistered
 
Post: #1
From what I can tell it is reading in the pcm data to the buffer correctly so I think the problem exists in the way I am handling the buffer after that. The first post is the file loading code I don't believe the problem exists there but it could.

Code:
void WAudio::PlaySoundTrack(u16 volumeGroup)
{
    gSoundTrackGroup = volumeGroup;

    // Don't load the soundtrack if it is already playing
    if(!gSoundTrackSound)
    {
        DELETE_PTR(gSoundTrackSound);
        if (gSoundTrackSource)
        {
            ReleaseSource(gSoundTrackSource);
        }
        char fName[WFILE_MAX_PATH_NAME];
        gSoundTrackSource = LoadSoundFromFile(gSoundTrackList[gTrackNum], STREAMING, SOUND_NOT3D, fName);
        gSoundTrackSound =  NewSound(gSoundTrackSource, fName);
        //gSoundTrackSound->SetStreaming(true);
        gSoundTrackSound->volumeGroup = volumeGroup;
        gSoundTrackSound->SetIsLooped(true);

        //    STT - added this line, which may have been fine in Murphy but broke kaloki.
        //    I'm disabling this for now.  Maybe later figure out where exactly he did the ramp up?
        //    see comment above.
        gSoundTrackSound->SetVolume(0);                        // ramp volume up later
        gSoundTrackSound->Play();
    }
    gSoundTrackSound->SetVolume(100);
    gSoundTrackSound->Play();
}


// The loading code
WtSoundSource WAudio::LoadSoundFromFile(char *strWaveFileName, u16 streaming, u16 sound3D,
        char* fName)
{
    SoundBufferInfo*    sourceBuffer;

    // see if we've loaded this one already
    sourceBuffer = (SoundBufferInfo *)GetSourceFromName(strWaveFileName);
    if (sourceBuffer != INVALID_SOURCE)
    {
        return((WtSoundSource)sourceBuffer);
    }

    CHECK_AL_ERROR("preloadwav");
    /// Dprintf("WAudio::LoadSoundFromFile  Source: %s\n", strWaveFileName);

    //    make new buffer
    sourceBuffer = (SoundBufferInfo *)WMALLOC(sizeof(SoundBufferInfo));
    sourceBuffer->loop = false;
    sourceBuffer->is3D = 0;
    
    // Streaming needs 2 buffers to work
    if(!streaming)
    {
        sourceBuffer->buffer = (ALuint*)WMALLOC(sizeof(ALuint));
        sourceBuffer->numBuffers = 1;
    }
    else
    {
        sourceBuffer->buffer = (ALuint*)WMALLOC(2 * sizeof(ALuint));
        sourceBuffer->numBuffers = 2;
    }

    int format;

    if (strWaveFileName==NULL || strWaveFileName[0] == 0)
    {
        return(INVALID_SOURCE);
    }

    
    ASSERT(strlen(strWaveFileName) < MAX_SOUND_FILE_NAME);
    strcpy(sourceBuffer->fileName, strWaveFileName);    //    store original unmodified name
    alGenBuffers(sourceBuffer->numBuffers, sourceBuffer->buffer);
    
    // Copy buffer[1] into buffer[0] for streaming to work
    CHECK_AL_ERROR("initial buffer");

    char    fileName[WFILE_MAX_PATH_NAME];
    // Since we are not using the wfile system, we need to set a bit of the path ourselves.
    #ifdef WTARGET_OS_MAC_X
    extern char* gMacFilePath;
    strcpy(fileName, gMacFilePath);
    #else
    strcpy(fileName, W_DATA_PATH);
    #endif
    strcat(fileName, "/");
    strcat(fileName, strWaveFileName);
    // See if the file has an extension, if not, add .ogg
    // Note: This will probably need to be ifdefed for other platforms
    // We also used to have .wav(e) support, but ogg is better :)


    char *ext = WStringUtils::GetDotExtension(fileName);
    if(fName)
        strncpy(fName, fileName, 256);

    if (!ext)
    {
        strcat(fileName, ".wave");            // tack it on to the end if it doesn't have it
        format = WAV_FILE;
    }
    else if (strcmp(ext, ".wave") == 0)
    {
        format = WAV_FILE;
    }
    else if (strcmp(ext, ".ogg") == 0)
    {
        format = OGG_FILE;
    }
    else// if (strcmp(ext, ".gom") == 0)
    {
        format = OGG_FILE;
    }
    
    if (format == WAV_FILE)
    {
        // --Scott -For some annoying reason, the PC version of this call takes a loop argument, and the mac version
        // does not.  Sheesh.
    #ifdef WTARGET_OS_MAC_X
        alutLoadWAVFile(fileName, &sourceBuffer->format, &sourceBuffer->data, &sourceBuffer->size, &sourceBuffer->freq);
    #else
        alutLoadWAVFile(fileName, &sourceBuffer->format, &sourceBuffer->data, &sourceBuffer->size, &sourceBuffer->freq, &sourceBuffer->loop);
    #endif
    }
    else// if (format == OGG_FILE)
    {    // ogg vorbis data.
        if(!streaming)
            LoadOGGFile(fileName, &sourceBuffer->format, &sourceBuffer->data, &sourceBuffer->size, &sourceBuffer->freq);
    }

    
    // Scott - alutLoadWAVFile does not return an error (despite what the spec says), and alGetError
    // does not show errors if alutLoadWAVFile fails.  To find out if we succeeded, we have to check the
    // size.  Sheesh.

    // Don't unload if we are streaming
    if(!streaming)
    {    
        alBufferData(sourceBuffer->buffer[0], sourceBuffer->format, sourceBuffer->data, sourceBuffer->size, sourceBuffer->freq);
        CHECK_AL_ERROR("generate buffers");

        if (format == OGG_FILE)
        {
            ASSERT(sourceBuffer->size != 0);

            UnloadOGG(sourceBuffer->format, sourceBuffer->data, sourceBuffer->size, sourceBuffer->freq);
        }
        else  
        {
            alutUnloadWAV(sourceBuffer->format, sourceBuffer->data, sourceBuffer->size, sourceBuffer->freq);
            CHECK_AL_ERROR("wavunload");
        }
    }
    sourceBuffer->is3D = false;    //    default

    gBufferList.AppendItem(&sourceBuffer);    //    add to master buffer list
    CHECK_AL_ERROR("delbuf");

    return (WtSoundSource)sourceBuffer;

}// LoadSoundFromFile
Quote this message in a reply
TooMad
Unregistered
 
Post: #2
This is the playback and buffer handling code

Code:
//--------------------------------------------------------------------------------
// Create a new sound based on a sound source.
//--------------------------------------------------------------------------------

WSound * WAudio::NewSound(WtSoundSource soundSource, char* fName)
{
    ASSERT(soundSource != NULL);
    SoundBufferInfo* theBuffer = (SoundBufferInfo *)soundSource;

    WALSound *theSound;
    theSound = (theBuffer->numBuffers != 1) ? new WALStreamingSound(fName, theBuffer ) : new WALSound();

    theSound->source = soundSource;
    
    alGenSources(1, &theSound->alSource);
    CHECK_AL_ERROR("gensource");

    gLastSoundCreated = theSound;    //    track last sound created for easier event handling

    ALfloat SourcePos[] = { 0.0, 0.0, 0.0 };
    ALfloat SourceVel[] = { 0.0, 0.0, 0.0 };

    //    set up a bunch of stuff, including binding the buffer to the source
    alSourcei (theSound->alSource, AL_BUFFER,   theBuffer->buffer[0]);
    alSourcef (theSound->alSource, AL_PITCH,    1.0      );
    alSourcef (theSound->alSource, AL_GAIN,     1.0      );
    alSourcefv(theSound->alSource, AL_POSITION, SourcePos);
    alSourcefv(theSound->alSource, AL_VELOCITY, SourceVel);
    alSourcei (theSound->alSource, AL_LOOPING,  theBuffer->loop);

    CHECK_AL_ERROR("alSource");    //    check all setup stuff

    //    by default, loop if the buffer is set that way, same for 3D
    theSound->SetIs3D(theBuffer->is3D);
    theSound->SetIsLooped(theBuffer->loop == AL_TRUE);

    return(theSound);

}// NewSound

//--------------------------------------------------------------------------------
//    constructor
//    Create WALStreamingSound with no parameters
WALStreamingSound::WALStreamingSound(void):WALSound()
{

}

WALStreamingSound::WALStreamingSound(char* fName, SoundBufferInfo* theBufferIn):WALSound()
{
    strncpy(fileName, fName, 256);
    file = fopen(fileName, "rb");
    if (file == NULL)
        return;

    oggFile = (OggVorbis_File*)WMALLOC(sizeof(OggVorbis_File));
    theBuffer = theBufferIn;

    // Try opening the given file
    if (ov_open(file, oggFile, NULL, 0) != 0)
    {
        fclose( file );    // Close file
        return;
    }
    
    // Get some information about the OGG file
    oggInfo = ov_info(oggFile, -1);

    theBuffer->freq = oggInfo->rate;
    theBuffer->size = BUFFER_SIZE;
    // Check the number of channels... always use 16-bit samples
    if (oggInfo->channels == 1)
        theBuffer->format = AL_FORMAT_MONO16;
    else
        theBuffer->format = AL_FORMAT_STEREO16;

    if(!PlayBack())
    {
        ASSERT("This sucks");
    }

}

// destructor
WALStreamingSound::~WALStreamingSound()
{
    if (IsPlaying())
    {
        StopSound();
    }
    Release();
    ov_clear(oggFile);
    if(file)
        fclose( file );

    //    automatically remove us from the list.
    WALSound *thisPtr = this;
    WAudio::gSoundList.RemoveItem(&thisPtr);
}
void WALStreamingSound::StopSound(void)
{
    alSourceStop(alSource);    
    CHECK_AL_ERROR("stop");
}

void WALStreamingSound::EmptyQueue(void)
{
    int queued;        
    alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);        
    while(queued--)    
    {        
        ALuint buffer;            
        alSourceUnqueueBuffers(alSource, 1, &buffer);
        CHECK_AL_ERROR("empty queue streaming");
    }
}

bool WALStreamingSound::PlayBack(void)
{
    if(IsPlaying())
        return true;
    if(!Stream(theBuffer->buffer[0]))
        return false;
    if(!Stream(theBuffer->buffer[1]))
        return false;
    alSourceQueueBuffers(alSource, 2, theBuffer->buffer);
    alSourcePlay(alSource);
    return true;
}

void WALStreamingSound::Play()
{
    Update();
    if(!IsPlaying())
    {
        if(!PlayBack())
            ASSERT("Ogg stream was interrupted");
    }
}
void WALStreamingSound::Release()
{
    EmptyQueue();    
    alDeleteSources(1, &alSource);    
    CHECK_AL_ERROR("release streaming");
    alDeleteBuffers(2, theBuffer->buffer);    
    CHECK_AL_ERROR("release streaming");
}    
bool WALStreamingSound::Update()
{
    int processed;    
    bool active = true;    
    alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);    
    while(processed--)    
    {        
        ALuint buffer;                
        alSourceUnqueueBuffers(alSource, 1, &buffer);        
        CHECK_AL_ERROR("update streaming");
        active = Stream(buffer);        
        alSourceQueueBuffers(alSource, 1, &buffer);        
        CHECK_AL_ERROR("update streaming");
    }    
    return active;
}

bool WALStreamingSound::Stream(ALuint buffer)
{
    #ifdef WTARGET_OS_MAC_X
        int endian = 1;                         // 0 for Little-Endian, 1 for Big-Endian
    #else
        int endian = 0;                         // 0 for Little-Endian, 1 for Big-Endian
    #endif

    char data[BUFFER_SIZE];    
    int  size = 0;    
    int  section;    
    int  result;
    int arraySize = ov_pcm_total(oggFile, -1);
    // Fill this buffer
    static int numPasses = 0;
    static int totalSize = 0;
    while(size < BUFFER_SIZE)    
    {        
        numPasses++;
        result = ov_read(oggFile, data + size, BUFFER_SIZE - size, endian, 2, 1, & section);            
        if(result > 0)            
            size += result;        
        else if(result < 0)
        {
            CHECK_AL_ERROR("Stream streaming");
        }
        else                
            break;    
    }
    totalSize += size;
    if(size == 0)        
        return false;    
    alBufferData(buffer, theBuffer->format, data, size, oggInfo->rate);    
    CHECK_AL_ERROR("Stream streaming");
    return true;
}
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #3
... and what's the problem?

There's a known bug in the OpenAL that ships with 10.4 which causes frequent crashes on Intel and less-frequent crashes on PowerPC when streaming audio. The fix for this is to get your own version from CVS and use that instead.

CVS builds seem to byte-swap data on Intel machines. If you're using ogg/vorbis, that's easy to work around by lying and telling ogg/vorbis that your Intel Mac is big-endian...

There's a CVS snapshot here: http://onesadcookie.com/svn/repos/Thirdparty which fixed the streaming crash for me. YMMV. It does have the endianness bug in it.
Quote this message in a reply
TooMad
Unregistered
 
Post: #4
Actually the code runs without crashing and compiles just fine and without using streaming the same file plays fine too. It is just the streaming that is not workiing properly. Also this is being written on a PC not a mac so I don't think that will help if it is still the problem. Lol didn't notice this was a mac only dev forum know of any good pc forums?
Quote this message in a reply
TooMad
Unregistered
 
Post: #5
I've made some progress now Smile it will stream in the first block of data play it then it gets stuck on playing the second block.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #6
but you've even got WTARGET_OS_MACX in your code... it's wrong (you meant __BIG_ENDIAN__), but it's there!

there are plenty of good streaming AL + ogg/vorbis tutorials out there... I assume you've googled, found, copied, and it's still not working?
Quote this message in a reply
TooMad
Unregistered
 
Post: #7
Yes now it is 'working' like I described with the second buffer to be loaded looping constantly. I did have to change one thing to make it work in the sample it never did this line anywhere in the sample but removing it crashes my game.
Code:
        alSourcei (theSound->alSource, AL_BUFFER,   theBuffer->buffer[0]);
Which I guess must lock that buffer which is why I was never getting any sound at first. So I changed it to this.
Code:
        alSourcei (theSound->alSource, AL_STREAMING, theBuffer->buffer[0]);
alSourcei (theSound->alSource, AL_STREAMING, theBuffer->buffer[1]);
I've also tried it without binding both buffers and binding only the first but that doesn't sound like it would work.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenAL looping sound problem Gillissie 0 3,839 Sep 16, 2010 12:31 AM
Last Post: Gillissie
  openal linking problem on vc++ express 2005 abousoft 1 4,222 Jan 1, 2007 03:55 AM
Last Post: sealfin
  Need some help streaming ogg via OpenAL Malarkey 4 4,244 Nov 10, 2005 07:31 PM
Last Post: Malarkey
  Streaming Quicktime to OpenGL Texture Holmes 5 4,885 Jul 12, 2004 10:54 PM
Last Post: kelvin