alBufferData() ตั้งค่า AL_INVALID_OPERATION เมื่อใช้ ID บัฟเฟอร์ที่ได้รับจาก alSourceUnqueueBuffers()

ฉันกำลังพยายามสตรีมข้อมูลเสียงจากดิสก์โดยใช้กลไกการจัดคิวบัฟเฟอร์ของ OpenAL ฉันโหลดและจัดคิวบัฟเฟอร์ 4 ตัว เริ่มเล่นต้นฉบับ และตรวจสอบตามช่วงเวลาปกติเพื่อรีเฟรชคิว ดูเหมือนว่าทุกอย่างจะดำเนินไปอย่างงดงาม จนถึงครั้งแรกที่ฉันพยายามโหลดข้อมูลลงในบัฟเฟอร์รีไซเคิลที่ฉันได้รับจาก alSourceUnqueueBuffers() ในสถานการณ์นี้ alBufferData() จะตั้งค่า AL_INVALID_OPERATION เสมอ ซึ่งเป็นไปตาม v1 อย่างเป็นทางการ 1 ข้อมูลจำเพาะ ดูเหมือนว่าไม่น่าจะทำได้

ฉันได้ค้นหาอย่างกว้างขวางใน Google และ StackOverflow และดูเหมือนจะไม่พบสาเหตุใด ๆ ว่าทำไมสิ่งนี้จึงเกิดขึ้น สิ่งที่ใกล้เคียงที่สุดที่ฉันพบคือคนที่มี ปัญหาที่อาจเกี่ยวข้อง ในโพสต์ในฟอรัมที่เก็บถาวร แต่มีรายละเอียดน้อยและการตอบกลับถือเป็นโมฆะ นอกจากนี้ยังมีคำถาม SO นี้ ด้วยสถานการณ์ที่แตกต่างกันเล็กน้อย แต่คำถามเดียวเท่านั้น คำแนะนำของคำตอบไม่ได้ช่วยอะไร

อาจเป็นประโยชน์: ฉันรู้ว่าบริบทและอุปกรณ์ของฉันได้รับการกำหนดค่าอย่างถูกต้อง เนื่องจากการโหลดไฟล์ wav ขนาดเล็กลงในบัฟเฟอร์เดียวและการเล่นไฟล์เหล่านั้นก็ทำงานได้ดี จากการทดลอง ฉันยังพบว่าการเข้าคิวบัฟเฟอร์ 2 ตัว การเริ่มเล่นต้นฉบับ และการโหลดและการเข้าคิวบัฟเฟอร์อีกสองตัวทันทีนั้นไม่มีข้อผิดพลาด เมื่อฉันยกเลิกคิวบัฟเฟอร์ที่ประมวลผลแล้วเท่านั้นที่ฉันประสบปัญหา

รหัสที่เกี่ยวข้อง:

static constexpr int MAX_BUFFER_COUNT = 4;

#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }

bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
    ALenum tErrCode = alGetError();
    if(tErrCode != 0)
    {
        auto tMsg = alGetString(tErrCode);
        Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
                        << "\tAL call " << pfunc << " failed." << end;
        return true;
    }
    return false;
}

void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
    static int called = 0;
    ++called;

    ALint tState;
    alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
    if(tState == AL_STATIC)
    {
        Stop();
//      alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
    }

    ALuint tBufId = AL_NONE;
    int tQueuedBuffers = QueuedUpBuffers();
    int tReady = ProcessedBuffers();
    if(tQueuedBuffers < MAX_BUFFER_COUNT)
    {
        tBufId = mBufferIds[tQueuedBuffers];
    }
    else if(tReady > 0)
    {
        // the fifth time through, this code gets hit
        alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));

        // debug code: make sure these values go down by one
        tQueuedBuffers = QueuedUpBuffers();
        tReady = ProcessedBuffers();
    }
    else
    {
        return; // no update needed yet.
    }

    void* tConverted = convert(pData, pFrames);

    // the fifth time through, we get AL_INVALID_OPERATION, and call abort()
    alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));

    alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
    if(mBitdepth == BITDEPTH_8)
    {
        delete (uint8_t*)tConverted;
    }
    else // if(mBitdepth == BITDEPTH_16)
    {
        delete (uint16_t*)tConverted;
    }
}

