music_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 17 Jun 2015 00:11:41 -0700
changeset 705 fe757163b8f7
parent 690 3d18eb009c89
child 711 f40c5ac95b12
permissions -rw-r--r--
Fixed bug 3018 - Loading MIDI music using FluidSynth leaks memory.

Philipp Wiesemann

There is a memory leak in fluidsynth.c and fluidsynth_loadsong_RW_internal(). The allocated temporary buffer is not deleted if fluid_player_add_mem() returns FLUID_OK.
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* $Id$ */
    23 
    24 #ifdef OGG_MUSIC
    25 
    26 /* This file supports Ogg Vorbis music streams */
    27 
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 
    32 #include "SDL_mixer.h"
    33 #include "dynamic_ogg.h"
    34 #include "music_ogg.h"
    35 
    36 /* This is the format of the audio mixer data */
    37 static SDL_AudioSpec mixer;
    38 
    39 /* Initialize the Ogg Vorbis player, with the given mixer settings
    40    This function returns 0, or -1 if there was an error.
    41  */
    42 int OGG_init(SDL_AudioSpec *mixerfmt)
    43 {
    44     mixer = *mixerfmt;
    45     return(0);
    46 }
    47 
    48 /* Set the volume for an OGG stream */
    49 void OGG_setvolume(OGG_music *music, int volume)
    50 {
    51     music->volume = volume;
    52 }
    53 
    54 static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
    55 {
    56     return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
    57 }
    58 
    59 static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
    60 {
    61     return (int)SDL_RWseek((SDL_RWops*)datasource, offset, whence);
    62 }
    63 
    64 static long sdl_tell_func(void *datasource)
    65 {
    66     return (long)SDL_RWtell((SDL_RWops*)datasource);
    67 }
    68 
    69 /* Load an OGG stream from an SDL_RWops object */
    70 OGG_music *OGG_new_RW(SDL_RWops *src, int freesrc)
    71 {
    72     OGG_music *music;
    73     ov_callbacks callbacks;
    74 
    75     if ( !Mix_Init(MIX_INIT_OGG) ) {
    76         return(NULL);
    77     }
    78 
    79     SDL_memset(&callbacks, 0, sizeof(callbacks));
    80     callbacks.read_func = sdl_read_func;
    81     callbacks.seek_func = sdl_seek_func;
    82     callbacks.tell_func = sdl_tell_func;
    83 
    84     music = (OGG_music *)SDL_malloc(sizeof *music);
    85     if ( music ) {
    86         /* Initialize the music structure */
    87         SDL_memset(music, 0, (sizeof *music));
    88         music->src = src;
    89         music->freesrc = freesrc;
    90         OGG_stop(music);
    91         OGG_setvolume(music, MIX_MAX_VOLUME);
    92         music->section = -1;
    93 
    94         if ( vorbis.ov_open_callbacks(src, &music->vf, NULL, 0, callbacks) < 0 ) {
    95             SDL_SetError("Not an Ogg Vorbis audio stream");
    96             SDL_free(music);
    97             return(NULL);
    98         }
    99     } else {
   100         SDL_OutOfMemory();
   101         return(NULL);
   102     }
   103     return(music);
   104 }
   105 
   106 /* Start playback of a given OGG stream */
   107 void OGG_play(OGG_music *music)
   108 {
   109     music->playing = 1;
   110 }
   111 
   112 /* Return non-zero if a stream is currently playing */
   113 int OGG_playing(OGG_music *music)
   114 {
   115     return(music->playing);
   116 }
   117 
   118 /* Read some Ogg stream data and convert it for output */
   119 static void OGG_getsome(OGG_music *music)
   120 {
   121     int section;
   122     int len;
   123     char data[4096];
   124     SDL_AudioCVT *cvt;
   125 
   126 #ifdef OGG_USE_TREMOR
   127     len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
   128 #else
   129     len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
   130 #endif
   131     if ( len <= 0 ) {
   132         if ( len == 0 ) {
   133             music->playing = 0;
   134         }
   135         return;
   136     }
   137     cvt = &music->cvt;
   138     if ( section != music->section ) {
   139         vorbis_info *vi;
   140 
   141         vi = vorbis.ov_info(&music->vf, -1);
   142         SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
   143                                mixer.format,mixer.channels,mixer.freq);
   144         if ( cvt->buf ) {
   145             SDL_free(cvt->buf);
   146         }
   147         cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
   148         music->section = section;
   149     }
   150     if ( cvt->buf ) {
   151         SDL_memcpy(cvt->buf, data, len);
   152         if ( cvt->needed ) {
   153             cvt->len = len;
   154             SDL_ConvertAudio(cvt);
   155         } else {
   156             cvt->len_cvt = len;
   157         }
   158         music->len_available = music->cvt.len_cvt;
   159         music->snd_available = music->cvt.buf;
   160     } else {
   161         SDL_SetError("Out of memory");
   162         music->playing = 0;
   163     }
   164 }
   165 
   166 /* Play some of a stream previously started with OGG_play() */
   167 int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
   168 {
   169     int mixable;
   170 
   171     while ( (len > 0) && music->playing ) {
   172         if ( ! music->len_available ) {
   173             OGG_getsome(music);
   174         }
   175         mixable = len;
   176         if ( mixable > music->len_available ) {
   177             mixable = music->len_available;
   178         }
   179         if ( music->volume == MIX_MAX_VOLUME ) {
   180             SDL_memcpy(snd, music->snd_available, mixable);
   181         } else {
   182             SDL_MixAudio(snd, music->snd_available, mixable,
   183                                           music->volume);
   184         }
   185         music->len_available -= mixable;
   186         music->snd_available += mixable;
   187         len -= mixable;
   188         snd += mixable;
   189     }
   190 
   191     return len;
   192 }
   193 
   194 /* Stop playback of a stream previously started with OGG_play() */
   195 void OGG_stop(OGG_music *music)
   196 {
   197     music->playing = 0;
   198 }
   199 
   200 /* Close the given OGG stream */
   201 void OGG_delete(OGG_music *music)
   202 {
   203     if ( music ) {
   204         if ( music->cvt.buf ) {
   205             SDL_free(music->cvt.buf);
   206         }
   207         if ( music->freesrc ) {
   208             SDL_RWclose(music->src);
   209         }
   210         vorbis.ov_clear(&music->vf);
   211         SDL_free(music);
   212     }
   213 }
   214 
   215 /* Jump (seek) to a given position (time is in seconds) */
   216 void OGG_jump_to_time(OGG_music *music, double time)
   217 {
   218 #ifdef OGG_USE_TREMOR
   219        vorbis.ov_time_seek( &music->vf, (ogg_int64_t)(time * 1000.0) );
   220 #else
   221        vorbis.ov_time_seek( &music->vf, time );
   222 #endif
   223 }
   224 
   225 #endif /* OGG_MUSIC */