diff --git a/player/audioplayer.c b/player/audioplayer.c new file mode 100644 --- /dev/null +++ b/player/audioplayer.c @@ -0,0 +1,228 @@ +/** + * $Id: audioplayer.c 53 2008-01-10 00:19:41Z mbroeker $ + * $URL: http://localhost/svn/c/VirtualReader/trunk/player/audioplayer.c $ + */ + +#include + +typedef struct { + SDL_AudioSpec spec; // internal structure + Uint8 *sound_buffer; // malloced pointer from sdl + Uint32 sound_pos; // position + Uint32 sound_len; // length in bytes + Uint32 length; // Length in Milliseconds + + int opened; // bool opened + int loaded; // bool loaded + int verbose; // verbose messages + int timeout; // timeout + int timer; // bool timer +} AudioDevice; + +AudioDevice AD; + +int audio_init () +{ + // initialize SDL for audio output + if (SDL_Init (SDL_INIT_AUDIO) < 0) { + fprintf (stderr, "audio_init: Cannot initialize SDL-Subsystem\n"); + return -1; + } + + AD.sound_buffer = 0; + AD.sound_pos = 0; + AD.sound_len = 0; + + AD.opened = 0; + AD.loaded = 0; + AD.verbose = 0; + + AD.timeout = 0; + AD.timer = 0; + + return 0; +} + +void audio_shutdown () +{ + // quit sdl + SDL_AudioQuit (); + SDL_Quit (); +} + +static void Callback (void *userdata, Uint8 * stream, int len) +{ + Uint8 *waveptr = NULL; + + /* + * loaded = 0 Segmentation fault + * len = 0 nothing to play + */ + if (!(AD.loaded && len)) + return; + + waveptr = AD.sound_buffer + AD.sound_pos; + SDL_MixAudio (stream, waveptr, len, SDL_MIX_MAXVOLUME); + AD.sound_pos += len; // bereits gespielt + + if (audioplayer_gettime () > (AD.length - AD.timeout)) { + AD.sound_pos = AD.length; + AD.sound_len = 0; + AD.timer = 0; + } +} + +Uint32 audioplayer_getsoundlen () +{ + return AD.sound_len; +} + +void audioplayer_media_info (char *fname) +{ + AD.length = audioplayer_getwavelength (fname); + + printf ("Playing %s: %d Hz, %d Bit Audio, %d Channel(s), %3.2d ms\n", + fname, AD.spec.freq, audioplayer_getbitrate (), AD.spec.channels, AD.length); +} + +int audioplayer_getbitrate () +{ + int bitrate = 0; + + switch (AD.spec.format) { + case AUDIO_U8: + case AUDIO_S8: + bitrate = 8; + break; + case AUDIO_S16LSB: + case AUDIO_S16MSB: + case AUDIO_U16LSB: + case AUDIO_U16MSB: + bitrate = 16; + break; + } + + return bitrate; +} + +Uint32 audioplayer_getwavelength (char *fname) +{ + struct stat info; + Uint32 value = 0; + + if (fname == NULL) + return AD.length; + + if (stat (fname, &info) == 0) + /* + * the value is really big, so be carefull + * changes in the order result in different values + * the storage type isn`t well choosen... + */ + value = ((info.st_size) / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0); + + return (value); +} + +Uint32 audioplayer_getposition () +{ + return AD.sound_pos; +} + +Uint32 audioplayer_gettime () +{ + Uint32 ret; + + ret = AD.sound_pos / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0; + + return ret; +} + +void audioplayer_settime (long tm) +{ + AD.sound_pos = tm / 1000.0 * (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)); + + /* + * Eine Adresse ... + */ + while ((AD.sound_pos % 2) != 0) + AD.sound_pos++; + + if (AD.verbose) + printf ("\e[31m[ATTENTION]\e[37m [#%d/#%d] = %d ms\n", AD.sound_pos, AD.sound_len, audioplayer_gettime ()); +} + +void audioplayer_stop () +{ + /* + * stops the callback function + */ + SDL_PauseAudio (1); + AD.spec.callback = NULL; + + if (AD.loaded == 1) + SDL_FreeWAV (AD.sound_buffer); + + AD.loaded = 0; + AD.timer = 0; +} + +void audioplayer_delay (Uint32 milliseconds) +{ + struct timespec tm; + + tm.tv_sec = 0; + tm.tv_nsec = milliseconds * 1000; + + while (AD.timer) + nanosleep (&tm, NULL); +} + +void audioplayer_setverbose (int verbose) +{ + AD.verbose = verbose; +} + +int audioplayer (char *fname, Uint32 timeout) +{ + if (SDL_LoadWAV (fname, &AD.spec, &AD.sound_buffer, &AD.sound_len) == NULL) { + printf ("SDL: %s\n", SDL_GetError ()); + return -1; + } + + AD.loaded = 1; + + if (!AD.opened) { + AD.spec.callback = Callback; + if (SDL_OpenAudio (&AD.spec, NULL) < 0) { + fprintf (stderr, "Cannot open audio device: %s\n", SDL_GetError ()); + return -1; + } + AD.opened = 1; + } + + /* + * calls implicitly getwavelength + */ + audioplayer_media_info (fname); + + AD.sound_pos = 0; + + /* + * starts playback via Callback function + */ + SDL_PauseAudio (0); + + /* + * initializes the timeout mechanism + */ + AD.timer = 1; + AD.timeout = timeout; + + /* + * controlled delay + */ + audioplayer_delay (timeout); + + return 0; +}