Skip to main content

Showing a stop speech button only when a webpage is speaking

As evident from the evolution of my first iOS app: My Day Todos; it started off as being a pure Html5 app until it turned into a native iOS app with Html5 powered UI. The app has a very significant text to speech component and before using native iOS API for it i.e. AvSpeechSynthesizer, the text to speech component was powered by the Web Speech API. I will not be talking  about why I switched the AvSpeechSynthesizer but rather a little problem that I had to solve while working with the web speech API.

Problem: Show a stop button only when an utterance is being spoken

So firstly, I think the Web Speech API is a lot of fun to play with and if you like to know more about it, you can either have a read of the spec or do this tutorial to get a feel of how it all works. Also when I talk about the web speech API, I am only talking about speech synthesis.
All right, so what I wanted in my app was to show a stop button when the app is speaking i.e. reading out something and only when it is speaking and not when it's not. I did not want the stop button to be visible at all times. 

Solution: A boolean and a timeout

The speech synthesis API has a boolean which would tell us if the speech is currently being spoken. You can have a look at the speaking attribute in the spec or typing window.speechSynthesis.speaking in Chrome developer tools console should return a boolean. So my solution was to combine the speaking attribute with setTimeout. Ok, I am not sure if this is the best solution to this problem, but it is a solution none the less, if you know of a better solution then please let me know by leaving a comment for this post.

Solution implementation

So the goal is to check at specified time intervals if an utterance is being spoken as soon we trigger the speech i.e. as soon as we make our web page start speaking. I have created a little demo of my solution that you can download from Github.

All right, let's have a look at the source for my solution on Github,

Firstly we have our webpage,

<body>
    <p> Speak an arbitrary long string of text</p>
    <button id="speak" onclick="speak()" style="float:left;margin-right:2px;"> Speak </button>
    <button id="stop" style="display:none;" onclick="stopSpeech()" > Stop </button>
</body>
It tells us that some arbitrary text will be spoken, when we click the button to speak and then we have a stop button which is not visible by default. 
FYI, I wanted to make a simple example to demonstrate my solution about so I did not bother adding CSS classes in a separate CSS file to style the contents. 

Ok, now let's look at the code (Javascript) that's invoked when Start and Stop buttons are clicked.


function speak(){
    var speechText ="This is a long, a very long string of text that I need to speak";
    var utterance = new SpeechSynthesisUtterance(speechText);
    window.speechSynthesis.speak(utterance);
    document.getElementById("speak").disabled = true;
    document.getElementById("stop").style.display = "block";
    function checkSpeaking(){
        if(window.speechSynthesis.speaking){
            setTimeout(checkSpeaking, 50);
        } else {
            document.getElementById("speak").disabled = false;
            document.getElementById("stop").style.display = "none";
        }
    }
    setTimeout(checkSpeaking,50);
}
function stopSpeech(){
    document.getElementById("speak").disabled = false;
    document.getElementById("stop").style.display = "none";
    window.speechSynthesis.cancel();
}
The code is pretty self-explanatory but should you have any questions, then feel free to ask. The only thing to note is, just see how we toggle the enabled state of the speak button and the visibility of the stop button? Now let's think of this in terms of states, so our little web page has 2 states,
  1. Not speaking: Speak button enabled and stop button invisible
  2. Speaking: Speak button disabled and Stop button visible
the states are controlled by the Speak and Stop buttons. However, what I wanted out of this was to ensure that the Stop button is only visible when something is being spoken so I added the timeout, which checks at periodic intervals if an utterance is being spoken. That is what the checkSpeaking method is for i.e. if an utterance is being spoken then leave the state to Speaking and if it is not then change the state to Not speaking.

Conclusion

This is yet another problem that I had to solve while building my iOS app My Day Todos, which I wanted to share with everyone. If you have had to solve this problem and you have a different solution, then I would love to hear about it, so please leave a comment.

Finally, I am working on my app full-time right now so if you find my blog posts useful and want to support me you can 
  • Or one of the cheaper versions, L or W
Any feedback on my apps or the way I write my post, would be great.



Comments

Popular posts from this blog

Upload to AWS S3 from Java API

In this post, you will see code samples for how to upload a file to AWS S3 bucket from a Java Spring Boot app. The code you will see here is from one of my open-source repositories on Github, called document-sharing. Problem Let’s say you are building a document sharing app where you allow your users to upload the file to a public cloud solution. Now, let’s say you are building the API for your app with Spring Boot and you are using AWS S3 as your public cloud solution. How would you do that? This blog post contains the code that can help you achieve that. Read more below,  Upload to AWS S3 bucket from Java Spring Boot app - My Day To-Do (mydaytodo.com)

Addressing app review rejections for auto-renewing subscription in-app purchase (iOS)

The ability to know what the weather is like while planning your day is a feature of  My Day To-Do  Pro and as of the last update it’s also a part of the  Lite version . Unlike the Pro version it’s an auto-renewing subscription based  in-app purchase (IAP)  in the Lite version. What means is that when a user purchases it, the user only pays for the subscription duration after which the user will be automatically charged for the next period. Adding an  auto-renewing  subscription based IAP proved to be somewhat challenging in terms of the app store review i.e. the app update was rejected by the App Review team thrice because of missing information about the IAP. Therefore in this post I will share my experiences and knowledge of adding auto-renewing IAP in hopes to save someone else the time that I had to spend on this problem. In-App purchase This year I started adding IAPs to My Day To-Do Lite which lead to learning about different types of IAP...

Serving HTML content in an iOS app that works in iOS 7 and later (using Swift)

As I have mentioned in an earlier post , I really enjoying coding in Swift. Now what am I doing with it? Well I am trying to build an HTML5 app that must work on devices with iOS 7. So in iOS8 apple has introduced a whole bunch of features that facilitate easy communication between web content and lets just call it back-end Swift code, but those features are not in iOS 7. So why do I want to build something that would work in an older OS? well I do not expect existing iOS users to upgrade to iOS 8 straight away and i also know a couple of people who would be very reluctant to upgrade their iPhones to iOS 8. Now in case you do not, you can have a read of the "Working with WebViews" section of this post , to know how to serve HTML content with WebViews. So when I started building my app, I wanted to know: How do I invoke some Swift code from my HTML content? Well the solution to this may feel a little bit "hacky" but it is a solution to achieve this.  The followi...