循环流式传输 .ogg 音频 - OpenAL

发布于 2024-09-10 14:46:37 字数 3529 浏览 5 评论 0原文

我在循环流式 ogg vorbis 文件时遇到问题。

这是代码:

fslStream_OGG::fslStream_OGG()
{
 className = "fslSound";
 iMemSize = 0;
 iLength = 0;
 bSourceRelative = false;
 bIsLooping = false;
 bForceStop = false;
 bActive = false;
 source = buffer = 0;
 current_gain = 1.0f;
 outer_gain = 0;
 snd_info.uiChannels = snd_info.uiFrequency = snd_info.uiSampling = 0;
}

fslStream_OGG::~fslStream_OGG()
{
 if (bStreamCreated)
 {
  alSourceStop(source);
  Empty();
  alDeleteSources(1,&source);
  alDeleteBuffers(2,buffers);
  ov_clear(&oggStream);
 }
}

bool fslStream_OGG::Update()
{
 ALenum state; 
 alGetSourcei(source,AL_SOURCE_STATE,&state);

 if (state == AL_PAUSED || !bActive) return false;

 int processed;
    alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);

    while (processed--)
    {
        ALuint bufferI;
        alSourceUnqueueBuffers(source,1,&bufferI);
        Stream(bufferI);
  if (bActive) alSourceQueueBuffers(source,1,&bufferI);
    }

 if (state == AL_STOPPED || !bActive)
 {
  bActive = false;
  StreamSetPos(0.0f);
  if (bForceStop) return false;

  if (bIsLooping)
  {
   alSourceStop(source); // <- *** note these ***
   Empty();    // <- *** 2 lines of code ***
   StreamPlay();
   alSourcePlay(source);
  }
  else
  {
   return true;
  }
 }

 return false;
}

void fslStream_OGG::StreamPlay()
{
 if (!bActive)
 {
  bActive = true;
  bForceStop = false;
  Stream(buffers[0]);
  Stream(buffers[1]);

  alSourceQueueBuffers(source,2,buffers);
 }
}

bool fslStream_OGG::Open(const char* strFile)
{
 bStreamCreated = false;
 vorbis_info* vorbisInfo;
 oggFile = fopen(strFile,"rb");

 if (!oggFile) return false;

 if (ov_open_callbacks(oggFile,&oggStream,NULL,0,OV_CALLBACKS_DEFAULT) != 0)
 {
  fclose(oggFile);
  return false;
 }

 vorbisInfo = ov_info(&oggStream,-1);

 if (vorbisInfo->channels == 1)
  format = AL_FORMAT_MONO16;
 else format = AL_FORMAT_STEREO16;

 alGenBuffers(2,buffers);
 alGenSources(1,&source);

 iLength = (long)(ov_time_total(&oggStream,-1) * 1000.0);
 snd_info.uiChannels = (format == AL_FORMAT_MONO8 || format == AL_FORMAT_MONO16)? 1:2;
 snd_info.uiSampling = (format == AL_FORMAT_MONO8 || format == AL_FORMAT_STEREO8)? 8:16;
 snd_info.uiFrequency = vorbisInfo->rate;

 bStreamCreated = true;
 bIsStream = true;

 return true;
}

void fslStream_OGG::Stream(ALuint bufferI)
{
 int  size = 0;
 int  section;
 int  result;

 bActive = true;

 while (size < OGG_STREAM_BUFFER_SIZE)
 {
  result = ov_read(&oggStream,data + size,OGG_STREAM_BUFFER_SIZE - size,0,2,1,&section);

  if (result > 0)
  {
   size += result;
  }
  else
  {
   if (result < 0) return; else break;
  }
 }

 if (size == 0) { bActive = false; return; }

    alBufferData(bufferI,format,data,size,snd_info.uiFrequency);
}

void fslStream_OGG::Empty()
{
 int queued;
 alGetSourcei(source,AL_BUFFERS_QUEUED,&queued);

 while (queued--)
 {
        ALuint bufferI;
  alSourceUnqueueBuffers(source,1,&bufferI);
 }
}

