/*---------------------------------------------------------------------------- * * File: * jet.c * * Contents and purpose: * Implementation for JET sound engine * * Copyright (c) 2006 Sonic Network Inc. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *---------------------------------------------------------------------------- * Revision Control: * $Revision: 563 $ * $Date: 2007-02-13 20:26:23 -0800 (Tue, 13 Feb 2007) $ *---------------------------------------------------------------------------- */ //#define LOG_NDEBUG 0 #define LOG_TAG "JET_C" //#define DEBUG_JET #include "eas_data.h" #include "eas_smf.h" #include "jet_data.h" #include "eas_host.h" #include "eas_report.h" /* default configuration */ static const S_JET_CONFIG jetDefaultConfig = { JET_EVENT_APP_LOW, JET_EVENT_APP_HIGH }; /* function prototypes */ extern EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value); extern EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream); extern EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS); /*---------------------------------------------------------------------------- * JET_ParseEvent() *---------------------------------------------------------------------------- * Returns current status *---------------------------------------------------------------------------- */ EAS_PUBLIC void JET_ParseEvent (EAS_U32 event, S_JET_EVENT *pEvent) { pEvent->segment = (EAS_U8) ((event & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT); pEvent->track = (EAS_U8) ((event & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); pEvent->channel = (EAS_U8) ((event & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT); pEvent->controller = (EAS_U8) ((event & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT); pEvent->value = (EAS_U8) (event & JET_EVENT_VAL_MASK); } #ifdef DEBUG_JET /*---------------------------------------------------------------------------- * JET_DumpEvent *---------------------------------------------------------------------------- * Advances queue read/write index *---------------------------------------------------------------------------- */ static void JET_DumpEvent (const char *procName, EAS_U32 event) { S_JET_EVENT sEvent; JET_ParseEvent(event, &sEvent); { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "%s: SegID=%d, TrkID=%d, channel=%d, ctrl=%d, val=%d\n", procName, sEvent.segment, sEvent.track, sEvent.channel, sEvent.controller, sEvent.value); */ } } #endif /*---------------------------------------------------------------------------- * JET_IncQueueIndex *---------------------------------------------------------------------------- * Advances queue read/write index *---------------------------------------------------------------------------- */ EAS_INLINE EAS_U8 JET_IncQueueIndex (EAS_U8 index, EAS_U8 queueSize) { if (++index == queueSize) index = 0; return index; } /*---------------------------------------------------------------------------- * JET_WriteQueue *---------------------------------------------------------------------------- * Save event to queue *---------------------------------------------------------------------------- */ EAS_INLINE void JET_WriteQueue (EAS_U32 *pEventQueue, EAS_U8 *pWriteIndex, EAS_U8 readIndex, EAS_U8 queueSize, EAS_U32 event) { EAS_U8 temp; /* check for queue overflow */ temp = JET_IncQueueIndex(*pWriteIndex, queueSize); if (temp == readIndex) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "JET_Event: Event queue overflow --- event ignored!\n"); */ } return; } /* save in queue and advance write index */ pEventQueue[*pWriteIndex] = event; *pWriteIndex = temp; } /*---------------------------------------------------------------------------- * JET_ReadQueue *---------------------------------------------------------------------------- * Read event to queue *---------------------------------------------------------------------------- */ EAS_INLINE EAS_BOOL JET_ReadQueue (EAS_U32 *pEventQueue, EAS_U8 *pReadIndex, EAS_U8 writeIndex, EAS_U8 queueSize, EAS_U32 *pEvent) { /* check for empty queue */ if (*pReadIndex == writeIndex) return EAS_FALSE; /* save in queue and advance write index */ *pEvent = pEventQueue[*pReadIndex]; *pReadIndex = JET_IncQueueIndex(*pReadIndex, queueSize); return EAS_TRUE; } /*---------------------------------------------------------------------------- * JET_NextSegment *---------------------------------------------------------------------------- * Advances segment number *---------------------------------------------------------------------------- */ EAS_INLINE EAS_INT JET_NextSegment (EAS_INT seg_num) { if (++seg_num == SEG_QUEUE_DEPTH) seg_num = 0; return seg_num; } /*---------------------------------------------------------------------------- * JET_PrepareSegment() *---------------------------------------------------------------------------- * Prepare a segment for playback *---------------------------------------------------------------------------- */ static EAS_RESULT JET_PrepareSegment (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) { EAS_RESULT result; S_JET_SEGMENT *p; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_PrepareSegment: %d\n", queueNum); */ } p = &easHandle->jetHandle->segQueue[queueNum]; result = EAS_Prepare(easHandle, p->streamHandle); if (result != EAS_SUCCESS) return result; /* pause segment - must be triggered by play or end of previous segment */ result = EAS_Pause(easHandle, p->streamHandle); if (result != EAS_SUCCESS) return result; p->state = JET_STATE_READY; /* set calback data */ result = EAS_IntSetStrmParam(easHandle, p->streamHandle, PARSER_DATA_JET_CB, queueNum); if (result != EAS_SUCCESS) return result; /* set DLS collection */ if (p->libNum >= 0) { result = EAS_IntSetStrmParam(easHandle, p->streamHandle, PARSER_DATA_DLS_COLLECTION, (EAS_I32) easHandle->jetHandle->libHandles[p->libNum]); if (result != EAS_SUCCESS) return result; } /* set transposition */ if (p->transpose) { result = EAS_SetTransposition(easHandle, p->streamHandle, p->transpose); if (result != EAS_SUCCESS) return result; } return result; } /*---------------------------------------------------------------------------- * JET_StartPlayback() *---------------------------------------------------------------------------- * Start segment playback *---------------------------------------------------------------------------- */ static EAS_RESULT JET_StartPlayback (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) { EAS_RESULT result = EAS_SUCCESS; S_JET_SEGMENT *pSeg; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_StartPlayback %d\n", queueNum); */ } /* if next segment is queued, start playback */ pSeg = &easHandle->jetHandle->segQueue[queueNum]; if (pSeg->streamHandle != NULL) { result = EAS_Resume(easHandle, pSeg->streamHandle); easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_PLAYING; /* set mute flags */ if ((result == EAS_SUCCESS) && (pSeg->muteFlags != 0)) result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); } return result; } /*---------------------------------------------------------------------------- * JET_CloseSegment *---------------------------------------------------------------------------- * Closes stream associated with a segment *---------------------------------------------------------------------------- */ EAS_INLINE EAS_INT JET_CloseSegment (EAS_DATA_HANDLE easHandle, EAS_INT queueNum) { EAS_RESULT result; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_CloseSegment %d\n", queueNum); */ } /* close the segment */ result = EAS_CloseFile(easHandle, easHandle->jetHandle->segQueue[queueNum].streamHandle); if (result != EAS_SUCCESS) return result; easHandle->jetHandle->segQueue[queueNum].streamHandle = NULL; easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_CLOSED; easHandle->jetHandle->numQueuedSegments--; return result; } /*---------------------------------------------------------------------------- * JetParseInfoChunk() *---------------------------------------------------------------------------- * Parses the JET info chunk *---------------------------------------------------------------------------- */ static EAS_RESULT JetParseInfoChunk (EAS_DATA_HANDLE easHandle, EAS_I32 pos, EAS_I32 chunkSize) { EAS_RESULT result; EAS_U32 infoType; EAS_U32 temp; /* offset to data */ result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); if (result != EAS_SUCCESS) return result; /* read the entire chunk */ result = EAS_SUCCESS; while ((result == EAS_SUCCESS) && (chunkSize > 0)) { /* get info infoType */ result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &infoType, EAS_TRUE); if (result != EAS_SUCCESS) break; /* get info field */ result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &temp, EAS_FALSE); if (result == EAS_SUCCESS) switch (infoType) { case INFO_NUM_SMF_CHUNKS: easHandle->jetHandle->numSegments = (EAS_U8) temp; break; case INFO_NUM_DLS_CHUNKS: easHandle->jetHandle->numLibraries = (EAS_U8) temp; break; case INFO_JET_VERSION: /* check major version number */ if ((temp & 0xff000000) != (JET_VERSION & 0xff000000)) return EAS_ERROR_INCOMPATIBLE_VERSION; break; default: { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET info type 0x%08x", infoType); */ } break; } chunkSize -= 8; } /* allocate pointers for chunks to follow */ return result; } /*---------------------------------------------------------------------------- * JET_OpenFile() *---------------------------------------------------------------------------- * Opens a JET content file for playback *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator) { EAS_RESULT result; EAS_U32 chunkType; EAS_I32 pos; EAS_I32 chunkSize; EAS_INT smfChunkNum; EAS_INT dlsChunkNum; EAS_I32 dataSize = 0; /* make lint happy */ /* make sure that we don't have an open file */ if (easHandle->jetHandle->jetFileHandle != NULL) return EAS_ERROR_FILE_ALREADY_OPEN; /* open the media file */ result = EAS_HWOpenFile(easHandle->hwInstData, locator, &easHandle->jetHandle->jetFileHandle, EAS_FILE_READ); if (result != EAS_SUCCESS) return result; /* check header */ result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); if (result == EAS_SUCCESS) { if (chunkType != JET_HEADER_TAG) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "File is not JET format\n"); */ } result = EAS_ERROR_UNRECOGNIZED_FORMAT; } } /* get the file data size */ if (result == EAS_SUCCESS) result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &dataSize, EAS_FALSE); /* parse through the file to find contents */ smfChunkNum = dlsChunkNum = 0; pos = chunkSize = 8; while ((result == EAS_SUCCESS) && (pos < dataSize)) { /* offset to chunk data */ result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); if (result != EAS_SUCCESS) break; /* get chunk size and type */ result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); if (result != EAS_SUCCESS) break; result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkSize, EAS_FALSE); if (result != EAS_SUCCESS) break; pos += 8; switch (chunkType) { case JET_INFO_CHUNK: result = JetParseInfoChunk(easHandle, pos, chunkSize); break; case JET_SMF_CHUNK: if (smfChunkNum < easHandle->jetHandle->numSegments) easHandle->jetHandle->segmentOffsets[smfChunkNum++] = pos; else { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous SMF chunk"); */ } break; case JET_DLS_CHUNK: if (dlsChunkNum < easHandle->jetHandle->numLibraries) result = DLSParser(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos, &easHandle->jetHandle->libHandles[dlsChunkNum++]); else { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous DLS chunk"); */ } break; case JET_APP_DATA_CHUNK: easHandle->jetHandle->appDataOffset = pos; easHandle->jetHandle->appDataSize = chunkSize; break; case INFO_JET_COPYRIGHT: break; default: { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET chunk type 0x%08x", chunkType); */ } break; } /* offset to next chunk */ pos += chunkSize; } /* close file if something went wrong */ if (result != EAS_SUCCESS) EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); return result; } /*---------------------------------------------------------------------------- * JET_GetAppData() *---------------------------------------------------------------------------- * Returns location and size of application data in the JET file *---------------------------------------------------------------------------- */ EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize) { /* check for app chunk */ if (easHandle->jetHandle->appDataSize == 0) { *pAppDataOffset = *pAppDataSize = 0; return EAS_FAILURE; } /* return app data */ *pAppDataOffset = easHandle->jetHandle->appDataOffset; *pAppDataSize = easHandle->jetHandle->appDataSize; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_CloseFile() *---------------------------------------------------------------------------- * Closes a JET content file and releases associated resources *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle) { EAS_INT index; EAS_RESULT result = EAS_SUCCESS; /* close open streams */ for (index = 0; index < SEG_QUEUE_DEPTH; index++) { if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) { result = JET_CloseSegment(easHandle, index); if (result != EAS_SUCCESS) break; } } /* close the main file handle */ if ((result == EAS_SUCCESS) && (easHandle->jetHandle->jetFileHandle != NULL)) { result = EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); if (result == EAS_SUCCESS) easHandle->jetHandle->jetFileHandle = NULL; } return result; } /*---------------------------------------------------------------------------- * JET_Init() *---------------------------------------------------------------------------- * Initializes the JET library, allocates memory, etc. Call * JET_Shutdown to de-allocate memory. *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize) { S_JET_DATA *pJet; EAS_U8 flags = 0; /* sanity check */ if (easHandle == NULL) return EAS_ERROR_HANDLE_INTEGRITY; if (easHandle->jetHandle != NULL) return EAS_ERROR_FEATURE_ALREADY_ACTIVE; if (pConfig == NULL) pConfig = &jetDefaultConfig; /* allocate the JET data object */ pJet = EAS_HWMalloc(easHandle->hwInstData, sizeof(S_JET_DATA)); if (pJet == NULL) return EAS_ERROR_MALLOC_FAILED; /* initialize JET data structure */ EAS_HWMemSet(pJet, 0, sizeof(S_JET_DATA)); easHandle->jetHandle = pJet; pJet->flags = flags; /* copy config data */ if (configSize > (EAS_INT) sizeof(S_JET_CONFIG)) configSize = sizeof(S_JET_CONFIG); EAS_HWMemCpy(&pJet->config, pConfig, configSize); return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_Shutdown() *---------------------------------------------------------------------------- * Frees any memory used by the JET library *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle) { EAS_RESULT result; /* close any open files */ result = JET_CloseFile(easHandle); /* free allocated data */ EAS_HWFree(easHandle->hwInstData, easHandle->jetHandle); easHandle->jetHandle = NULL; return result; } /*---------------------------------------------------------------------------- * JET_Status() *---------------------------------------------------------------------------- * Returns current status *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus) { S_JET_SEGMENT *pSeg; pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; if (pSeg->streamHandle != NULL) { pStatus->currentUserID = pSeg->userID; pStatus->segmentRepeatCount = pSeg->repeatCount; } else { pStatus->currentUserID = -1; pStatus->segmentRepeatCount = 0; } pStatus->paused = !(easHandle->jetHandle->flags & JET_FLAGS_PLAYING); pStatus->numQueuedSegments = easHandle->jetHandle->numQueuedSegments; pStatus->currentPlayingSegment = easHandle->jetHandle->playSegment; pStatus->currentQueuedSegment = easHandle->jetHandle->queueSegment; if (pSeg->streamHandle != NULL) { EAS_RESULT result; EAS_I32 location ; if ((result = EAS_GetLocation(easHandle, pSeg->streamHandle, &location)) == EAS_SUCCESS) if(location != 0) { pStatus->location = location; } } return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_GetEvent() *---------------------------------------------------------------------------- * Checks for application events *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent) { EAS_U32 jetEvent; EAS_BOOL gotEvent; /* process event queue */ gotEvent = JET_ReadQueue(easHandle->jetHandle->appEventQueue, &easHandle->jetHandle->appEventQueueRead, easHandle->jetHandle->appEventQueueWrite, APP_EVENT_QUEUE_SIZE, &jetEvent); if (gotEvent) { if (pEventRaw != NULL) *pEventRaw = jetEvent; if (pEvent != NULL) JET_ParseEvent(jetEvent, pEvent); } return gotEvent; } /*---------------------------------------------------------------------------- * JET_QueueSegment() *---------------------------------------------------------------------------- * Queue a segment for playback *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_QueueSegment (EAS_DATA_HANDLE easHandle, EAS_INT segmentNum, EAS_INT libNum, EAS_INT repeatCount, EAS_INT transpose, EAS_U32 muteFlags, EAS_U8 userID) { EAS_FILE_HANDLE fileHandle; EAS_RESULT result; S_JET_SEGMENT *p; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_QueueSegment segNum=%d, queue=%d\n", segmentNum, easHandle->jetHandle->queueSegment); */ } /* make sure it's a valid segment */ if (segmentNum >= easHandle->jetHandle->numSegments) return EAS_ERROR_PARAMETER_RANGE; /* make sure it's a valid DLS */ if (libNum >= easHandle->jetHandle->numLibraries) return EAS_ERROR_PARAMETER_RANGE; /* check to see if queue is full */ p = &easHandle->jetHandle->segQueue[easHandle->jetHandle->queueSegment]; if (p->streamHandle != NULL) return EAS_ERROR_QUEUE_IS_FULL; /* initialize data */ p->userID = userID; p->repeatCount = (EAS_I16) repeatCount; p->transpose = (EAS_I8) transpose; p->libNum = (EAS_I8) libNum; p->muteFlags = muteFlags; p->state = JET_STATE_CLOSED; /* open the file */ result = EAS_OpenJETStream(easHandle, easHandle->jetHandle->jetFileHandle, easHandle->jetHandle->segmentOffsets[segmentNum], &p->streamHandle); if (result != EAS_SUCCESS) return result; p->state = JET_STATE_OPEN; /* if less than SEG_QUEUE_DEPTH segments queued up, prepare file for playback */ if (++easHandle->jetHandle->numQueuedSegments < SEG_QUEUE_DEPTH) { result = JET_PrepareSegment(easHandle, easHandle->jetHandle->queueSegment); if (result != EAS_SUCCESS) return result; } /* create duplicate file handle */ result = EAS_HWDupHandle(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &fileHandle); if (result != EAS_SUCCESS) return result; easHandle->jetHandle->jetFileHandle = fileHandle; easHandle->jetHandle->queueSegment = (EAS_U8) JET_NextSegment(easHandle->jetHandle->queueSegment); return result; } /*---------------------------------------------------------------------------- * JET_Play() *---------------------------------------------------------------------------- * Starts playback of the file *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle) { EAS_RESULT result; EAS_INT index; EAS_INT count = 0; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Play\n"); */ } /* sanity check */ if (easHandle->jetHandle->flags & JET_FLAGS_PLAYING) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* resume all paused streams */ for (index = 0; index < SEG_QUEUE_DEPTH; index++) { if (((index == easHandle->jetHandle->playSegment) && (easHandle->jetHandle->segQueue[index].state == JET_STATE_READY)) || (easHandle->jetHandle->segQueue[index].state == JET_STATE_PAUSED)) { result = JET_StartPlayback(easHandle, index); if (result != EAS_SUCCESS) return result; count++; } } /* if no streams are playing, return error */ if (!count) return EAS_ERROR_QUEUE_IS_EMPTY; easHandle->jetHandle->flags |= JET_FLAGS_PLAYING; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_Pause() *---------------------------------------------------------------------------- * Pauses playback of the file *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle) { EAS_RESULT result; EAS_INT index; EAS_INT count = 0; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Pause\n"); */ } /* sanity check */ if ((easHandle->jetHandle->flags & JET_FLAGS_PLAYING) == 0) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* pause all playing streams */ for (index = 0; index < SEG_QUEUE_DEPTH; index++) { if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) { result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle); if (result != EAS_SUCCESS) return result; easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].state = JET_STATE_PAUSED; count++; } } /* if no streams are paused, return error */ if (!count) return EAS_ERROR_QUEUE_IS_EMPTY; easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_SetMuteFlags() *---------------------------------------------------------------------------- * Change the state of the mute flags *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync) { S_JET_SEGMENT *pSeg; /* get pointer to current segment */ pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; /* unsynchronized mute, set flags and return */ if (!sync) { if (pSeg->streamHandle == NULL) return EAS_ERROR_QUEUE_IS_EMPTY; pSeg->muteFlags = muteFlags; return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) muteFlags); } /* check for valid stream state */ if (pSeg->state == JET_STATE_CLOSED) return EAS_ERROR_QUEUE_IS_EMPTY; /* save mute flags */ pSeg->muteFlags = muteFlags; /* if repeating segment, set mute update flag */ if (sync) pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_SetMuteFlag() *---------------------------------------------------------------------------- * Change the state of a single mute flag *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync) { S_JET_SEGMENT *pSeg; EAS_U32 trackMuteFlag; /* setup flag */ if ((trackNum < 0) || (trackNum > 31)) return EAS_ERROR_PARAMETER_RANGE; trackMuteFlag = (1 << trackNum); /* get pointer to current segment */ pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; /* unsynchronized mute, set flags and return */ if (!sync) { if (pSeg->streamHandle == NULL) return EAS_ERROR_QUEUE_IS_EMPTY; if (muteFlag) pSeg->muteFlags |= trackMuteFlag; else pSeg->muteFlags &= ~trackMuteFlag; return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); } /* check for valid stream state */ if (pSeg->state == JET_STATE_CLOSED) return EAS_ERROR_QUEUE_IS_EMPTY; /* save mute flags and set mute update flag */ if (muteFlag) pSeg->muteFlags |= trackMuteFlag; else pSeg->muteFlags &= ~trackMuteFlag; pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_TriggerClip() *---------------------------------------------------------------------------- * Unmute a track and then mute it when it is complete. If a clip * is already playing, change mute event to a trigger event. The * JET_Event function will not mute the clip, but will allow it * to continue playing through the next clip. * * NOTE: We use bit 7 to indicate an entry in the queue. For a * small queue, it is cheaper in both memory and CPU cycles to * scan the entire queue for non-zero events than keep enqueue * and dequeue indices. *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID) { EAS_INT i; EAS_INT index = -1; /* check for valid clipID */ if ((clipID < 0) || (clipID > 63)) return EAS_ERROR_PARAMETER_RANGE; /* set active flag */ clipID |= JET_CLIP_ACTIVE_FLAG; /* Reverse the search so that we get the first empty element */ for (i = JET_MUTE_QUEUE_SIZE-1; i >= 0 ; i--) { if (easHandle->jetHandle->muteQueue[i] == clipID) { index = i; break; } if (easHandle->jetHandle->muteQueue[i] == 0) index = i; } if (index < 0) return EAS_ERROR_QUEUE_IS_FULL; easHandle->jetHandle->muteQueue[index] = (EAS_U8) clipID | JET_CLIP_TRIGGER_FLAG; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * JET_Process() *---------------------------------------------------------------------------- * Called during EAS_Render to process stream states *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle) { S_JET_SEGMENT *pSeg; EAS_STATE state; EAS_INT index; EAS_INT playIndex; EAS_RESULT result = EAS_SUCCESS; EAS_BOOL endOfLoop = EAS_FALSE; EAS_BOOL startNextSegment = EAS_FALSE; EAS_BOOL prepareNextSegment = EAS_FALSE; EAS_U32 jetEvent; /* process event queue */ while (JET_ReadQueue(easHandle->jetHandle->jetEventQueue, &easHandle->jetHandle->jetEventQueueRead, easHandle->jetHandle->jetEventQueueWrite, JET_EVENT_QUEUE_SIZE, &jetEvent)) { S_JET_EVENT event; #ifdef DEBUG_JET JET_DumpEvent("JET_Process", jetEvent); #endif JET_ParseEvent(jetEvent, &event); /* check for end of loop */ if ((event.controller == JET_EVENT_MARKER) && (event.value == JET_MARKER_LOOP_END) && (easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle != NULL)) endOfLoop = EAS_TRUE; } /* check state of all streams */ index = playIndex = easHandle->jetHandle->playSegment; for (;;) { pSeg = &easHandle->jetHandle->segQueue[index]; if (pSeg->state != JET_STATE_CLOSED) { /* get playback state */ result = EAS_State(easHandle, pSeg->streamHandle, &state); if (result != EAS_SUCCESS) return result; /* process state */ switch (pSeg->state) { /* take action if this segment is stopping */ case JET_STATE_PLAYING: if (endOfLoop || (state == EAS_STATE_STOPPING) || (state == EAS_STATE_STOPPED)) { /* handle repeats */ if (pSeg->repeatCount != 0) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render repeating segment %d\n", index); */ } result = EAS_Locate(easHandle, pSeg->streamHandle, 0, EAS_FALSE); if (result != EAS_SUCCESS) return result; if (pSeg->repeatCount > 0) pSeg->repeatCount--; /* update mute flags if necessary */ if (pSeg->flags & JET_SEG_FLAG_MUTE_UPDATE) { result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); if (result != EAS_SUCCESS) return result; pSeg->flags &= ~JET_SEG_FLAG_MUTE_UPDATE; } } /* no repeat, start next segment */ else { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render stopping queue %d\n", index); */ } startNextSegment = EAS_TRUE; pSeg->state = JET_STATE_STOPPING; easHandle->jetHandle->playSegment = (EAS_U8) JET_NextSegment(index); } } break; /* if playback has stopped, close the segment */ case JET_STATE_STOPPING: if (state == EAS_STATE_STOPPED) { result = JET_CloseSegment(easHandle, index); if (result != EAS_SUCCESS) return result; } break; case JET_STATE_READY: if (startNextSegment) { result = JET_StartPlayback(easHandle, index); if (result != EAS_SUCCESS) return result; startNextSegment = EAS_FALSE; prepareNextSegment = EAS_TRUE; } break; case JET_STATE_OPEN: if (prepareNextSegment) { result = JET_PrepareSegment(easHandle, index); if (result != EAS_SUCCESS) return result; prepareNextSegment = EAS_FALSE; } break; case JET_STATE_PAUSED: break; default: { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "JET_Render: Unexpected segment state %d\n", pSeg->state); */ } break; } } /* increment index */ index = JET_NextSegment(index); if (index == playIndex) break; } /* if out of segments, clear playing flag */ if (easHandle->jetHandle->numQueuedSegments == 0) easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; return result; } /*---------------------------------------------------------------------------- * JET_Event() *---------------------------------------------------------------------------- * Called from MIDI parser when data of interest is received *---------------------------------------------------------------------------- */ void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) { EAS_U32 event; if (easHandle->jetHandle == NULL) return; /* handle triggers */ if (controller == JET_EVENT_TRIGGER_CLIP) { S_JET_SEGMENT *pSeg; EAS_INT i; EAS_U32 muteFlag; for (i = 0; i < JET_MUTE_QUEUE_SIZE; i++) { /* search for event in queue */ if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_ID_MASK) == (value & JET_CLIP_ID_MASK)) { /* get segment pointer and mute flag */ pSeg = &easHandle->jetHandle->segQueue[segTrack >> JET_EVENT_SEG_SHIFT]; muteFlag = 1 << ((segTrack & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); /* un-mute the track */ if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_TRIGGER_FLAG) && ((value & 0x40) > 0)) { pSeg->muteFlags &= ~muteFlag; easHandle->jetHandle->muteQueue[i] &= ~JET_CLIP_TRIGGER_FLAG; } /* mute the track */ else { EAS_U32 beforeMute ; beforeMute = pSeg->muteFlags ; pSeg->muteFlags |= muteFlag; if (beforeMute != pSeg->muteFlags) easHandle->jetHandle->muteQueue[i] = 0; } EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); return; } } return; } /* generic event stuff */ event = (channel << JET_EVENT_CHAN_SHIFT) | (controller << JET_EVENT_CTRL_SHIFT) | value; /* write to app queue, translate queue index to segment number */ if ((controller >= easHandle->jetHandle->config.appEventRangeLow) && (controller <= easHandle->jetHandle->config.appEventRangeHigh)) { event |= easHandle->jetHandle->segQueue[(segTrack & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT].userID << JET_EVENT_SEG_SHIFT; #ifdef DEBUG_JET JET_DumpEvent("JET_Event[app]", event); #endif JET_WriteQueue(easHandle->jetHandle->appEventQueue, &easHandle->jetHandle->appEventQueueWrite, easHandle->jetHandle->appEventQueueRead, APP_EVENT_QUEUE_SIZE, event); } /* write to JET queue */ else if ((controller >= JET_EVENT_LOW) && (controller <= JET_EVENT_HIGH)) { event |= segTrack; #ifdef DEBUG_JET JET_DumpEvent("JET_Event[jet]", event); #endif JET_WriteQueue(easHandle->jetHandle->jetEventQueue, &easHandle->jetHandle->jetEventQueueWrite, easHandle->jetHandle->jetEventQueueRead, JET_EVENT_QUEUE_SIZE, event); } } /*---------------------------------------------------------------------------- * JET_Clear_Queue() *---------------------------------------------------------------------------- * Clears the queue and stops play without a complete shutdown *---------------------------------------------------------------------------- */ EAS_RESULT JET_Clear_Queue(EAS_DATA_HANDLE easHandle) { EAS_INT index; EAS_RESULT result = EAS_SUCCESS; { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Clear_Queue\n"); */ } /* pause all playing streams */ for (index = 0; index < SEG_QUEUE_DEPTH; index++) { if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) { result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[index].streamHandle); if (result != EAS_SUCCESS) return result; easHandle->jetHandle->segQueue[index].state = JET_STATE_PAUSED; } } /* close all streams */ for (index = 0; index < SEG_QUEUE_DEPTH; index++) { if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) { result = JET_CloseSegment(easHandle, index); if (result != EAS_SUCCESS) return result; } } /* clear all clips */ for (index = 0; index < JET_MUTE_QUEUE_SIZE ; index++) { easHandle->jetHandle->muteQueue[index] = 0; } easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; easHandle->jetHandle->playSegment = easHandle->jetHandle->queueSegment = 0; return result; }