package com.geeshenk.sipgateio.service;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.inject.Inject;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.geeshenk.commons.ApplicationException;
import com.geeshenk.commons.DumpUtil;
import com.geeshenk.sipgateio.configuration.ServingResourcesFromFileSystemAdapter;
import com.sun.speech.freetts.Voice;
import com.sun.speech.freetts.VoiceManager;
import com.sun.speech.freetts.audio.AudioPlayer;
import com.sun.speech.freetts.audio.SingleFileAudioPlayer;
@Component
public class SipgateIoService {
private final static Logger logger = LoggerFactory.getLogger(SipgateIoService.class);
@Value("${name:World}")
private String name;
private ServingResourcesFromFileSystemAdapter servingResourcesFromFileSystemAdapter;
@Inject
public SipgateIoService(ServingResourcesFromFileSystemAdapter servingResourcesFromFileSystemAdapter) {
this.servingResourcesFromFileSystemAdapter = servingResourcesFromFileSystemAdapter;
}
public String getHelloMessage() {
return "Hello " + this.name;
}
public String getWaveFileLocationForSpokenString(String toBeSpoken) throws ApplicationException {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
logger.error("Could not instantiate SHA-256 algorithm", e);
throw new ApplicationException(e);
}
try {
md.update(toBeSpoken.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
logger.error("UTF-8 does not exist (1)", e);
throw new ApplicationException(e);
}
byte[] toBeSpokenHashByteArray = md.digest();
String toBeSpokenHash;
toBeSpokenHash = DumpUtil.toHex(toBeSpokenHashByteArray);
logger.info("toBeSpokenHash: {}", toBeSpokenHash);
AudioPlayer audioPlayer = null;
VoiceManager voiceManager = VoiceManager.getInstance();
Voice speakingVoice = voiceManager.getVoice("kevin16");
speakingVoice.allocate();
String outputDirectory = servingResourcesFromFileSystemAdapter.getExternalFileSystemChroot();
String waveFileUnprocessedFilesystemLocationWithoutFileExtension = outputDirectory + toBeSpokenHash + "_unprocessed";
logger.info("Will be writing an unprocessed wave file to location: {}", waveFileUnprocessedFilesystemLocationWithoutFileExtension);
audioPlayer = new SingleFileAudioPlayer(waveFileUnprocessedFilesystemLocationWithoutFileExtension, Type.WAVE);
/*
* TODO FreeTTS seems to have a bug: it cannot change the sampling rate,
* it always produces files with a sampling rate of 16000 Hz AudioFormat
* audioFormat = new AudioFormat(44100f, 16, 2, true, true);
* audioPlayer.setAudioFormat(audioFormat);
*
* System.out.println("Sample rate: " +
* audioPlayer.getAudioFormat().getSampleRate() ); if
* (audioPlayer.getAudioFormat().getSampleRate() == 8000) {
* System.out.println("is true"); } else {
* System.out.println("is false"); }
*/
speakingVoice.setAudioPlayer(audioPlayer);
speakingVoice.speak(toBeSpoken);
speakingVoice.deallocate();
audioPlayer.close();
AudioFormat newAudioFormat = new AudioFormat(8000f, 16, 1, true, false);
AudioInputStream oldStream;
try {
oldStream = AudioSystem.getAudioInputStream( new File(waveFileUnprocessedFilesystemLocationWithoutFileExtension + ".wav") );
} catch (UnsupportedAudioFileException | IOException e) {
logger.error("Problem 1 while getting audio stream", e);
throw new ApplicationException(e);
}
AudioInputStream newAudioStream = AudioSystem.getAudioInputStream(
newAudioFormat, oldStream);
try {
String waveFileProcessedFilesystemLocation = outputDirectory + toBeSpokenHash + "_processed.wav";
AudioSystem.write( newAudioStream, Type.WAVE, new File(waveFileProcessedFilesystemLocation) );
return waveFileProcessedFilesystemLocation;
} catch (IOException e) {
logger.error("Problem 2 while writing audio stream", e);
throw new ApplicationException(e);
}
}
}