void fslStream_OGG::StreamSetPos(float p)
{
 ov_time_seek(&oggStream,p);
}

float fslStream_OGG::StreamGetPos()
{
 return (float)ov_time_tell(&oggStream);
}

注意我用 *** 标记的两行代码。

在所有情况下,文件都会开始正常播放并在结束时倒带。但是:

没有这两行代码,重复时文件听起来“已损坏”。如果再重复一遍,听起来就更“腐败”了。我相信这是因为 OpenAl 和 Vorbis 解码器在重复流时“不同步”写入/读取缓冲区。

如果我添加这两行代码,文件会重复,而不会听起来损坏。然而,该文件并不是无缝重复的;它在结束前倒回几厘秒。我怀疑这是因为在倒回开始之前缓冲区没有播放到最后。

如果有人可以伸出援助之手,我将不胜感激。

预先非常感谢,

比尔

I have problem looping a streamed ogg vorbis file.

This is the code :

fslStream_OGG::fslStream_OGG()
{
 className = "fslSound";
 iMemSize = 0;
 iLength = 0;
 bSourceRelative = false;
 bIsLooping = false;
 bForceStop = false;
 bActive = false;
 source = buffer = 0;
 current_gain = 1.0f;
 outer_gain = 0;
 snd_info.uiChannels = snd_info.uiFrequency = snd_info.uiSampling = 0;
}

fslStream_OGG::~fslStream_OGG()
{
 if (bStreamCreated)
 {
  alSourceStop(source);
  Empty();
  alDeleteSources(1,&source);
  alDeleteBuffers(2,buffers);
  ov_clear(&oggStream);
 }
}

bool fslStream_OGG::Update()
{
 ALenum state; 
 alGetSourcei(source,AL_SOURCE_STATE,&state);

 if (state == AL_PAUSED || !bActive) return false;

 int processed;
    alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);

    while (processed--)
    {
        ALuint bufferI;
        alSourceUnqueueBuffers(source,1,&bufferI);
        Stream(bufferI);
  if (bActive) alSourceQueueBuffers(source,1,&bufferI);
    }

 if (state == AL_STOPPED || !bActive)
 {
  bActive = false;
  StreamSetPos(0.0f);
  if (bForceStop) return false;

  if (bIsLooping)
  {
   alSourceStop(source); // <- *** note these ***
   Empty();    // <- *** 2 lines of code ***
   StreamPlay();
   alSourcePlay(source);
  }
  else
  {
   return true;
  }
 }

 return false;
}

void fslStream_OGG::StreamPlay()
{
 if (!bActive)
 {
  bActive = true;
  bForceStop = false;
  Stream(buffers[0]);
  Stream(buffers[1]);

  alSourceQueueBuffers(source,2,buffers);
 }
}

bool fslStream_OGG::Open(const char* strFile)
{
 bStreamCreated = false;
 vorbis_info* vorbisInfo;
 oggFile = fopen(strFile,"rb");

 if (!oggFile) return false;

 if (ov_open_callbacks(oggFile,&oggStream,NULL,0,OV_CALLBACKS_DEFAULT) != 0)
 {
  fclose(oggFile);
  return false;
 }

 vorbisInfo = ov_info(&oggStream,-1);

 if (vorbisInfo->channels == 1)
  format = AL_FORMAT_MONO16;
 else format = AL_FORMAT_STEREO16;

 alGenBuffers(2,buffers);
 alGenSources(1,&source);

 iLength = (long)(ov_time_total(&oggStream,-1) * 1000.0);
 snd_info.uiChannels = (format == AL_FORMAT_MONO8 || format == AL_FORMAT_MONO16)? 1:2;
 snd_info.uiSampling = (format == AL_FORMAT_MONO8 || format == AL_FORMAT_STEREO8)? 8:16;
 snd_info.uiFrequency = vorbisInfo->rate;

 bStreamCreated = true;
 bIsStream = true;

 return true;
}

