All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.daisy.pipeline.audio.lame.impl.LameEncoderService Maven / Gradle / Ivy

The newest version!
package org.daisy.pipeline.audio.lame.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

import javax.sound.sampled.AudioFileFormat;

import org.daisy.common.file.URLs;
import org.daisy.common.properties.Properties;
import org.daisy.common.properties.Properties.Property;
import org.daisy.common.shell.BinaryFinder;
import org.daisy.pipeline.audio.AudioEncoder;
import org.daisy.pipeline.audio.AudioEncoderService;
import static org.daisy.pipeline.audio.AudioFileTypes.MP3;

import org.osgi.service.component.annotations.Component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
	name = "audio-encoder-lame",
	immediate = true,
	service = { AudioEncoderService.class }
)
public class LameEncoderService implements AudioEncoderService {

	private static final Logger logger = LoggerFactory.getLogger(LameEncoderService.class);
	private static final Property MP3_BITRATE = Properties.getProperty("org.daisy.pipeline.tts.mp3.bitrate",
	                                                                   true,
	                                                                   "Bit rate of MP3 files",
	                                                                   false,
	                                                                   null);
	private static final Property CLI_OPTIONS = Properties.getProperty("org.daisy.pipeline.tts.lame.cli.options",
	                                                                   false,
	                                                                   "Additional command line options passed to lame (deprecated)",
	                                                                   false,
	                                                                   null);

	@Override
	public boolean supportsFileType(AudioFileFormat.Type fileType) {
		 return MP3.equals(fileType);
	}

	@Override
	public Optional newEncoder(Map params) {
		LameEncoder.LameEncodingOptions lameOpts = parseEncodingOptions(params);
		try {
			test(lameOpts);
			return Optional.of(new LameEncoder(lameOpts));
		} catch (Exception e) {
			logger.error("Lame encoder can not be instantiated", e);
			return Optional.empty();
		}
	}

	private static LameEncoder.LameEncodingOptions parseEncodingOptions(Map params) {
		LameEncoder.LameEncodingOptions opts = new LameEncoder.LameEncodingOptions();
		{
			String bitrate = MP3_BITRATE.getValue(params);
			if (bitrate != null) {
				try {
					opts.bitrate = Integer.valueOf(bitrate);
				} catch (NumberFormatException e) {
					logger.warn(MP3_BITRATE.getName() + ": " + bitrate + "is  not a valid number");
				}
			}
		}
		{
			String prop = "org.daisy.pipeline.tts.lame.cli.options";
			String extraCliArguments = params.get(prop);
			if (extraCliArguments != null) {
				logger.warn("'" + prop + "' setting is deprecated. It may become unavailable in future version of DAISY Pipeline.");
				opts.extraCliArguments = extraCliArguments.split(" ");
			}
		}
		opts.binpath = findLame(params);
		return opts;
	}

	private static String findLame(Map params) {
		String lamePath = null;
		String prop = "org.daisy.pipeline.tts.lame.path";
		lamePath = params.get(prop);
		if (lamePath == null) {
			try {
				Optional lame = extractLame();
				if (lame.isPresent())
					lamePath = lame.get().getAbsolutePath();
			} catch (Throwable e) {
				logger.warn("Unexpected error happened while unpacking Lame executable", e);
			}
		}
		if (lamePath == null) {
			Optional lame = BinaryFinder.find("lame");
			if (lame.isPresent())
				lamePath = lame.get();
		}
		return lamePath;
	}

	private static void test(LameEncoder.LameEncodingOptions lameOpts) throws Exception {
		if (lameOpts.binpath == null) {
			throw new RuntimeException("Lame executable not found");
		}
		if (!new File(lameOpts.binpath).exists()) {
			throw new RuntimeException("Lame executable not found: " + lameOpts.binpath);
		}
		logger.debug("Using Lame executable at path '" + lameOpts.binpath + "'");
		// check that the encoder can run
		String[] cmd = new String[] {
			lameOpts.binpath, "--help"
		};
		Process p = null;
		try {
			p = Runtime.getRuntime().exec(cmd);
			// read the output to prevent the process from sleeping
			BufferedReader stdOut = new BufferedReader(new InputStreamReader(p.getInputStream()));
			while ((stdOut.readLine()) != null);
			p.waitFor();
		} catch (Exception e) {
			if (p != null)
				p.destroy();
			throw e;
		}
	}

	/**
	 * Unpack lame executable
	 */
	private static Optional extractLame() throws IOException, InterruptedException {
		String os = System.getProperty("os.name");
		String lamePath; {
			if (os.toLowerCase().startsWith("windows"))
				lamePath = "windows_x86";
			else if (os.toLowerCase().startsWith("mac os x"))
				lamePath = "macosx";
			else
				return Optional.empty();
		}
		String lameFileName = "lame" + (os.toLowerCase().startsWith("windows") ? ".exe" : "");
		URL url = URLs.getResourceFromJAR(lamePath + "/" + lameFileName, LameEncoderService.class);
		File lame; {
			try {
				lame = new File(URLs.asURI(url));
			} catch (IllegalArgumentException iae) {
				File tmpDirectory = Files.createTempDirectory("pipeline-").toFile();
				tmpDirectory.deleteOnExit();
				// extract all files from directory
				Iterator resources = URLs.listResourcesFromJAR(lamePath, LameEncoderService.class);
				while (resources.hasNext()) {
					String res = resources.next();
					File file = new File(tmpDirectory, new File(res).getName());
					file.deleteOnExit();
					copy(URLs.getResourceFromJAR(res, LameEncoderService.class), file);
				}
				lame = new File(tmpDirectory, lameFileName);
			}
		}
		if (!os.toLowerCase().startsWith("windows"))
			Runtime.getRuntime().exec(new String[] { "chmod", "775", lame.getAbsolutePath() }).waitFor();
		return Optional.of(lame);
	}

	public static void copy(URL url, File file) throws IOException {
		file.getParentFile().mkdirs();
		file.createNewFile();
		FileOutputStream writer = new FileOutputStream(file);
		url.openConnection();
		InputStream reader = url.openStream();
		byte[] buffer = new byte[153600];
		int bytesRead = 0;
		while ((bytesRead = reader.read(buffer)) > 0) {
			writer.write(buffer, 0, bytesRead);
			buffer = new byte[153600];
		}
		writer.close();
		reader.close();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy