/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.
*
*/
package org.opencastproject.workflow.handler.speechrecognition;
import static org.opencastproject.util.data.Monadics.mlist;
import org.opencastproject.job.api.Job;
import org.opencastproject.job.api.JobBarrier;
import org.opencastproject.job.api.JobContext;
import org.opencastproject.mediapackage.Catalog;
import org.opencastproject.mediapackage.MediaPackageElementFlavor;
import org.opencastproject.mediapackage.MediaPackageElementParser;
import org.opencastproject.mediapackage.MediaPackageException;
import org.opencastproject.mediapackage.Track;
import org.opencastproject.serviceregistry.api.ServiceRegistryException;
import org.opencastproject.speechrecognition.api.SpeechRecognitionService;
import org.opencastproject.util.NotFoundException;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Monadics.ListMonadic;
import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
import org.opencastproject.workflow.api.WorkflowInstance;
import org.opencastproject.workflow.api.WorkflowOperationException;
import org.opencastproject.workflow.api.WorkflowOperationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* {@link org.opencastproject.workflow.api.WorkflowOperationHandler} to let a service like <a
* href="http://www.koemei.com/">Koemei Speech Recognition</a> transcribe audio tracks in the media package.
*/
public class SpeechRecognitionWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
private static final Logger logger = LoggerFactory.getLogger(SpeechRecognitionWorkflowOperationHandler.class);
public static final MediaPackageElementFlavor AUDIO_FLAVOR = new MediaPackageElementFlavor("speech", "work");
private SpeechRecognitionService speechRecognitionService;
/**
* Injected by OSGi environment.
*/
public void setSpeechRecognitionService(SpeechRecognitionService speechRecognitionService) {
this.speechRecognitionService = speechRecognitionService;
}
@Override
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
throws WorkflowOperationException {
// check media package for suitable audio track and submit it to the SpeechRecognitionService
ListMonadic<Track> mTracks = mlist(workflowInstance.getMediaPackage().getTracks()).filter(filterByFlavor);
List<Track> tracks = mTracks.value();
if (tracks.isEmpty()) {
// No audio track available - log a message
logger.info("media package contains no processable audio track");
return createResult(WorkflowOperationResult.Action.CONTINUE);
}
// Send all tracks to the transcription service
List<Job> transcriptionJobs = new ArrayList<Job>();
for (Track track : tracks) {
// Found a track - send it to speech recognition service
logger.info("Sending track {} to SpeechRecognitionService", track);
Job job = speechRecognitionService.transcribe(track, workflowInstance.getMediaPackage().getLanguage());
transcriptionJobs.add(job);
}
// Wait for all jobs to be finished (or failed)
logger.info("SpeechRecognitionService is waiting for {} transcription job(s) to return", transcriptionJobs.size());
final JobBarrier.Result result = waitForStatus(transcriptionJobs.toArray(new Job[transcriptionJobs.size()]));
for (Job job : transcriptionJobs) {
if (result.isSuccess()) {
Job newJob;
try {
newJob = serviceRegistry.getJob(job.getId());
} catch (NotFoundException e) {
throw new WorkflowOperationException(e);
} catch (ServiceRegistryException e) {
throw new WorkflowOperationException(e);
}
Catalog speechCatalog;
try {
speechCatalog = (Catalog) MediaPackageElementParser.getFromXml(newJob.getPayload());
} catch (MediaPackageException e) {
throw new WorkflowOperationException(e);
}
workflowInstance.getMediaPackage().add(speechCatalog);
return createResult(WorkflowOperationResult.Action.CONTINUE);
} else
throw new RuntimeException("Job terminated unsuccessfully");
}
return createResult(WorkflowOperationResult.Action.CONTINUE);
}
/**
* Filter tracks of flavor {@link #AUDIO_FLAVOR}.
*/
private static final Function<Track, Boolean> filterByFlavor = new Function<Track, Boolean>() {
@Override
public Boolean apply(Track track) {
return AUDIO_FLAVOR.equals(track.getFlavor());
}
};
}