-#include <stdexcept>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
#include <vorbis/vorbisfile.h>
+#pragma GCC diagnostic pop
+#include <msp/strings/format.h>
#include "oggdecoder.h"
using namespace std;
namespace Msp {
namespace AL {
+ogg_error::ogg_error(const std::string &func, int code):
+ runtime_error(format("%s: %s", func, get_message(code)))
+{ }
+
+string ogg_error::get_message(int code)
+{
+ switch(code)
+ {
+ case OV_FALSE: return "No data available";
+ case OV_HOLE: return "Missing or corrupt data";
+ case OV_EREAD: return "Read error";
+ case OV_EFAULT: return "Internal inconsistency";
+ case OV_EIMPL: return "Not implemented";
+ case OV_EINVAL: return "Invalid argument";
+ case OV_ENOTVORBIS: return "Not Vorbis data";
+ case OV_EBADHEADER: return "Corrupt Vorbis header";
+ case OV_EVERSION: return "Unsupported version";
+ case OV_EBADLINK: return "Bad link";
+ case OV_ENOSEEK: return "Stream is not seekable";
+ default: return format("Unknown error (%d)", code);
+ }
+}
+
+
struct OggDecoder::Private
{
OggVorbis_File ovfile;
OggDecoder::OggDecoder(IO::Seekable &io):
priv(new Private)
{
- if(ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks)<0)
- throw runtime_error("Could not open ogg vorbis resource");
+ int ret = ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks);
+ if(ret<0)
+ throw ogg_error("ov_open_callbacks", ret);
vorbis_info *info = ov_info(&priv->ovfile, -1);
freq = info->rate;
+ format = create_format(2, info->channels);
- size = ov_pcm_total(&priv->ovfile, 0)*info->channels*2;
-
- switch(info->channels)
- {
- case 1: format = MONO16; break;
- case 2: format = STEREO16; break;
- default: throw runtime_error("Unsupported number of channels");
- }
+ size = ov_pcm_total(&priv->ovfile, 0)*get_unit_size(format);
}
OggDecoder::~OggDecoder()
delete priv;
}
-void OggDecoder::rewind()
+bool OggDecoder::detect(const std::string &sig)
+{
+ static const char ogg_sig[] = { 'O', 'g', 'g', 'S' };
+ if(sig.size()<sizeof(ogg_sig))
+ return false;
+ return !sig.compare(0, sizeof(ogg_sig), ogg_sig, sizeof(ogg_sig));
+}
+
+void OggDecoder::seek(unsigned pos)
{
- ov_pcm_seek(&priv->ovfile, 0);
+ pos /= get_unit_size(format);
+ ov_pcm_seek(&priv->ovfile, pos);
}
unsigned OggDecoder::read(char *buf, unsigned len)
int section = 0;
int res = ov_read(&priv->ovfile, buf, len, 0, 2, 1, §ion);
if(res<0)
- throw runtime_error("Error reading ogg vorbis file");
+ throw ogg_error("ov_read", res);
else if(res==0)
eof_flag = true;
return res;