void fslStream_OGG::Stream(ALuint bufferI)
{
 int  size = 0;
 int  section;
 int  result;

 bActive = true;

 while (size < OGG_STREAM_BUFFER_SIZE)
 {
  result = ov_read(&oggStream,data + size,OGG_STREAM_BUFFER_SIZE - size,0,2,1,§ion);

  if (result > 0)
  {
   size += result;
  }
  else
  {
   if (result < 0) return; else break;
  }
 }

 if (size == 0) { bActive = false; return; }

    alBufferData(bufferI,format,data,size,snd_info.uiFrequency);
}

void fslStream_OGG::Empty()
{
 int queued;
 alGetSourcei(source,AL_BUFFERS_QUEUED,&queued);

 while (queued--)
 {
        ALuint bufferI;
  alSourceUnqueueBuffers(source,1,&bufferI);
 }
}

void fslStream_OGG::StreamSetPos(float p)
{
 ov_time_seek(&oggStream,p);
}

float fslStream_OGG::StreamGetPos()
{
 return (float)ov_time_tell(&oggStream);
}

Note the 2 lines of code I have marked with ***.

In all cases, the file starts playing fine and rewinds when it ends. However :

Without those 2 lines of code, when repeated the file sounds "corrupted". If let to repeat again, it sounds even more "corrupted". I believe this is because OpenAl and the Vorbis decoder get "unsynchronized" writing/reading the buffer when the stream is repeated.

If I add those 2 lines of code, the file repeats without sounding corrupted. However, the file isn't repeated seamlessly; it rewinds a few centiseconds before it ends. I suspect this is because the buffers are not played to the end before rewinding to start.

I would be obliged if anyone could lend a helping hand.

Many thanks in advance,

Bill

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心舞飞扬 2024-09-17 14:46:37

似乎我已经解决了这个问题(如果没有广泛的测试,我无法确定)。

我已经修复了 Update 方法,如下所示:

bool fslStream_OGG::Update()
{
    ALenum state; 
    alGetSourcei(source,AL_SOURCE_STATE,&state);

    //if (state == AL_PAUSED || !bActive) return false; // <- WRONG
    if (state == AL_PAUSED) return false;

    int processed;
    alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);

    while (processed--)
    {
        ALuint bufferI;
        alSourceUnqueueBuffers(source,1,&bufferI);
        Stream(bufferI);
        if (bActive) alSourceQueueBuffers(source,1,&bufferI);
    }

    //if (state == AL_STOPPED || !bActive) /// <- WRONG
    if (state == AL_STOPPED)
    {
        bActive = false;
        StreamSetPos(0.0f);
        if (bForceStop) return false;

        if (bIsLooping)
        {
            //alSourceStop(source); // <- I have added these
            //Empty();              // <- 2 lines of code
            StreamPlay();
            alSourcePlay(source);
        }
        else
        {
            return true;
        }
    }

    return false;
}

那两行代码现在似乎没有必要了。必须用不同的操作系统、硬件等来测试它......

It seems that I have fixed the problem (I won't be sure without extensive testing).

I have fixed the Update method as follows :

bool fslStream_OGG::Update()
{
    ALenum state; 
    alGetSourcei(source,AL_SOURCE_STATE,&state);

    //if (state == AL_PAUSED || !bActive) return false; // <- WRONG
    if (state == AL_PAUSED) return false;

    int processed;
    alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed);

    while (processed--)
    {
        ALuint bufferI;
        alSourceUnqueueBuffers(source,1,&bufferI);
        Stream(bufferI);
        if (bActive) alSourceQueueBuffers(source,1,&bufferI);
    }

    //if (state == AL_STOPPED || !bActive) /// <- WRONG
    if (state == AL_STOPPED)
    {
        bActive = false;
        StreamSetPos(0.0f);
        if (bForceStop) return false;

        if (bIsLooping)
        {
            //alSourceStop(source); // <- I have added these
            //Empty();              // <- 2 lines of code
            StreamPlay();
            alSourcePlay(source);
        }
        else
        {
            return true;
        }
    }

    return false;
}

Those 2 lines of code seem not to be necessary now. Will have to test it with different OSes, hardware etc...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文