فهرست منبع

Updated AudioBuffer to use Stream instead of FILE.
Android no longer needs to copy wav and ogg files to the SD card before loading them.

Darryl Gough 13 سال پیش
والد
کامیت
9ace6b892a
2فایلهای تغییر یافته به همراه84 افزوده شده و 57 حذف شده
  1. 81 55
      gameplay/src/AudioBuffer.cpp
  2. 3 2
      gameplay/src/AudioBuffer.h

+ 81 - 55
gameplay/src/AudioBuffer.cpp

@@ -8,6 +8,36 @@ namespace gameplay
 // Audio buffer cache
 static std::vector<AudioBuffer*> __buffers;
 
+// Callbacks for loading an ogg file using Stream
+static size_t readStream(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return stream->read(ptr, size, nmemb);
+}
+
+static int seekStream(void *datasource, ogg_int64_t offset, int whence)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return !stream->seek(offset, whence);
+}
+
+static int closeStream(void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    stream->close();
+    return 0;
+}
+
+static long tellStream(void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return stream->position();
+}
+
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
     : _filePath(path), _alBuffer(buffer)
 {
@@ -63,8 +93,8 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     
     // Load sound file.
-    FILE* file = FileSystem::openFile(path, "rb");
-    if (!file)
+    std::auto_ptr<Stream> stream(FileSystem::open(path));
+    if (stream.get() == NULL || !stream->canRead())
     {
         GP_ERROR("Failed to load audio file %s.", path);
         goto cleanup;
@@ -72,7 +102,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     
     // Read the file header
     char header[12];
-    if (fread(header, 1, 12, file) != 12)
+    if (stream->read(header, 1, 12) != 12)
     {
         GP_ERROR("Invalid header for audio file %s.", path);
         goto cleanup;
@@ -81,7 +111,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     // Check the file format
     if (memcmp(header, "RIFF", 4) == 0)
     {
-        if (!AudioBuffer::loadWav(file, alBuffer))
+        if (!AudioBuffer::loadWav(stream.get(), alBuffer))
         {
             GP_ERROR("Invalid wave file: %s", path);
             goto cleanup;
@@ -89,7 +119,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     else if (memcmp(header, "OggS", 4) == 0)
     {
-        if (!AudioBuffer::loadOgg(file, alBuffer))
+        if (!AudioBuffer::loadOgg(stream.get(), alBuffer))
         {
             GP_ERROR("Invalid ogg file: %s", path);
             goto cleanup;
@@ -101,10 +131,6 @@ AudioBuffer* AudioBuffer::create(const char* path)
         goto cleanup;
     }
 
-    //NOTE: loadOgg actually sets this null, so it is expected
-    if (file)    
-        fclose(file);
-
     buffer = new AudioBuffer(path, alBuffer);
 
     // Add the buffer to the cache.
@@ -113,34 +139,32 @@ AudioBuffer* AudioBuffer::create(const char* path)
     return buffer;
     
 cleanup:
-    
-    if (file)
-        fclose(file);
     if (alBuffer)
         AL_CHECK( alDeleteBuffers(1, &alBuffer) );
     return NULL;
 }
 
-bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
+bool AudioBuffer::loadWav(Stream* stream, ALuint buffer)
 {
-    GP_ASSERT(file);
-    unsigned char stream[12];
+    GP_ASSERT(stream);
+
+    unsigned char data[12];
     
     // Verify the wave fmt magic value meaning format.
-    if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
+    if (stream->read(data, 1, 8) != 8 || memcmp(data, "fmt ", 4) != 0 )
     {
         GP_ERROR("Failed to verify the magic value for the wave file format.");
         return false;
     }
     
     unsigned int section_size;
-    section_size  = stream[7]<<24;
-    section_size |= stream[6]<<16;
-    section_size |= stream[5]<<8;
-    section_size |= stream[4];
+    section_size  = data[7]<<24;
+    section_size |= data[6]<<16;
+    section_size |= data[5]<<8;
+    section_size |= data[4];
 
     // Check for a valid pcm format.
-    if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
+    if (stream->read(data, 1, 2) != 2 || data[1] != 0 || data[0] != 1)
     {
         GP_ERROR("Unsupported audio file format (must be a valid PCM format).");
         return false;
@@ -148,31 +172,31 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     // Get the channel count (16-bit little-endian).
     int channels;
-    if (fread(stream, 1, 2, file) != 2)
+    if (stream->read(data, 1, 2) != 2)
     {
         GP_ERROR("Failed to read the wave file's channel count.");
         return false;
     }
-    channels  = stream[1]<<8;
-    channels |= stream[0];
+    channels  = data[1]<<8;
+    channels |= data[0];
     
     // Get the sample frequency (32-bit little-endian).
     ALuint frequency;
-    if (fread(stream, 1, 4, file) != 4)
+    if (stream->read(data, 1, 4) != 4)
     {
         GP_ERROR("Failed to read the wave file's sample frequency.");
         return false;
     }
 
-    frequency  = stream[3]<<24;
-    frequency |= stream[2]<<16;
-    frequency |= stream[1]<<8;
-    frequency |= stream[0];
+    frequency  = data[3]<<24;
+    frequency |= data[2]<<16;
+    frequency |= data[1]<<8;
+    frequency |= data[0];
     
     // The next 6 bytes hold the block size and bytes-per-second. 
     // We don't need that info, so just read and ignore it. 
     // We could use this later if we need to know the duration.
-    if (fread(stream, 1, 6, file) != 6)
+    if (stream->read(data, 1, 6) != 6)
     {
         GP_ERROR("Failed to read past the wave file's block size and bytes-per-second.");
         return false;
@@ -180,13 +204,13 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     // Get the bit depth (16-bit little-endian).
     int bits;
-    if (fread(stream, 1, 2, file) != 2)
+    if (stream->read(data, 1, 2) != 2)
     {
         GP_ERROR("Failed to read the wave file's bit depth.");
         return false;
     }
-    bits  = stream[1]<<8;
-    bits |= stream[0];
+    bits  = data[1]<<8;
+    bits |= data[0];
     
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
@@ -216,7 +240,7 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         unsigned int length = section_size - 16;
 
         // Extension size is 2 bytes.
-        if (fread(stream, 1, length, file) != length)
+        if (stream->read(data, 1, length) != length)
         {
             GP_ERROR("Failed to read extension size from wave file.");
             return false;
@@ -227,32 +251,32 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     while (true)
     {
         // Check if we are at the end of the file without reading the data.
-        if (feof(file))
+        if (stream->eof())
         {
             GP_ERROR("Failed to load wave file; file appears to have no data.");
             return false;
         }
 
         // Read in the type of the next section of the file.
-        if (fread(stream, 1, 4, file) != 4)
+        if (stream->read(data, 1, 4) != 4)
         {
             GP_ERROR("Failed to read next section type from wave file.");
             return false;
         }
 
         // Data chunk.
-        if (memcmp(stream, "data", 4) == 0)
+        if (memcmp(data, "data", 4) == 0)
         {
             // Read how much data is remaining and buffer it up.
             unsigned int dataSize;
-            if (fread(&dataSize, sizeof(int), 1, file) != 1)
+            if (stream->read(&dataSize, sizeof(int), 1) != 1)
             {
                 GP_ERROR("Failed to read size of data section from wave file.");
                 return false;
             }
 
             char* data = new char[dataSize];
-            if (fread(data, sizeof(char), dataSize, file) != dataSize)
+            if (stream->read(data, sizeof(char), dataSize) != dataSize)
             {
                 GP_ERROR("Failed to load wave file; file is missing data.");
                 SAFE_DELETE_ARRAY(data);
@@ -281,22 +305,22 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         {
             // Store the name of the chunk so we can report errors informatively.
             char chunk[5] = { 0 };
-            memcpy(chunk, stream, 4);
+            memcpy(chunk, data, 4);
 
             // Read the chunk size.
-            if (fread(stream, 1, 4, file) != 4)
+            if (stream->read(data, 1, 4) != 4)
             {
                 GP_ERROR("Failed to read size of '%s' chunk from wave file.", chunk);
                 return false;
             }
 
-            section_size  = stream[3]<<24;
-            section_size |= stream[2]<<16;
-            section_size |= stream[1]<<8;
-            section_size |= stream[0];
+            section_size  = data[3]<<24;
+            section_size |= data[2]<<16;
+            section_size |= data[1]<<8;
+            section_size |= data[0];
 
             // Seek past the chunk.
-            if (fseek(file, section_size, SEEK_CUR) != 0)
+            if (stream->seek(section_size, SEEK_CUR) == false)
             {
                 GP_ERROR("Failed to seek past '%s' chunk in wave file.", chunk);
                 return false;
@@ -304,10 +328,10 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         }
     }
 }
-    
-bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
+
+bool AudioBuffer::loadOgg(Stream* stream, ALuint buffer)
 {
-    GP_ASSERT(file);
+    GP_ASSERT(stream);
 
     OggVorbis_File ogg_file;
     vorbis_info* info;
@@ -316,11 +340,16 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     int section;
     long size = 0;
 
-    rewind(file);
+    stream->rewind();
 
-    if ((result = ov_open(file, &ogg_file, NULL, 0)) < 0)
+    ov_callbacks callbacks;
+    callbacks.read_func = readStream;
+    callbacks.seek_func = seekStream;
+    callbacks.close_func = closeStream;
+    callbacks.tell_func = tellStream;
+
+    if ((result = ov_open_callbacks(stream, &ogg_file, NULL, 0, callbacks)) < 0)
     {
-        fclose(file);
         GP_ERROR("Failed to open ogg file.");
         return false;
     }
@@ -367,9 +396,6 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     SAFE_DELETE_ARRAY(data);
     ov_clear(&ogg_file);
 
-    // ov_clear actually closes the file pointer as well.
-    file = 0;
-
     return true;
 }
 

+ 3 - 2
gameplay/src/AudioBuffer.h

@@ -2,6 +2,7 @@
 #define AUDIOBUFFER_H_
 
 #include "Ref.h"
+#include "Stream.h"
 
 namespace gameplay
 {
@@ -43,9 +44,9 @@ private:
      */
     static AudioBuffer* create(const char* path);
     
-    static bool loadWav(FILE* file, ALuint buffer);
+    static bool loadWav(Stream* stream, ALuint buffer);
     
-    static bool loadOgg(FILE*& file, ALuint buffer);
+    static bool loadOgg(Stream* stream, ALuint buffer);
 
     std::string _filePath;
     ALuint _alBuffer;