2014-03-11 07:13:31 +00:00
|
|
|
/*
|
|
|
|
* This file is subject to the terms of the GFX License. If a copy of
|
|
|
|
* the license was not distributed with this file, you can obtain one at:
|
|
|
|
*
|
|
|
|
* http://ugfx.org/license.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file src/gaudio/gaudio.c
|
|
|
|
* @brief GAUDIO sub-system code.
|
|
|
|
*
|
|
|
|
* @addtogroup GAUDIO
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
#include "gfx.h"
|
|
|
|
|
|
|
|
#if GFX_USE_GAUDIO
|
|
|
|
|
|
|
|
#if GAUDIO_NEED_PLAY
|
|
|
|
#include "src/gaudio/driver_play.h"
|
|
|
|
|
|
|
|
static gfxQueueASync playList;
|
|
|
|
static gfxSem playComplete;
|
|
|
|
static uint16_t playFlags;
|
|
|
|
#define PLAYFLG_USEEVENTS 0x0001
|
|
|
|
#define PLAYFLG_PLAYING 0x0002
|
|
|
|
#define PLAYFLG_ISINIT 0x0004
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
static GTimer playTimer;
|
|
|
|
static void PlayTimerCallback(void *param);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if GAUDIO_NEED_RECORD
|
|
|
|
#include "src/gaudio/driver_record.h"
|
|
|
|
|
|
|
|
static gfxQueueGSync recordList;
|
|
|
|
static uint16_t recordFlags;
|
|
|
|
#define RECORDFLG_USEEVENTS 0x0001
|
|
|
|
#define RECORDFLG_RECORDING 0x0002
|
|
|
|
#define RECORDFLG_STALLED 0x0004
|
|
|
|
#define RECORDFLG_ISINIT 0x0008
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
static GTimer recordTimer;
|
|
|
|
static void RecordTimerCallback(void *param);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void _gaudioInit(void)
|
|
|
|
{
|
|
|
|
#if GAUDIO_NEED_PLAY
|
|
|
|
gfxQueueASyncInit(&playList);
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
gtimerInit(&playTimer);
|
|
|
|
#endif
|
|
|
|
gfxSemInit(&playComplete, 0, 0);
|
|
|
|
#endif
|
|
|
|
#if GAUDIO_NEED_RECORD
|
|
|
|
gfxQueueGSyncInit(&recordList);
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
gtimerInit(&recordTimer);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void _gaudioDeinit(void)
|
|
|
|
{
|
|
|
|
#if GAUDIO_NEED_PLAY
|
2014-03-20 13:33:32 +00:00
|
|
|
gfxQueueASyncDeinit(&playList);
|
2014-03-11 07:13:31 +00:00
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
gtimerDeinit(&playTimer);
|
|
|
|
#endif
|
|
|
|
gfxSemDestroy(&playComplete);
|
|
|
|
#endif
|
|
|
|
#if GAUDIO_NEED_RECORD
|
2014-03-20 13:33:32 +00:00
|
|
|
gfxQueueGSyncDeinit(&recordList);
|
2014-03-11 07:13:31 +00:00
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
gtimerDeinit(&recordTimer);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if GAUDIO_NEED_PLAY
|
|
|
|
|
|
|
|
bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
|
|
|
|
gaudioPlayStop();
|
|
|
|
playFlags &= ~PLAYFLG_ISINIT;
|
|
|
|
if (!gaudio_play_lld_init(channel, frequency, format))
|
|
|
|
return FALSE;
|
|
|
|
playFlags |= PLAYFLG_ISINIT;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-03-20 13:33:32 +00:00
|
|
|
void gaudioPlay(GDataBuffer *pd) {
|
2014-03-11 07:13:31 +00:00
|
|
|
if (!(playFlags & PLAYFLG_ISINIT)) {
|
|
|
|
// Oops - init failed - return it directly to the free-list
|
2014-03-20 13:33:32 +00:00
|
|
|
if (pd) {
|
|
|
|
gfxBufferRelease(pd);
|
2014-03-11 07:13:31 +00:00
|
|
|
gfxYield(); // Make sure we get no endless cpu hogging loops
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-30 09:06:29 +00:00
|
|
|
if (pd)
|
|
|
|
gfxQueueASyncPut(&playList, (gfxQueueASyncItem *)pd);
|
2014-03-11 07:13:31 +00:00
|
|
|
playFlags |= PLAYFLG_PLAYING;
|
|
|
|
gaudio_play_lld_start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioPlayPause(void) {
|
|
|
|
if ((playFlags & (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) == (PLAYFLG_ISINIT|PLAYFLG_PLAYING))
|
|
|
|
gaudio_play_lld_stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioPlayStop(void) {
|
2014-03-20 13:33:32 +00:00
|
|
|
GDataBuffer *pd;
|
2014-03-11 07:13:31 +00:00
|
|
|
|
|
|
|
if (playFlags & PLAYFLG_PLAYING)
|
|
|
|
gaudio_play_lld_stop();
|
2014-03-20 13:33:32 +00:00
|
|
|
while((pd = (GDataBuffer *)gfxQueueASyncGet(&playList)))
|
|
|
|
gfxBufferRelease(pd);
|
2014-03-11 07:13:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool_t gaudioPlaySetVolume(uint8_t vol) {
|
|
|
|
return gaudio_play_lld_set_volume(vol);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool_t gaudioPlayWait(delaytime_t ms) {
|
|
|
|
if (!(playFlags & PLAYFLG_PLAYING))
|
|
|
|
return TRUE;
|
|
|
|
return gfxSemWait(&playComplete, ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
static void PlayTimerCallback(void *param) {
|
|
|
|
(void) param;
|
|
|
|
GSourceListener *psl;
|
|
|
|
GEventAudioPlay *pe;
|
|
|
|
|
|
|
|
psl = 0;
|
|
|
|
while ((psl = geventGetSourceListener((GSourceHandle)&playTimer, psl))) {
|
|
|
|
if (!(pe = (GEventAudioPlay *)geventGetEventBuffer(psl))) {
|
|
|
|
// This listener is missing - save this.
|
|
|
|
psl->srcflags |= GAUDIO_PLAY_LOSTEVENT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pe->type = GEVENT_AUDIO_PLAY;
|
|
|
|
pe->flags = psl->srcflags;
|
|
|
|
psl->srcflags = 0;
|
|
|
|
if ((playFlags & PLAYFLG_PLAYING))
|
|
|
|
pe->flags |= GAUDIO_PLAY_PLAYING;
|
2014-03-20 13:33:32 +00:00
|
|
|
if (gfxBufferIsAvailable())
|
2014-03-11 07:13:31 +00:00
|
|
|
pe->flags |= GAUDIO_PLAY_FREEBLOCK;
|
|
|
|
geventSendEvent(psl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GSourceHandle gaudioPlayGetSource(void) {
|
|
|
|
if (!gtimerIsActive(&playTimer))
|
|
|
|
gtimerStart(&playTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE);
|
|
|
|
playFlags |= PLAYFLG_USEEVENTS;
|
|
|
|
return (GSourceHandle)&playTimer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Routines provided for use by drivers.
|
|
|
|
*/
|
|
|
|
|
2014-03-20 13:33:32 +00:00
|
|
|
GDataBuffer *gaudioPlayGetDataBlockI(void) {
|
|
|
|
return (GDataBuffer *)gfxQueueASyncGetI(&playList);
|
2014-03-11 07:13:31 +00:00
|
|
|
}
|
|
|
|
|
2014-03-20 13:33:32 +00:00
|
|
|
void gaudioPlayReleaseDataBlockI(GDataBuffer *pd) {
|
|
|
|
gfxBufferReleaseI(pd);
|
2014-03-11 07:13:31 +00:00
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
if (playFlags & PLAYFLG_USEEVENTS)
|
|
|
|
gtimerJabI(&playTimer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioPlayDoneI(void) {
|
|
|
|
playFlags &= ~PLAYFLG_PLAYING;
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
if (playFlags & PLAYFLG_USEEVENTS)
|
|
|
|
gtimerJabI(&playTimer);
|
|
|
|
#endif
|
|
|
|
gfxSemSignalI(&playComplete); // This should really be gfxSemSignalAllI(&playComplete);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if GAUDIO_NEED_RECORD
|
|
|
|
bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
|
|
|
|
gaudioRecordStop();
|
|
|
|
recordFlags &= ~RECORDFLG_ISINIT;
|
|
|
|
if (!gaudio_record_lld_init(channel, frequency, format))
|
|
|
|
return FALSE;
|
|
|
|
recordFlags |= RECORDFLG_ISINIT;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioRecordStart(void) {
|
|
|
|
if (!(recordFlags & RECORDFLG_ISINIT))
|
|
|
|
return; // Oops - init failed
|
|
|
|
|
|
|
|
recordFlags |= RECORDFLG_RECORDING;
|
|
|
|
recordFlags &= ~RECORDFLG_STALLED;
|
|
|
|
gaudio_record_lld_start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioRecordStop(void) {
|
2014-03-20 13:33:32 +00:00
|
|
|
GDataBuffer *pd;
|
2014-03-11 07:13:31 +00:00
|
|
|
|
|
|
|
if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING)
|
|
|
|
gaudio_record_lld_stop();
|
|
|
|
recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED);
|
2014-03-20 13:33:32 +00:00
|
|
|
while((pd = (GDataBuffer *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE)))
|
|
|
|
gfxBufferRelease(pd);
|
2014-03-11 07:13:31 +00:00
|
|
|
}
|
|
|
|
|
2014-03-20 13:33:32 +00:00
|
|
|
GDataBuffer *gaudioRecordGetData(delaytime_t ms) {
|
|
|
|
return (GDataBuffer *)gfxQueueGSyncGet(&recordList, ms);
|
2014-03-11 07:13:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
static void RecordTimerCallback(void *param) {
|
|
|
|
(void) param;
|
|
|
|
GSourceListener *psl;
|
|
|
|
GEventAudioRecord *pe;
|
|
|
|
|
|
|
|
psl = 0;
|
|
|
|
while ((psl = geventGetSourceListener((GSourceHandle)&recordTimer, psl))) {
|
|
|
|
if (!(pe = (GEventAudioRecord *)geventGetEventBuffer(psl))) {
|
|
|
|
// This listener is missing - save this.
|
|
|
|
psl->srcflags |= GAUDIO_RECORD_LOSTEVENT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pe->type = GEVENT_AUDIO_RECORD;
|
|
|
|
pe->flags = psl->srcflags;
|
|
|
|
psl->srcflags = 0;
|
|
|
|
if ((recordFlags & RECORDFLG_RECORDING))
|
|
|
|
pe->flags |= GAUDIO_RECORD_RECORDING;
|
|
|
|
if ((recordFlags & RECORDFLG_STALLED))
|
|
|
|
pe->flags |= GAUDIO_RECORD_STALL;
|
|
|
|
if (!gfxQueueGSyncIsEmpty(&recordList))
|
2014-03-20 13:33:32 +00:00
|
|
|
pe->flags |= GAUDIO_RECORD_GOTBUFFER;
|
2014-03-11 07:13:31 +00:00
|
|
|
geventSendEvent(psl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GSourceHandle gaudioRecordGetSource(void) {
|
|
|
|
if (!gtimerIsActive(&recordTimer))
|
|
|
|
gtimerStart(&recordTimer, RecordTimerCallback, 0, TRUE, TIME_INFINITE);
|
|
|
|
recordFlags |= RECORDFLG_USEEVENTS;
|
|
|
|
return (GSourceHandle)&recordTimer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Routines provided for use by drivers.
|
|
|
|
*/
|
|
|
|
|
2014-03-20 13:33:32 +00:00
|
|
|
void gaudioRecordSaveDataBlockI(GDataBuffer *paud) {
|
2014-03-11 07:13:31 +00:00
|
|
|
gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud);
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
if (recordFlags & RECORDFLG_USEEVENTS)
|
|
|
|
gtimerJabI(&recordTimer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gaudioRecordDoneI(void) {
|
|
|
|
recordFlags |= RECORDFLG_STALLED;
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
if (recordFlags & RECORDFLG_USEEVENTS)
|
|
|
|
gtimerJabI(&recordTimer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* GFX_USE_GAUDIO */
|
|
|
|
/** @} */
|