Microsoft Cognitive TTS onAudioEnd event not working - text-to-speech

I am using the JavaScript version of Microsoft Cognitive Services Speech SDK from https://github.com/Azure-Samples/cognitive-services-speech-sdk.
About the SpeechSynthesizer, I include SpeakerAudioDestination to it. I want to do something when the audio playback is done so I add onAudioEnd event, but it is never fired.
Is the code below correct?
player = new SpeechSDK.SpeakerAudioDestination();
player.onAudioEnd = function (s) {
console.log("onAudioEnd", s);
};
synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig,
SpeechSDK.AudioConfig.fromSpeakerOutput(player));
Any help is appreciated!

Inside the synthesizer.speakTextAsync() callback, synthesizer.close() needs to called for player.onAudioEnd event to be fired.

Related

How to use Google Translate TTS with the new V2 API?

I used to call Google Translate TTS to download an audio file using this url:
http://translate.google.com/translate_tts?tl=en&q=Hello+world!
However Google changed the way that works and therefore I can no longer download the audio files.
I've signed up for a free trial for Google Translate API V2, but can't find how to get the TTS audio files.
Any idea?
You can use that link without captcha..
https://translate.google.com/translate_tts?ie=UTF-8&tl=tr-TR&client=tw-ob&q=Batsın+bu+dünya+bitsin+bu+rüya
I stumbled across this thread and wanted to give my take on it, with reference to #Alexandre Andrade, mainly because he didn't submit any code.
I did this in a react app, but the same procedure should works for a vanilla web project.
I did add the meta tag to my head public/index.html,
<head>
...
<meta name="referrer" content="no-referrer">
...
</head>
Then added the audio tag in my component:
Javascript:
const playTTS = (text, lang) => {
// Get the audio element
const audioEl = document.getElementById('tts-audio');
const url= `https://translate.google.com/translate_tts?ie=UTF-8&tl=${lang}&client=tw-ob&q=${text}`;
// add the sound to the audio element
audioEl.src = url;
//For auto playing the sound
audioEl.play();
};
html
...
<audio controls id="tts-audio"/>
...
Then it's just a matter of hooking the function up to some of your life cycle methods. Since I wrote my react code in react hooks, I added the function call in one of my hooks to get it initialized when the component was loaded. (this would be in the componentDidMount() function otherwise).
Hope this helps anyone out!
try this link for English:
https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=en&q=Hello+World
For Chinese (Puthonghua)
https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=zh-CN&q=世界+你好
Text-to-speech was always an 'unofficial' API which is now captcha-protected to prevent abuse. It was never advertised as part of the Translate API, and currently there is no TTS functionality in the Translate V2 API, paid or otherwise.
There is some more background on the following groups thread which had been ongoing for some time.
Here's to those who have desperately been trying to play Google TTS as an audio in HTML: let me save you a couple of hours of time and tell you how to do it.
Let's say we have this link:
https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=en&q=I+love+coffee
If you try to play this audio given the link and using <audio>, <iframe>, using third-party libraries or playing it with Javascript...
var audio = new Audio('https://translate.google.com/translate_tts...');
audio.play();
...then you'll soon find out that none of the aforementioned ways work as Error 404 is being thrown.
Solution
Apparently, the only possible way to play this TTS generic audio is to utilise <embed> tag wrapped into a custom <iframe> and giving the link a unique version number (it is important, as caching by browsers prevents the audio from playing for some reason).
Here is the solution for our example: (assuming you have an iframe#ttsiframe)
function playTTS(lang,sentence) {
//get the iframe
var iFrame = document.getElementById('ttsiframe');
//remove its sandbox property
iFrame.removeAttribute('sandbox');
//this is your reference variable for the iframe body and head tag
var iFrameBody;
//get the body
if (iFrame.contentDocument) { // FF
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0];
iFrameHead = iFrame.contentDocument.getElementsByTagName('head')[0];
}
else if (iFrame.contentWindow) { // IE
iFrameBody = iFrame.contentWindow.document.getElementsByTagName('body')[0];
iFrameHead = iFrame.contentWindow.document.getElementsByTagName('head')[0];
}
else {
iFrameBody = iFrame.contentDocument.body;
iFrameHead = iFrame.contentDocument.head;
}
//generate link to Google Translate TTS using arguments (pay attention to random version number at the end)
var link = 'https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=' + lang + '&q=' + sentence.replace(/ /g,'+').replace(/[.]/g,'') + '&rd=' + getRandomInt(0,50000000);
//add embed element with our link
iFrameBody.innerHTML = '<embed src="' + link + '" id="TTS">';
//isolate iframe
iFrame.setAttribute('sandbox','');
}
you can simply use the link:
Text to Speech

UWP custom toast notification sound doesn't play on mobile

