Main Page Data Structures File List Data Fields Globals Related Pages

# mpbuf.cpp

Go to the documentation of this file.

    00001 /*  mpbuf.cpp
    00002     buffered mpeg stream functions.
    00003
    00004     17.09.2001: tk, stupid bug fixed. One assert for bufCount wasn't
    00005                     enclosed in a enable/disable, and caused sporadic
    00006                     errors (after ~2h of mp3 streaming..).
    00007     15.09.2001: tk, added disable/enable pairs, because the
    00008                     long integers could get updated by the callback
    00009                     in the middle of an access. (it really matters!)
    00010     12.09.2001: tk, the function calls are now similar to the
    00011                     DirectX Audio DSB interface. It's actually
    00012                     quite nice, and fits perfectly for the task.
    00013     10.08.2001: tk, initial implementation.
    00014
    00015     Copyright (c)2000 by Thomas Kindler, thomas.kindler@gmx.de
    00016
    00017     This program is free software; you can redistribute it and/or
    00018     modify it under the terms of the GNU General Public License as
    00019     published by the Free Software Foundation; either version 2 of
    00020     the License, or (at your option) any later version. Read the
    00021     full License at http://www.gnu.org/copyleft for more details.
    00022 */
    00023
    00024 // include files -----
    00025 //
    00026 #include <stdlib.h>
    00027 #include <stdio.h>
    00028 #include <alloc.h>
    00029 #include <assert.h>
    00030 #include <mem.h>
    00031 #include "clib/rtos.h"
    00032 #include "vs1001.h"
    00033 #include "mpbuf.h"
    00034
    00035 // farmalloc'd buffer for mpeg data
    00036 //
    00037 static char huge  *bufPtr;
    00038 static long        bufSize;
    00039
    00040 // current playing position, and number of bytes.
    00041 //
    00042 // ** IMPORTANT **
    00043 // The long volatiles may only be read or modified inside
    00044 // a disable/enable section. The callback function might get
    00045 // called in the middle of an access otherwise.
    00046 //
    00047 static volatile long  bufHead, bufCount;
    00048 static volatile int   bufState;
    00049 static long           bufThreshold;
    00050
    00051
    00058 void callback(void *param)
    00059 {
    00060   bufHead  += (long)param;
    00061   bufHead  %= bufSize;
    00062   bufCount -= (long)param;
    00063
    00064   if (bufState == BUF_STOPPING)
    00065     bufState = BUF_STOPPED;
    00066   if (bufState == BUF_PLAYING )
    00067     BUF_Play();
    00068 }
    00069
    00070
    00076 long BUF_GetSize()
    00077 {
    00078   return  bufSize;
    00079 }
    00080
    00081
    00086 long BUF_GetCount()
    00087 {
    00088   disable();
    00089   long count = bufCount;
    00090   enable();
    00091   return  count;
    00092 }
    00093
    00094
    00102 long BUF_GetFreeBytes()
    00103 {
    00104   return BUF_GetSize()-BUF_GetCount();
    00105 }
    00106
    00107
    00125 int  BUF_GetState()
    00126 {
    00127   return bufState;
    00128 }
    00129
    00130
    00146 void BUF_SetThreshold(long threshold)
    00147 {
    00148   bufThreshold = threshold;
    00149 }
    00150
    00151
    00164 void BUF_GetPositions(long *playpos, long *writepos)
    00165 {
    00166   disable();
    00167   if (playpos)
    00168     *playpos = bufHead;
    00169   if (writepos)
    00170     *writepos = (bufHead+bufCount) % bufSize;
    00171   enable();
    00172 }
    00173
    00174
    00202 void BUF_Lock(long offset, long length,
    00203               char **buf1, long *len1,
    00204               char **buf2, long *len2 )
    00205 {
    00206   if (offset == BUF_FROMWRITEPOS)
    00207     BUF_GetPositions(NULL, &offset);
    00208
    00209   offset = offset % bufSize;
    00210   if (length > bufSize)
    00211     length = bufSize;
    00212
    00213   *buf1 = &bufPtr[offset];
    00214   *len1 = min(length, bufSize-offset);
    00215   if (buf2 && len2) {
    00216     if (*len1 < length) {
    00217       *buf2 = bufPtr;
    00218       *len2 = length - *len1;
    00219     } else {
    00220       *buf2 = NULL;
    00221       *len2 = 0;
    00222     }
    00223   }
    00224 }
    00225
    00226
    00237 void BUF_Unlock(long bytesWritten)
    00238 {
    00239   disable();
    00240   bufCount += bytesWritten;
    00241   bool   ok = bufCount <= bufSize;
    00242   enable();
    00243   assert(ok);
    00244
    00245   // continue playback (if buffer was stalled)
    00246   //
    00247   if (bufState == BUF_STALLED &&
    00248       bufCount >= bufThreshold)
    00249     BUF_Play();
    00250 }
    00251
    00252
    00273 unsigned BUF_Write(char *src, unsigned length)
    00274 {
    00275   char *buf1, *buf2;
    00276   long  len1,  len2;
    00277
    00278   length = min(length, BUF_GetFreeBytes());
    00279
    00280   BUF_Lock( BUF_FROMWRITEPOS, length,
    00281             &buf1, &len1, &buf2, &len2);
    00282
    00283   memcpy(buf1, src, len1);
    00284   if (buf2)
    00285     memcpy(buf2, &src[len1], len2);
    00286   BUF_Unlock(len1+len2);
    00287
    00288   return len1+len2;
    00289 }
    00290
    00291
    00306 void BUF_Play()
    00307 {
    00308   if (BUF_GetCount() == 0) {
    00309     bufState = BUF_STALLED;
    00310   } else if (VS_IsPlaying()) {
    00311     bufState = BUF_PLAYING;
    00312   } else {
    00313     char *buf1;
    00314     long  len1 = BUF_GetCount();
    00315
    00316     if (len1 > VS_FIFOSIZE)
    00317       len1 = VS_FIFOSIZE;
    00318
    00319     BUF_Lock(bufHead, len1, &buf1, &len1, NULL, NULL);
    00320     VS_PlayMpegAsync(buf1, len1, callback, (void*)len1);
    00321
    00322     bufState = BUF_PLAYING;
    00323   }
    00324 }
    00325
    00326
    00333 void BUF_Stop()
    00334 {
    00335   if (bufState == BUF_STALLED)
    00336     bufState = BUF_STOPPED;
    00337   else if (bufState == BUF_PLAYING)
    00338     bufState = BUF_STOPPING;
    00339 }
    00340
    00341
    00346 void BUF_Flush()
    00347 {
    00348   BUF_Play();
    00349   while (bufState != BUF_STALLED)
    00350     RTX_Sleep_Time(10);
    00351   BUF_Stop();
    00352 }
    00353
    00354
    00359 void BUF_Clear()
    00360 {
    00361   BUF_Stop();
    00362   while (bufState != BUF_STOPPED) {};
    00363
    00364   bufCount = 0;
    00365   bufHead  = 0;
    00366 }
    00367
    00368
    00382 long BUF_Init(long minsize, long maxsize)
    00383 {
    00384   printf("BUF_Init: ");
    00385
    00386   bufSize = maxsize;
    00387   while (bufSize >= minsize) {
    00388     bufPtr = (char*)farmalloc(bufSize);
    00389     if (bufPtr)
    00390       break;
    00391     bufSize -= 16*1024;
    00392   }
    00393
    00394   if (bufPtr) {
    00395     printf( "allocated %ldkb at %p.\n", bufSize>>10, bufPtr );
    00396   } else {
    00397     printf( "couldn't allocate at least %ld bytes.\n", minsize);
    00398     bufSize = 0;
    00399   }
    00400
    00401   bufState     = BUF_STOPPED;
    00402   bufHead      = 0;
    00403   bufCount     = 0;
    00404   bufThreshold = VS_FIFOSIZE;
    00405   return bufSize;
    00406 }
    00407
    00408
    00413 void BUF_Done()
    00414 {
    00415   BUF_Stop();
    00416   if (bufPtr)
    00417     farfree(bufPtr);
    00418   bufSize=0;
    00419 }
    00420