package org.jactr.modules.pm.aural.buffer.processor; /* * default logging */ import java.util.concurrent.Future; import javolution.util.FastList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.chunk.IChunk; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.event.IParameterEvent; import org.jactr.core.logging.Logger; import org.jactr.core.model.IModel; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.production.request.ChunkTypeRequest; import org.jactr.core.production.request.IRequest; import org.jactr.core.queue.ITimedEvent; import org.jactr.core.slot.ISlot; import org.jactr.modules.pm.aural.IAuralModule; import org.jactr.modules.pm.aural.buffer.IAuralLocationBuffer; import org.jactr.modules.pm.aural.event.IAuralModuleListener; import org.jactr.modules.pm.buffer.IPerceptualBuffer; import org.jactr.modules.pm.common.buffer.AbstractRequestDelegate; import org.jactr.modules.pm.common.event.IPerceptualMemoryModuleEvent; import org.jactr.modules.pm.common.memory.IPerceptualMemory; import org.jactr.modules.pm.common.memory.PerceptualSearchResult; /** * handles aural-location requests by checking and managing the buffer states * and routing to the aural module. This also uses a blocking timed event from * the super class to make sure that the model does not run past the firing time * until the visual module has completed its aural search * * @author harrison */ public class AuralSearchRequestDelegate extends AbstractRequestDelegate { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(AuralSearchRequestDelegate.class); private IAuralModule _module; private boolean _isStuffRequest; @SuppressWarnings("serial") public AuralSearchRequestDelegate(IAuralModule module) { super(module.getAudioEventChunkType()); setAsynchronous(true); setUseBlockingTimedEvents(true); setDelayStart(false); _module = module; _module.addListener(new IAuralModuleListener() { @SuppressWarnings("unchecked") public void parameterChanged(IParameterEvent pe) { } public void moduleReset(IPerceptualMemoryModuleEvent event) { release(); } public void perceptAttended(IPerceptualMemoryModuleEvent event) { } public void perceptIndexFound(IPerceptualMemoryModuleEvent event) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Found " + event.getChunk() + " releasing"); // release the block, if any release(); } }, ExecutorServices.INLINE_EXECUTOR); } final public boolean isBufferStuffPending() { ITimedEvent previousSearch = getCurrentTimedEvent(); return previousSearch != null && !previousSearch.hasFired() && !previousSearch.hasAborted() && _isStuffRequest; } final public void cancelBufferStuff() { ITimedEvent previousSearch = getCurrentTimedEvent(); if (previousSearch != null && !previousSearch.hasFired() && !previousSearch.hasAborted() && _isStuffRequest) previousSearch.abort(); } @Override final protected boolean isValid(IRequest request, IActivationBuffer buffer) throws IllegalArgumentException { /* * check to see if we are busy or not.. */ IModel model = _module.getModel(); if (isBusy(buffer) /* || isBusy(_module.getVisualActivationBuffer()) */) { String msg = "Aural system is currently busy, cannot perform aural search"; if (LOGGER.isDebugEnabled()) LOGGER.debug(msg); if (Logger.hasLoggers(model)) Logger.log(model, Logger.Stream.AURAL, msg); return false; } return true; } @Override final protected Object startRequest(IRequest request, IActivationBuffer buffer, double requestTime) { ChunkTypeRequest ctr = (ChunkTypeRequest) request; IAuralLocationBuffer locBuffer = _module.getAuralLocationBuffer(); IChunk busy = _module.getModel().getDeclarativeModule().getBusyChunk(); /* * cancel previous stuff request */ if (isBufferStuffPending()) cancelBufferStuff(); /* * figure out if this is a stuff request */ FastList<ISlot> slots = FastList.newInstance(); ctr.getSlots(slots); boolean isStuffRequest = false; for (ISlot slot : slots) if (IPerceptualBuffer.IS_BUFFER_STUFF_REQUEST.equals(slot.getName()) && Boolean.TRUE.equals(slot.getValue())) { isStuffRequest = true; ctr.removeSlot(slot); break; } /* * clear it. */ locBuffer.removeSourceChunk(locBuffer.getSourceChunk()); /* * set the buffer states. */ locBuffer.setStateChunk(busy); locBuffer.setModalityChunk(busy); locBuffer.setExecutionChunk(busy); locBuffer.setProcessorChunk(busy); locBuffer.setPreparationChunk(busy); _isStuffRequest = isStuffRequest; FastList.recycle(slots); return _module.search(ctr, requestTime, isStuffRequest); } @Override final protected void abortRequest(IRequest request, IActivationBuffer buffer, Object startValue) { IAuralLocationBuffer locBuffer = _module.getAuralLocationBuffer(); IChunk free = _module.getModel().getDeclarativeModule().getFreeChunk(); /* * set the buffer states. */ locBuffer.setStateChunk(free); locBuffer.setModalityChunk(free); locBuffer.setExecutionChunk(free); locBuffer.setProcessorChunk(free); locBuffer.setPreparationChunk(free); super.abortRequest(request, buffer, startValue); } @SuppressWarnings("unchecked") @Override final protected void finishRequest(IRequest request, IActivationBuffer buffer, Object startValue) { IModel model = _module.getModel(); IAuralLocationBuffer locBuffer = _module.getAuralLocationBuffer(); IDeclarativeModule decM = model.getDeclarativeModule(); IChunk error = decM.getErrorChunk(); IChunk free = decM.getFreeChunk(); IChunk auralLocation = error; PerceptualSearchResult searchResult = null; try { searchResult = ((Future<PerceptualSearchResult>) startValue).get(); } catch (InterruptedException ie) { return; } catch (Exception e) { LOGGER.error("Failed to get future value from search " + request, e); } if (searchResult.getLocation() != null) auralLocation = searchResult.getLocation(); if (error.equals(auralLocation)) { if (_isStuffRequest) { locBuffer.setStateChunk(free); locBuffer.setModalityChunk(free); locBuffer.setErrorChunk(null); } else { if (LOGGER.isDebugEnabled() || Logger.hasLoggers(model)) { String msg = String.format( "No valid audio-event could be found matching request %s", request); LOGGER.debug(msg); Logger.log(model, Logger.Stream.AURAL, msg); } locBuffer.setStateChunk(error); locBuffer.setModalityChunk(error); locBuffer.setErrorChunk(searchResult.getErrorCode()); } } else { if (LOGGER.isDebugEnabled() || Logger.hasLoggers(model)) { String msg = String.format("Found %1$s matching %2$s because of %3$s.", auralLocation, request, auralLocation .getMetaData(IPerceptualMemory.SEARCH_RESULT_IDENTIFIER_KEY)); LOGGER.debug(msg); Logger.log(model, Logger.Stream.AURAL, msg); } locBuffer.setStateChunk(free); locBuffer.setModalityChunk(free); locBuffer.setErrorChunk(null); locBuffer.addSourceChunk(auralLocation); /* * and handle the stuff flag */ if (auralLocation != null) if (_isStuffRequest) locBuffer.setBufferChunk(decM.getUnrequestedChunk()); else locBuffer.setBufferChunk(decM.getRequestedChunk()); } locBuffer.setExecutionChunk(free); locBuffer.setProcessorChunk(free); locBuffer.setPreparationChunk(free); } }