using System;
using System.IO;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using Amazon.Polly;
using Amazon.Polly.Model;
public class PollyService
{
private readonly string _accessKeyId;
private readonly string _secretKey;
private readonly string _sessionToken;
private readonly Amazon.RegionEndpoint _region;
private VoiceId _voiceId;
const string k_AudioDirectoryName = "PollyAudio";
public PollyService(string accessKeyId, string secretKey, string sessionToken, Amazon.RegionEndpoint region, string voice)
{
_accessKeyId = accessKeyId;
_secretKey = secretKey;
_sessionToken = sessionToken;
_region = region;
_voiceId = VoiceId.FindValue(voice);
string directoryPath = Path.Combine(Application.persistentDataPath, k_AudioDirectoryName);
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
}
///
/// Calls Amazon Polly to convert text to speech
///
/// text to convert
public async Task SynthesizeSpeech(string message, int sampleRate = 16000, EventHandler callback = null)
{
try
{
using (var client = new AmazonPollyClient(_accessKeyId, _secretKey, _sessionToken, _region))
{
if (_voiceId == null)
{
_voiceId = VoiceId.Emma;
}
var response = await client.SynthesizeSpeechAsync(
new SynthesizeSpeechRequest()
{
Text = message,
VoiceId = _voiceId,
OutputFormat = OutputFormat.Mp3,
SampleRate = sampleRate.ToString()
}
);
if (response.HttpStatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception($"[TranslateManager] Failed to get audio clip. Status code: {response.HttpStatusCode}");
}
if (response.AudioStream != null)
{
string path = await CreateFile(response.AudioStream);
MainThreadDispatcher.ExecuteCoroutineOnMainThread(IERequestAudio(path, callback));
}
}
}
catch (Exception e)
{
throw new Exception($"[TranslateManager] Speech Synthesis Failed. {e}");
}
}
private IEnumerator IERequestAudio(string path, EventHandler callback = null)
{
string localPath = $"file://{path}";
using (UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(localPath, AudioType.MPEG))
{
yield return request.SendWebRequest();
switch (request.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
case UnityWebRequest.Result.ProtocolError:
Debug.LogError($"{request.result}: {request.error}");
break;
case UnityWebRequest.Result.Success:
AudioClip clip = DownloadHandlerAudioClip.GetContent(request);
if (callback != null)
{
callback.Invoke(this, new SynthesizeSpeechEventArgs(path, clip));
}
break;
}
}
}
private async Task CreateFile(Stream audioStream)
{
string dateTime = DateTime.Now.ToString("yyyyMMddHHmmss");
string filename = $"{dateTime}-polly-audio.mp3";
string path = Path.Combine(Application.persistentDataPath, k_AudioDirectoryName, filename);
using (FileStream fs = File.Create(path))
{
await audioStream.CopyToAsync(fs);
}
return path;
}
}
public class SynthesizeSpeechEventArgs : EventArgs
{
public SynthesizeSpeechEventArgs(string path, AudioClip clip)
{
this.Path = path;
this.Clip = clip;
}
public string Path;
public AudioClip Clip;
}