So I have an xml as notification body witch includes audio element with source (src) attribute pointing to preset windows sound and it doesn't play the sound I want and instead plays the default system sound. My notification xml looks like this (I use this as a test message to send trough Azure notification hubs debug option)
<?xml version="1.0" encoding="utf-8"?>
<toast>
<visual>
<binding template="ToastText01">
<text id="1">Test message</text>
</binding>
</visual>
<audio src="ms-winsoundevent:Notification.Looping.Alarm" loop="false"/>
</toast>
I don't have any toast handling on my app (no background task is launched or anything). Funny thing is that my PC plays the sound it should when it recieves the notification, but phone plays default sound every time.
I need to at least play preset windows sound, but playing custom sound from local files would be ace (this doesn't work with custom sounds neither). Also if you know if there's a possibility to start playing music from background task triggered by toast notification let me know, I couldn't find any info on google on this matter.
This is the microsoft link that tells my xml is good (even though it doesn't work): https://msdn.microsoft.com/en-us/library/windows/apps/br230842.aspx
I don't have any toast handling on my app (no background task is launched or anything). Funny thing is that my PC plays the sound it should when it recieves the notification, but phone plays default sound every time.
Looks like all values which prefix is ms-winsoundevent:Notification.Looping will be replaced by system sound while set loop element to false. Based on my understanding, this should be an expected result, these values are for Looping audio, if you need to disable looping, use the first 5 values, for example: ms-winsoundevent:Notification.IM
but playing custom sound from local files would be ace (this doesn't work with custom sounds neither)
This is a known issue which was mentioned in this article
The reason is path parser has an issue to resolve ms-appx:/// path, so the audio src will be regarded as Invalid, then the default sound will be played.
The workaround is copying your wav audio file programmatically to LocalFolder and using the "ms-appdata:///local/" protocol, for example:
private async void Button_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.StorageFile audioFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/sound.wav"));
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
await audioFile.CopyAsync(localFolder);
AddNotification();
}
public void AddNotification()
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode("This is a Toast Message"));
IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("launch", "MainPage.xaml");
XmlElement audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-appdata:///local/sound.wav"); //Here
toastNode.AppendChild(audio);
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}

AIR native extension: Can I call ActionScript 3 method from C/Objective-C?

I have an AIR application that uses a native extension to create a series of dialogs the user navigates through. After the user navigates through the dialogs, I need the C/Objective-C side to notify the AIR app that the user finished as well as forward the series of choices the user made.
Is that possible?
IE: the C/ObjC equivalent of
public function evokeMyASMethod(choice0:int,choice1:int):Boolean
{
// context opens the native extension to the AS3 side
var success:Boolean = context.call("myASMethod", choice0, choice1) as Boolean;
return success;
}
An alternate solution is to start a timer in ActionScript that pings the native extension periodically to check whether the user has finished and fetch the values, but that seems so messy that I think I must be missing something obvious.
Any help is much appreciated. Thanks!
What you'll need to do is dispatch "status" events from the native code and then listen for them in your AS3 code.
So firstly in your AS3 code add a listener to your extension context:
context.addEventListener( StatusEvent.STATUS, onStatus);
private function onStatus( event:StatusEvent ):void
{
trace( "code = " + event.code );
trace( "level = " + event.level );
}
The code and level variables are two strings you can pass back from your native code. In your ObjC code you'll use the FREDispatchStatusEventAsync function to fire an event back to your AS3 code:
FREDispatchStatusEventAsync( yourFreContext, (const uint8_t*)"code", (const uint8_t*)"level" );
You just need to change the "code" and "level" strings as you see fit and process them in your onStatus handler.
More information here:
http://help.adobe.com/en_US/air/extensions/WSb464b1207c184b143961a5e412937b5d5c6-7ffc.html
http://help.adobe.com/en_US/air/extensions/WSb464b1207c184b14-62b8e11f12937b86be4-7ff5.html

CoreDispatcher.ProcessEvents() causes an indirect crash?

I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT (using C++/CX). Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.
I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.
Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):
void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
bool cancel = false;
auto popup = ref new Popup();
auto button = ref new Button();
button->Content = "Boom";
auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
popup->Child = button;
popup->IsOpen = true;
while (!cancel)
{
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
popup->IsOpen = false;
button->Click -= token;
}
This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will instantly crash deep in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).
Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?
If anyone is interested: I asked the same question a few days later on the MSDN forums and got a response there from a Microsoft employee:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/
Apparently the problem here is the nested message loop that is caused by calling ProcessEvents inside an event handler. It seems that this is not supported by WinRT, but instead of failing in a well-defined manner, this will or may cause a crash.
Alas this was the best and only answer I could find, so I ended up working around the problem, by dispatching the event handler (and a lot of other code) into another thread. I could then emulate the waiting behavior of DialogBox()/DialogBoxParam() (outside the main thread), by waiting on an event that was signaled when the user clicked/tapped a button on my XAML "dialog" popup.
A workaround that works fine for me is to replace the line:
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
with:
auto myDispatchedHandler = ref new DispatchedHandler([&](){
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
});
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);
For more info see this post at MSDN.

Web Audio API. Play sound on click of button

I am a complete novice with HTML5 and coding for that matter. I have been trying to get to grips with the web audio API. I want a sound to play at a click of a button. I used a tutorial posted on HTML5Rocks, but cannot get it to work. I have tried to use jfiddle to help me troubleshoot, but to no avail.
here is my code:
http://jsfiddle.net/ue8WP/
Try this:
function playsound()
{
var filepath='sounds/'+....+'.mp3'; //example
var audio = new Audio();
audio.src = filepath;
audio.controls = true;
audio.autoplay = true;
}
Here's a simplified version of your code that should work fine. You only need to load some other sample sound, since there is a problem with fetching the one you provided (not allowed by Access-Control-Allow-Origin).
http://jsfiddle.net/WB6Pw/3/