Explorar el Código

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 hace 13 años
padre
commit
9ace6b892a
Se han modificado 2 ficheros con 84 adiciones y 57 borrados
  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
 // Audio buffer cache
 static std::vector<AudioBuffer*> __buffers;
 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)
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
     : _filePath(path), _alBuffer(buffer)
     : _filePath(path), _alBuffer(buffer)
 {
 {
@@ -63,8 +93,8 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     }
     
     
     // Load sound file.
     // 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);
         GP_ERROR("Failed to load audio file %s.", path);
         goto cleanup;
         goto cleanup;
@@ -72,7 +102,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     
     
     // Read the file header
     // Read the file header
     char header[12];
     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);
         GP_ERROR("Invalid header for audio file %s.", path);
         goto cleanup;
         goto cleanup;
@@ -81,7 +111,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     // Check the file format
     // Check the file format
     if (memcmp(header, "RIFF", 4) == 0)
     if (memcmp(header, "RIFF", 4) == 0)
     {
     {
-        if (!AudioBuffer::loadWav(file, alBuffer))
+        if (!AudioBuffer::loadWav(stream.get(), alBuffer))
         {
         {
             GP_ERROR("Invalid wave file: %s", path);
             GP_ERROR("Invalid wave file: %s", path);
             goto cleanup;
             goto cleanup;
@@ -89,7 +119,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     }
     else if (memcmp(header, "OggS", 4) == 0)
     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);
             GP_ERROR("Invalid ogg file: %s", path);
             goto cleanup;
             goto cleanup;
@@ -101,10 +131,6 @@ AudioBuffer* AudioBuffer::create(const char* path)
         goto cleanup;
         goto cleanup;
     }
     }
 
 
-    //NOTE: loadOgg actually sets this null, so it is expected
-    if (file)    
-        fclose(file);
-
     buffer = new AudioBuffer(path, alBuffer);
     buffer = new AudioBuffer(path, alBuffer);
 
 
     // Add the buffer to the cache.
     // Add the buffer to the cache.
@@ -113,34 +139,32 @@ AudioBuffer* AudioBuffer::create(const char* path)
     return buffer;
     return buffer;
     
     
 cleanup:
 cleanup:
-    
-    if (file)
-        fclose(file);
     if (alBuffer)
     if (alBuffer)
         AL_CHECK( alDeleteBuffers(1, &alBuffer) );
         AL_CHECK( alDeleteBuffers(1, &alBuffer) );
     return NULL;
     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.
     // 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.");
         GP_ERROR("Failed to verify the magic value for the wave file format.");
         return false;
         return false;
     }
     }
     
     
     unsigned int section_size;
     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.
     // 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).");
         GP_ERROR("Unsupported audio file format (must be a valid PCM format).");
         return false;
         return false;
@@ -148,31 +172,31 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     
     // Get the channel count (16-bit little-endian).
     // Get the channel count (16-bit little-endian).
     int channels;
     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.");
         GP_ERROR("Failed to read the wave file's channel count.");
         return false;
         return false;
     }
     }
-    channels  = stream[1]<<8;
-    channels |= stream[0];
+    channels  = data[1]<<8;
+    channels |= data[0];
     
     
     // Get the sample frequency (32-bit little-endian).
     // Get the sample frequency (32-bit little-endian).
     ALuint frequency;
     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.");
         GP_ERROR("Failed to read the wave file's sample frequency.");
         return false;
         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. 
     // 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 don't need that info, so just read and ignore it. 
     // We could use this later if we need to know the duration.
     // 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.");
         GP_ERROR("Failed to read past the wave file's block size and bytes-per-second.");
         return false;
         return false;
@@ -180,13 +204,13 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     
     // Get the bit depth (16-bit little-endian).
     // Get the bit depth (16-bit little-endian).
     int bits;
     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.");
         GP_ERROR("Failed to read the wave file's bit depth.");
         return false;
         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. 
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
     ALuint format = 0;
@@ -216,7 +240,7 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         unsigned int length = section_size - 16;
         unsigned int length = section_size - 16;
 
 
         // Extension size is 2 bytes.
         // 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.");
             GP_ERROR("Failed to read extension size from wave file.");
             return false;
             return false;
@@ -227,32 +251,32 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     while (true)
     while (true)
     {
     {
         // Check if we are at the end of the file without reading the data.
         // 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.");
             GP_ERROR("Failed to load wave file; file appears to have no data.");
             return false;
             return false;
         }
         }
 
 
         // Read in the type of the next section of the file.
         // 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.");
             GP_ERROR("Failed to read next section type from wave file.");
             return false;
             return false;
         }
         }
 
 
         // Data chunk.
         // Data chunk.
-        if (memcmp(stream, "data", 4) == 0)
+        if (memcmp(data, "data", 4) == 0)
         {
         {
             // Read how much data is remaining and buffer it up.
             // Read how much data is remaining and buffer it up.
             unsigned int dataSize;
             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.");
                 GP_ERROR("Failed to read size of data section from wave file.");
                 return false;
                 return false;
             }
             }
 
 
             char* data = new char[dataSize];
             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.");
                 GP_ERROR("Failed to load wave file; file is missing data.");
                 SAFE_DELETE_ARRAY(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.
             // Store the name of the chunk so we can report errors informatively.
             char chunk[5] = { 0 };
             char chunk[5] = { 0 };
-            memcpy(chunk, stream, 4);
+            memcpy(chunk, data, 4);
 
 
             // Read the chunk size.
             // 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);
                 GP_ERROR("Failed to read size of '%s' chunk from wave file.", chunk);
                 return false;
                 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.
             // 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);
                 GP_ERROR("Failed to seek past '%s' chunk in wave file.", chunk);
                 return false;
                 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;
     OggVorbis_File ogg_file;
     vorbis_info* info;
     vorbis_info* info;
@@ -316,11 +340,16 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     int section;
     int section;
     long size = 0;
     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.");
         GP_ERROR("Failed to open ogg file.");
         return false;
         return false;
     }
     }
@@ -367,9 +396,6 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     SAFE_DELETE_ARRAY(data);
     SAFE_DELETE_ARRAY(data);
     ov_clear(&ogg_file);
     ov_clear(&ogg_file);
 
 
-    // ov_clear actually closes the file pointer as well.
-    file = 0;
-
     return true;
     return true;
 }
 }
 
 

+ 3 - 2
gameplay/src/AudioBuffer.h

@@ -2,6 +2,7 @@
 #define AUDIOBUFFER_H_
 #define AUDIOBUFFER_H_
 
 
 #include "Ref.h"
 #include "Ref.h"
+#include "Stream.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -43,9 +44,9 @@ private:
      */
      */
     static AudioBuffer* create(const char* path);
     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;
     std::string _filePath;
     ALuint _alBuffer;
     ALuint _alBuffer;