Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / SoundSystem / Common / OggVorbisStream.cpp
blob8c92d1554d53914ade22f99572c96c9bb7c47e02
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "OggVorbisStream.hpp"
8 #include "FileSys/FileMan.hpp"
9 #include "FileSys/File.hpp"
11 #include <cassert>
12 #include <iostream>
13 #include <stdexcept>
16 // Static callback method for the IO read function used by libvorbis to read from ogg files.
17 // We use our streamed file here to load data into buffer, so libvorbis works directly with cf::FileSys files.
18 // ElementSize: Size in bytes of one element to read.
19 // NumRead: Number of elements to read.
20 static size_t FileSysRead(void* Buffer, size_t ElementSize, size_t NumRead, void* DataSource)
22 cf::FileSys::InFileI* StreamFile=(cf::FileSys::InFileI*) DataSource;
24 return StreamFile->Read((char*)Buffer, uint32_t(ElementSize*NumRead));
28 // Static callback method for the IO seek function used by libvorbis to seek in ogg files.
29 // We use our streamed file here to seek in a file, so libvorbis works directly with cf::FileSys files.
30 static int FileSysSeek(void* DataSource, ogg_int64_t Offset, int Whence)
32 cf::FileSys::InFileI* StreamFile=(cf::FileSys::InFileI*) DataSource;
34 cf::FileSys::FileI::SeekFromT SeekFrom=cf::FileSys::FileI::FROM_BEGINNING;
35 switch (Whence)
37 case SEEK_CUR: SeekFrom=cf::FileSys::FileI::FROM_CURRENT_POS; break;
38 case SEEK_END: SeekFrom=cf::FileSys::FileI::FROM_END; break;
41 if (StreamFile->Seek((int)Offset, SeekFrom))
42 return int(StreamFile->GetPos());
44 return -1;
48 // Static callback method for the IO tell function used by libvorbis to tell the current position in ogg files.
49 // We use our streamed file here to tell the position, so libvorbis works directly with cd::FileSys files.
50 static long FileSysTell(void* DataSource)
52 cf::FileSys::InFileI* StreamFile=(cf::FileSys::InFileI*) DataSource;
54 return long(StreamFile->GetPos());
58 static std::string ErrorToStr(int ErrorCode);
61 OggVorbisStreamT::OggVorbisStreamT(const std::string& FileName)
62 : StreamHandle(),
63 StreamFile(NULL),
64 StreamInfo(NULL),
65 BitStream(-1)
67 // Create struct of custom callback methods, so libvorbis works with cf::FileSys.
68 ov_callbacks CallBacks;
70 CallBacks.read_func =&FileSysRead;
71 CallBacks.seek_func =&FileSysSeek;
72 CallBacks.close_func=NULL; // Not set since we want to close the streamed file ourselves using the file manager.
73 CallBacks.tell_func =&FileSysTell;
75 StreamFile=cf::FileSys::FileMan->OpenRead(FileName);
78 int Result=ov_test_callbacks(StreamFile, &StreamHandle, NULL, 0, CallBacks);;
80 if (Result!=0)
81 throw std::runtime_error("OggVorbis: File is no OggVorbis file ("+ErrorToStr(Result)+")");
83 Result=ov_test_open(&StreamHandle);
85 if (Result!=0)
86 throw std::runtime_error("OggVorbis: Couldn't open stream ("+ErrorToStr(Result)+")");
88 // Read rate and channels from the current bitstream.
89 StreamInfo=ov_info(&StreamHandle, BitStream);
91 if (StreamInfo==NULL)
92 throw std::runtime_error("OggVorbis: Couldn't access stream information");
96 OggVorbisStreamT::~OggVorbisStreamT()
98 ov_clear(&StreamHandle);
100 cf::FileSys::FileMan->Close(StreamFile);
104 int OggVorbisStreamT::Read(unsigned char* Buffer, unsigned int Size)
106 // libvorbis implementation doesn't actually write Size bytes from the stream in to the buffer when ov_read is called.
107 // Size is just a maximum that will never be exceeded.
108 // To make sure we read Size bytes from the stream into the buffer, we need to call ov_read until Size bytes are read.
109 int Result =0;
110 unsigned int ReadBytes=0;
112 int CurrentBitStream=BitStream;
113 long CurrentRate =StreamInfo->rate;
115 while (ReadBytes<Size)
117 Result=ov_read(&StreamHandle, (char*)&Buffer[ReadBytes], Size-ReadBytes, 0, 2, 1, &BitStream);
119 if (Result<0)
121 std::cout << "OggVorbis: Couldn't read from stream (Error: " << ErrorToStr(Result) << ")\n";
122 return Result;
125 if (Result==0) return ReadBytes;
127 ReadBytes+=Result;
129 if (CurrentBitStream!=BitStream)
131 StreamInfo=ov_info(&StreamHandle, BitStream);
132 CurrentBitStream=BitStream;
134 if (CurrentRate!=StreamInfo->rate)
136 CurrentRate=StreamInfo->rate;
137 std::cout << "OggVorbis: Warning! Ogg file contains multiple streams with different sample rate, playback errors may occur...\n";
142 return ReadBytes;
146 bool OggVorbisStreamT::Rewind()
148 int Result=ov_time_seek(&StreamHandle, 0.0);
150 if (Result!=0)
152 std::cout << "OggVorbis: Couldn't rewind stream (Error: " << ErrorToStr(Result) << ")\n";
153 return false;
156 return true;
160 unsigned int OggVorbisStreamT::GetChannels()
162 if (StreamInfo==NULL) return 0;
164 return StreamInfo->channels;
168 unsigned int OggVorbisStreamT::GetRate()
170 if (StreamInfo==NULL) return 0;
172 return StreamInfo->rate;
176 static std::string ErrorToStr(int ErrorCode)
178 switch(ErrorCode)
180 case OV_EREAD: return "OV_EREAD";
181 case OV_ENOTVORBIS: return "OV_ENOTVORBIS";
182 case OV_EVERSION: return "OV_EVERSION";
183 case OV_EBADHEADER: return "OV_EBADHEADER";
184 case OV_EFAULT: return "OV_EFAULT";
185 case OV_HOLE: return "OV_HOLE";
186 case OV_EBADLINK: return "OV_EBADLINK";
187 case OV_ENOSEEK: return "OV_ENOSEEK";
188 case OV_EINVAL: return "OV_EINVAL";
191 return "Unknown error";