void SoundyOutport::PlayBufferedStream()
{
    if(!StreamingMode() || !QueuedUpBuffers())
    {
        Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
        return;
    }

    alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
    alCall(alSourcePlay(mSourceId));
}

int SoundyOutport::QueuedUpBuffers()
{
    int tCount = 0;
    alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
    return tCount;
}

int SoundyOutport::ProcessedBuffers()
{
    int tCount = 0;
    alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
    return tCount;
}

void SoundyOutport::Stop()
{
    if(Playing())
    {
        alCall(alSourceStop(mSourceId));
    }

    int tBuffers;
    alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
    if(tBuffers)
    {
        ALuint tDummy[tBuffers];
        alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
    }
    alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}

bool SoundyOutport::Playing()
{
    ALint tPlaying;
    alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
    return tPlaying == AL_PLAYING;
}

bool SoundyOutport::StreamingMode()
{
    ALint tState;
    alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
    return tState == AL_STREAMING;
}

bool SoundyOutport::StaticMode()
{
    ALint tState;
    alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
    return tState == AL_STATIC;
}

และนี่คือภาพหน้าจอที่มีคำอธิบายประกอบของสิ่งที่ฉันเห็นในดีบักเกอร์เมื่อฉันพบข้อผิดพลาด:

มุมมองคำอธิบายประกอบของเนื้อหาดีบักเกอร์

ฉันได้ลองปรับแต่งและรูปแบบต่างๆ เล็กน้อยแล้ว และผลลัพธ์ก็เหมือนเดิมเสมอ ฉันเสียเวลาไปหลายวันเกินไปในการพยายามแก้ไขปัญหานี้ กรุณาช่วย :)


person Ionoclast Brigham    schedule 14.04.2014    source แหล่งที่มา


คำตอบ (1)


ข้อผิดพลาดนี้เกิดขึ้นเมื่อคุณพยายามเติมบัฟเฟอร์ด้วยข้อมูล เมื่อบัฟเฟอร์ยังคงอยู่ในคิวไปยังแหล่งที่มา

รหัสนี้ก็ผิดเช่นกัน

if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
    tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
    // the fifth time through, this code gets hit
    alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));

    // debug code: make sure these values go down by one
    tQueuedBuffers = QueuedUpBuffers();
    tReady = ProcessedBuffers();
}
else
{
    return; // no update needed yet.
}

คุณสามารถเติมบัฟเฟอร์ด้วยข้อมูลได้เฉพาะในกรณีที่ไม่ได้เข้าคิวจากแหล่งที่มาเท่านั้น แต่บล็อก if แรกของคุณได้รับ tBufId ที่เข้าคิวไปยังแหล่งที่มา เขียนโค้ดใหม่เช่นนั้น

if(tReady > 0)
{
    // the fifth time through, this code gets hit
    alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));

    // debug code: make sure these values go down by one
    tQueuedBuffers = QueuedUpBuffers();
    tReady = ProcessedBuffers();
}
else
{
    return; // no update needed yet.
}
person mrDIMAS    schedule 01.11.2015
comment
จริงๆ แล้วฉันเปลี่ยนมาใช้ SDL Mixer เมื่อนานมาแล้ว ซึ่งดูเหมือนไม่มีใครรู้ว่าโค้ด AL ของฉันจะเกิดอะไรขึ้น หากใครสามารถเข้ามายืนยันคำตอบนี้ได้ ฉันยินดีที่จะยอมรับ - person Ionoclast Brigham; 03.11.2015