/** * 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.sox.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.opencastproject.job.api.Job; import org.opencastproject.job.api.JobBarrier; import org.opencastproject.mediapackage.AudioStream; import org.opencastproject.mediapackage.MediaPackageElementParser; import org.opencastproject.mediapackage.Track; import org.opencastproject.mediapackage.track.TrackImpl; import org.opencastproject.security.api.DefaultOrganization; import org.opencastproject.security.api.JaxbOrganization; import org.opencastproject.security.api.JaxbRole; import org.opencastproject.security.api.JaxbUser; import org.opencastproject.security.api.OrganizationDirectoryService; import org.opencastproject.security.api.SecurityService; import org.opencastproject.security.api.User; import org.opencastproject.security.api.UserDirectoryService; import org.opencastproject.serviceregistry.api.IncidentService; import org.opencastproject.serviceregistry.api.ServiceRegistry; import org.opencastproject.serviceregistry.api.ServiceRegistryInMemoryImpl; import org.opencastproject.sox.api.SoxException; import org.opencastproject.util.IoSupport; import org.opencastproject.util.StreamHelper; import org.opencastproject.workspace.api.Workspace; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.List; /** * Tests the {@link SoxServiceImpl}. */ public class SoxServiceTest { /** Logging facility */ private static final Logger logger = LoggerFactory.getLogger(SoxServiceTest.class); private static final String SOX_BINARY = "sox"; /** The source file to test with */ private File source = null; /** The SoX service to test */ private SoxServiceImpl soxService = null; /** The service registry for job dispatching */ private ServiceRegistry serviceRegistry = null; /** True to run the tests */ private static boolean soxInstalled = true; @BeforeClass public static void testForSox() throws SoxException { StreamHelper stdout = null; StreamHelper stderr = null; Process p = null; try { ArrayList<String> command = new ArrayList<String>(); command.add(SOX_BINARY); command.add("--version"); p = new ProcessBuilder(command).start(); stdout = new StreamHelper(p.getInputStream()); stderr = new StreamHelper(p.getErrorStream()); if (p.waitFor() != 0) throw new IllegalStateException(); } catch (Throwable t) { logger.warn("Skipping sox audio processing service tests due to unsatisifed or erroneus sox installation"); soxInstalled = false; } finally { IoSupport.closeQuietly(stdout); IoSupport.closeQuietly(stderr); IoSupport.closeQuietly(p); } } @Before public void setUp() throws Exception { if (!soxInstalled) return; // Copy an existing media file to a temp file File f = new File("src/test/resources/audio-test.flac"); source = File.createTempFile(FilenameUtils.getBaseName(f.getName()), ".flac"); FileUtils.copyFile(f, source); f = null; JaxbOrganization org = new DefaultOrganization(); User user = new JaxbUser("admin", "test", org, new JaxbRole(DefaultOrganization.DEFAULT_ORGANIZATION_ADMIN, org)); OrganizationDirectoryService orgDirectory = EasyMock.createNiceMock(OrganizationDirectoryService.class); EasyMock.expect(orgDirectory.getOrganization((String) EasyMock.anyObject())).andReturn(org).anyTimes(); UserDirectoryService userDirectory = EasyMock.createNiceMock(UserDirectoryService.class); EasyMock.expect(userDirectory.loadUser("admin")).andReturn(user).anyTimes(); SecurityService securityService = EasyMock.createNiceMock(SecurityService.class); EasyMock.expect(securityService.getOrganization()).andReturn(org).anyTimes(); EasyMock.expect(securityService.getUser()).andReturn(user).anyTimes(); Workspace workspace = EasyMock.createNiceMock(Workspace.class); EasyMock.expect(workspace.get((URI) EasyMock.anyObject())).andReturn(source).anyTimes(); BundleContext bc = EasyMock.createNiceMock(BundleContext.class); EasyMock.expect(bc.getProperty(SoxServiceImpl.CONFIG_SOX_PATH)).andReturn(SOX_BINARY).anyTimes(); ComponentContext cc = EasyMock.createNiceMock(ComponentContext.class); EasyMock.expect(cc.getBundleContext()).andReturn(bc).anyTimes(); IncidentService incidentService = EasyMock.createNiceMock(IncidentService.class); // Finish setting up the mocks EasyMock.replay(bc, cc, orgDirectory, userDirectory, securityService, workspace, incidentService); // Create and populate the composer service soxService = new SoxServiceImpl(); serviceRegistry = new ServiceRegistryInMemoryImpl(soxService, securityService, userDirectory, orgDirectory, incidentService); soxService.setOrganizationDirectoryService(orgDirectory); soxService.setSecurityService(securityService); soxService.setServiceRegistry(serviceRegistry); soxService.setUserDirectoryService(userDirectory); soxService.setWorkspace(workspace); soxService.activate(cc); } @After public void tearDown() throws Exception { FileUtils.deleteQuietly(source); } @Test public void testAnalyzeAudio() throws Exception { if (!soxInstalled) return; assertTrue(source.isFile()); String sourceTrackXml = "<track xmlns=\"http://mediapackage.opencastproject.org\" id=\"track-1\" type=\"presentation/source\"><mimetype>audio/flac</mimetype>" + "<url>http://localhost:8080/workflow/samples/camera.mpg</url>" + "<checksum type=\"md5\">43b7d843b02c4a429b2f547a4f230d31</checksum><duration>14546</duration>" + "<audio><device type=\"UFG03\" version=\"30112007\" vendor=\"Unigraf\" />" + "<encoder type=\"H.264\" version=\"7.4\" vendor=\"Apple Inc\" /><channels>2</channels>" + "<bitdepth>16</bitdepth><samplingrate>44100</samplingrate></audio></track>"; Track sourceTrack = (Track) MediaPackageElementParser.getFromXml(sourceTrackXml); List<Job> jobs = new ArrayList<Job>(); for (int i = 0; i < 10; i++) { jobs.add(soxService.analyze(sourceTrack)); } boolean success = new JobBarrier(null, serviceRegistry, jobs.toArray(new Job[jobs.size()])).waitForJobs().isSuccess(); assertTrue(success); for (Job j : jobs) { // Always check the service registry for the latest version of the job Job job = serviceRegistry.getJob(j.getId()); TrackImpl track = (TrackImpl) MediaPackageElementParser.getFromXml(job.getPayload()); AudioStream audioStream = track.getAudio().get(0); assertEquals(-8.55f, audioStream.getPkLevDb().floatValue(), 0.0002); assertEquals(-27.78f, audioStream.getRmsLevDb().floatValue(), 0.0002); assertEquals(-20.12f, audioStream.getRmsPkDb().floatValue(), 0.0002); assertEquals(Job.Status.FINISHED, job.getStatus()); } } @Test public void testNormalizeIncreaseAudio() throws Exception { if (!soxInstalled) return; assertTrue(source.isFile()); String sourceTrackXml = "<track xmlns=\"http://mediapackage.opencastproject.org\" id=\"track-1\" type=\"presentation/source\"><mimetype>audio/flac</mimetype>" + "<url>http://localhost:8080/workflow/samples/camera.mpg</url>" + "<checksum type=\"md5\">43b7d843b02c4a429b2f547a4f230d31</checksum><duration>14546</duration>" + "<audio><device type=\"UFG03\" version=\"30112007\" vendor=\"Unigraf\" />" + "<encoder type=\"H.264\" version=\"7.4\" vendor=\"Apple Inc\" /><channels>2</channels>" + "<bitdepth>16</bitdepth><rmsleveldb>-27.78</rmsleveldb><samplingrate>44100</samplingrate></audio></track>"; Track sourceTrack = (Track) MediaPackageElementParser.getFromXml(sourceTrackXml); List<Job> jobs = new ArrayList<Job>(); for (int i = 0; i < 10; i++) { jobs.add(soxService.normalize(sourceTrack, -25f)); } boolean success = new JobBarrier(null, serviceRegistry, jobs.toArray(new Job[jobs.size()])).waitForJobs().isSuccess(); assertTrue(success); for (Job j : jobs) { // Always check the service registry for the latest version of the job Job job = serviceRegistry.getJob(j.getId()); TrackImpl track = (TrackImpl) MediaPackageElementParser.getFromXml(job.getPayload()); AudioStream audioStream = track.getAudio().get(0); assertEquals(-25f, audioStream.getRmsLevDb().floatValue(), 0.9); assertEquals(Job.Status.FINISHED, job.getStatus()); } } @Test public void testNormalizeDecreaseAudio() throws Exception { if (!soxInstalled) return; assertTrue(source.isFile()); String sourceTrackXml = "<track xmlns=\"http://mediapackage.opencastproject.org\" id=\"track-1\" type=\"presentation/source\"><mimetype>audio/flac</mimetype>" + "<url>http://localhost:8080/workflow/samples/camera.mpg</url>" + "<checksum type=\"md5\">43b7d843b02c4a429b2f547a4f230d31</checksum><duration>14546</duration>" + "<audio><device type=\"UFG03\" version=\"30112007\" vendor=\"Unigraf\" />" + "<encoder type=\"H.264\" version=\"7.4\" vendor=\"Apple Inc\" /><channels>2</channels>" + "<bitdepth>16</bitdepth><rmsleveldb>-27.78</rmsleveldb><samplingrate>44100</samplingrate></audio></track>"; Track sourceTrack = (Track) MediaPackageElementParser.getFromXml(sourceTrackXml); List<Job> jobs = new ArrayList<Job>(); for (int i = 0; i < 10; i++) { jobs.add(soxService.normalize(sourceTrack, -30f)); } boolean success = new JobBarrier(null, serviceRegistry, jobs.toArray(new Job[jobs.size()])).waitForJobs().isSuccess(); assertTrue(success); for (Job j : jobs) { // Always check the service registry for the latest version of the job Job job = serviceRegistry.getJob(j.getId()); TrackImpl track = (TrackImpl) MediaPackageElementParser.getFromXml(job.getPayload()); AudioStream audioStream = track.getAudio().get(0); assertEquals(-30f, audioStream.getRmsLevDb().floatValue(), 0.1); assertEquals(Job.Status.FINISHED, job.getStatus()); } } }