Git Product home page Git Product logo

text-to-speech's Introduction


Text to Speech

@capacitor-community/text-to-speech

Capacitor community plugin for synthesizing speech from text.


Maintainers

Maintainer GitHub Social
Robin Genz robingenz @robin_genz

Installation

npm install @capacitor-community/text-to-speech
npx cap sync

Configuration

No configuration required for this plugin.

Demo

A working example can be found here: robingenz/capacitor-plugin-demo

Usage

import { TextToSpeech } from '@capacitor-community/text-to-speech';

const speak = async () => {
  await TextToSpeech.speak({
    text: 'This is a sample text.',
    lang: 'en-US',
    rate: 1.0,
    pitch: 1.0,
    volume: 1.0,
    category: 'ambient',
  });
};

const stop = async () => {
  await TextToSpeech.stop();
};

const getSupportedLanguages = async () => {
  const languages = await TextToSpeech.getSupportedLanguages();
};

const getSupportedVoices = async () => {
  const voices = await TextToSpeech.getSupportedVoices();
};

const isLanguageSupported = async (lang: string) => {
  const isSupported = await TextToSpeech.isLanguageSupported({ lang });
};

API

speak(...)

speak(options: TTSOptions) => Promise<void>

Starts the TTS engine and plays the desired text.

Param Type
options TTSOptions

stop()

stop() => Promise<void>

Stops the TTS engine.


getSupportedLanguages()

getSupportedLanguages() => Promise<{ languages: string[]; }>

Returns a list of supported BCP 47 language tags.

Returns: Promise<{ languages: string[]; }>


getSupportedVoices()

getSupportedVoices() => Promise<{ voices: SpeechSynthesisVoice[]; }>

Returns a list of supported voices.

Returns: Promise<{ voices: SpeechSynthesisVoice[]; }>


isLanguageSupported(...)

isLanguageSupported(options: { lang: string; }) => Promise<{ supported: boolean; }>

Checks if a specific BCP 47 language tag is supported.

Param Type
options { lang: string; }

Returns: Promise<{ supported: boolean; }>


openInstall()

openInstall() => Promise<void>

Verifies proper installation and availability of resource files on the system.

Only available for Android.


Interfaces

TTSOptions

Prop Type Description Default
text string The text that will be synthesised when the utterance is spoken.
lang string The language of the utterance. Possible languages can be queried using getSupportedLanguages. "en-US"
rate number The speed at which the utterance will be spoken at. 1.0
pitch number The pitch at which the utterance will be spoken at. 1.0
volume number The volume that the utterance will be spoken at. 1.0
voice number The index of the selected voice that will be used to speak the utterance. Possible voices can be queried using getSupportedVoices.
category string Select the iOS Audio session category. Possible values: ambient and playback. Use playback to play audio even when the app is in the background. Only available for iOS. "ambient"

SpeechSynthesisVoice

The SpeechSynthesisVoice interface represents a voice that the system supports.

Prop Type Description
default boolean Specifies whether the voice is the default voice for the current app (true) or not (false).
lang string BCP 47 language tag indicating the language of the voice.
localService boolean Specifies whether the voice is supplied by a local (true) or remote (false) speech synthesizer service.
name string Human-readable name that represents the voice.
voiceURI string Type of URI and location of the speech synthesis service for this voice.

Changelog

See CHANGELOG.md.

License

See LICENSE.

text-to-speech's People

Contributors

dependabot[bot] avatar dhruv-1105 avatar ecc521 avatar hpflatorre avatar jcesarmobile avatar jerrynavi avatar marnickvda avatar mlynch avatar mogery avatar priyankpat avatar robingenz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

text-to-speech's Issues

bug: The text is still heard when changing the url

Plugin version:
1.1.2

Platform(s):
Chrome and Edge browsers

Current behavior:
Hello, in Chrome and Edge (Chromium browsers), when you are listening to a text, and you change the url to a completely different one, the text continues to be heard. I have tried to put await TextToSpeech.stop(); on a lot of sites but there is no way to make it not speak.

Expected behavior:
That the text is not heard when you change the url of the page.

Steps to reproduce:
Run the example from https://github.com/robingenz/capacitor-plugin-demo in Chrome, and go to the text-to-speech tab, put a long text, and change the url to one that doesn't have nothing to do with the project.

Capacitor doctor:

Latest Dependencies:

  @capacitor/cli: 3.4.3
  @capacitor/core: 3.4.3
  @capacitor/android: 3.4.3
  @capacitor/ios: 3.4.3

Installed Dependencies:

  @capacitor/ios: not installed
  @capacitor/core: 3.4.3
  @capacitor/cli: 3.4.3
  @capacitor/android: 3.4.3

Regards!

bug: unhelpful error "Failed to read text." when passed a long amount of text.

OS: Android 10
Latest "text-to-speech" version

The error message gives no other clues.. is my device out of memory, is there a limit to the text to send, are there characters the reader doesn't support?

Basic snippet works with short bits of text but longer text fails:

await TextToSpeech.speak({
        text: input.text,
        lang,
        rate: input.rate,
        pitch: input.pitch,
        volume: input.volume,
        category: 'ambient',
      });

When passing in the following string which is an article extract from a random blog (https://medium.com/@everywhereist/bros-lecce-we-eat-at-the-worst-michelin-starred-restaurant-ever-3466c98cdbdf) it only returns "Failed to read text.":

Geraldine DeRuiter [https://miro.medium.com/fit/c/56/56/1*w_MQ2FTD63HQBazomOwJLg.png]
[https://medium.com/@everywhereist?source=post_page-----3466c98cdbdf-----------------------------------]

[https://miro.medium.com/max/1400/1*JxYfu0_CFzTM-r4U6x7OtA.png]

Rand’s face as he tries one of the “courses.”

Note: This was originally published on The Everywhereist blog [https://bit.ly/HellNoBros].

There is something to be said about a truly disastrous meal, a meal forever indelible in your memory because it’s so uniquely bad,
it can only be deemed an achievement. The sort of meal where everyone involved was definitely trying to do something; it’s just
not entirely clear what.

I’m not talking about a meal that’s poorly cooked, or a server who might be planning your murder — that sort of thing happens in
the fat lump of the bell curve of bad. Instead, I’m talking about the long tail stuff — the sort of meals that make you feel as
though the fabric of reality is unraveling. The ones that cause you to reassess the fundamentals of capitalism, and whether or not
you’re living in a simulation in which someone failed to properly program this particular restaurant. The ones where you just know
somebody’s going to lift a metal dome off a tray and reveal a single blue or red pill.

I’m talking about those meals.

At some point, the only way to regard that sort of experience — without going mad — is as some sort of community improv theater.
You sit in the audience, shouting suggestions like, “A restaurant!” and “Eating something that resembles food” and “The exchange
of money for goods, and in this instance the goods are a goddamn meal!” All of these suggestion go completely ignored.

That is how I’ve come to regard our dinner at Bros, Lecce’s only Michelin-starred restaurant, as a means of preserving what’s left
of my sanity. It wasn’t dinner. It was just dinner theater.

No, scratch that. Because dinner was not involved. I mean — dinner played a role, the same way Godot played a role in Beckett’s
eponymous play. The entire evening was about it, and guess what? IT NEVER SHOWED.

[https://miro.medium.com/max/1126/1*ruc9YQ1gJ9YhwEjMjB_Tvw.png]

Rand holding up one of the courses — a paper-thin fish cracker — in its entirety.

So no, we can’t call it dinner theater. Instead, we will say it was just theater.

Very, very expensive theater.

I realize that not everyone is willing or able to afford a ticket to Waiting for Gateau and so this post exists, to spare you our
torment. We had plenty of beautiful meals in Lecce that were not this one, and if you want a lovely meal out, I’ll compile a list
shortly.

But for now, let us rehash whatever the hell this was.

We headed to the restaurant with high hopes — eight of us in total, led into a cement cell of a room, Drake pumping through
invisible speakers. It was sweltering hot, and no other customers were present. The décor had the of chicness of an underground
bunker where one would expect to be interrogated for the disappearance of an ambassador’s child.

Earlier that day, we’d seen a statue of a bear, chiseled into marble centuries ago, by someone who had never actually seen a bear.
This is the result:

[https://miro.medium.com/max/1400/1*27GpSnf8K6dcTIHBUsj_Nw.png]

And this is a perfect allegory for our evening. It’s as though someone had read about food and restaurants, but had never
experienced either, and this was their attempt to recreate it.

What followed was a 27-course meal (note that “course” and “meal” and “27” are being used liberally here) which spanned 4.5 hours
and made me feel like I was a character in a Dickensian novel. Because — I cannot impart this enough — there was nothing even
close to an actual meal served. Some “courses” were slivers of edible paper. Some shot were glasses of vinegar. Everything tasted
like fish, even the non-fish courses. And nearly everything, including these noodles, which was by far the most substantial dish
we had, was served cold.

[https://miro.medium.com/max/1400/1*u_FZ6s9YeSkWSwrhO-ndcQ.png]

I’ve added the bread plate for scale. This was the largest course of the 27 (We got six noodles and one piece of bread each.)

Amassing two-dozen of them together amounted to a meal the same way amassing two-dozen toddlers together amounts to one
middle-aged adult.

[https://miro.medium.com/max/1120/1*lSmxF-OT0aaY1HX49YARrQ.png]

A course for *two* people at Bros.

I’ve checked Trip Advisor. Other people who’ve eaten at Bros were served food
[https://www.tripadvisor.com/Restaurant_Review-g194791-d9725946-Reviews-Bros-Lecce_Province_of_Lecce_Puglia.html]. Some of them
got meat, and ravioli, and more than one slice of bread. Some of them were served things that needed to be eaten with forks and
spoons.

We got a tablespoon of crab.

[https://miro.medium.com/max/1124/1*OTLxZpyvYmIxkkjRadhFyw.png]

This was a main course. It’s about a tablespoon of food.

I’ve tried to come up with hypotheses for what happened. Maybe the staff just ran out of food that night. Maybe they confused our
table with that of their ex-lover’s. Maybe they were drunk. But we got twelve kinds of foam, something that I can only describe as
“an oyster loaf that tasted like Newark airport”, and a teaspoon of savory ice cream that was olive flavored.

[https://miro.medium.com/max/1130/1*Nr5x73aqIxhU7ybBc8xzhg.png]

A sliver of oyster loaf with foam. David’s face here says more than I ever can.

[https://miro.medium.com/max/1008/1*Ba0aTB_jpEaNmpP5DbZahg.png]

Teaspoon of olive ice cream.

I’m still not over that, to be honest. I thought it was going to be pistachio.

There is no menu at Bros. Just a blank newspaper with a QR code linking to a video featuring one of the chefs, presumably, against
a black background, talking directly into the camera about things entirely unrelated to food. He occasionally used the proper noun
of the restaurant as an adverb, the way a Smurf would. This means that you can’t order anything besides the tasting menu, but also
that you are at the mercy of the servers to explain to you what the hell is going on.

The servers will not explain to you what the hell is going on.

They will not do this in Italian. They will not do this in English. They will not play Pictionary with you on the blank newspaper
as a means of communicating what you are eating. On the rare occasion where they did offer an explanation for a dish, it did not
help.

“These are made with rancid ricotta,” the server said, a tiny fried cheese ball in front of each of us.

“I’m… I’m sorry, did you say rancid? You mean… fermented? Aged?”

“No. Rancid.”

“Okay,” I said in Italian. “But I think that something might be lost in translation. Because it can’t be-”

“Rancido,” he clarified.

Another course — a citrus foam — was served in a plaster cast of the chef’s mouth. Absent utensils, we were told to lick it out of
the chef’s mouth in a scene that I’m pretty sure was stolen from an eastern European horror film.

[https://miro.medium.com/max/1078/1*jyVvN-wPQbQouQ2RNUrVaQ.png]

For reasons that could fill an entire volume of TimeLife Mysteries of the Unknown, THIS ITEM IS AVAILABLE FOR SALE AT THEIR
GIFTSHOP [https://www.pellegrinobrothers.it/en/product/limoniamo-floriano/]. In case you want to have a restraining order filed
against you this holiday season.

Now, at this point, I may have started quietly freaking out. A hierarchical pecking order was being established, and when you’re
the one desperately slurping sustenance out of the plaster cast of someone else’s mouth, it’s safe to say you are at the bottom of
that pyramid. We’d been beaten into some sort of weird psychological submission. Like the Stanford Prison Experiment
[https://en.wikipedia.org/wiki/Stanford_prison_experiment] but with less prison and more aspic. That’s the only reason I have for
why we didn’t leave during any of these incidents:

 * When a member of our party stood up during the lengthy stretch between courses to go have a cigarette outside, and was scolded
   to sit down.
 * When one member of our party was served nothing for three consecutive courses, because they couldn’t figure out how to
   accommodate her food allergies.
 * When Rand was served food he was allergic to, repeatedly, because they didn’t care enough to accommodate his.
 * When a server reprimanded me for eating. These reconstituted orange slices (one per person) were a course. I asked if I could
   eat the real orange that had been served alongside it (we’d all gotten one, and I, at this point, was extremely hungry). “Yes,”
   the server said, annoyed. “But you aren’t really supposed to.” He let me have two segments and then whisked the fruit away.

[https://miro.medium.com/max/1130/1*BqS17SosY_lAIQME-hmW6A.png]

No, we just sat there while the food was portioned out a teaspoon at a time, a persistent and sustained sort of agony, like slowly
peeling off a band-aid. That’s the problem with a tasting menu. With so many courses, you just assume things are going to turn
around. Every dish is a chance for redemption. Maybe this meal was like Nic Cage’s career — you have to wait a really long time
for the good stuff, but there is good stuff.

BUT NO. We kept waiting for someone to bring us something — anything! — that resembled dinner. Until the exact moment when we
realized: it would never come. It was when our friend Lisa tried to order another bottle of wine.

“Would you like red or white?” the server asked.

“What are we having for the main?” she inquired.

His face blanched.

“The… main, madame? Um… we’re about to move on to dessert.”

We sat for a moment, letting this truth settle over us. Because by now it had been hours, and at no point had we been served
anything that could be considered dinner. (There was one time when I thought it might happen — the staff placed dishes in front of
us, and then swirled sauces on the dishes, and I clapped my hands, excitedly waiting for something to be plated atop those
beautiful sauces. Instead, someone came by with an eyedropper and squirted drops of gelee onto our plates).

[https://miro.medium.com/max/896/1*pImaHJeSxn0zEaoPR0ua3A.png]

The meat droplet course.

“We’ve infused these droplets with meat molecules,” the server explained, and left.

I don’t know if our experience was the norm. I’ve looked TripAdvisor’s photo for Bros, and other people who’ve gone there seem to
have been fed actual food. Like, even this person, who was served the same weird meat droplet course, at least got it with a
triangle of foamy-looking bread [https://www.instagram.com/p/CHAjuY2DX5m/]. Do you know what it’s like to envy someone for a piece
of foamy looking bread? IT’S NOT GREAT.

“There’s no … main?” Lisa said to us in disbelief after the server had retreated.

“Hey,” I said, my hand resting on her arm. She was shaking slightly from low blood sugar. “It’s okay.”

“They haven’t fucking fed us,” she said, her eyes wide.

“I know, I know” I said, “But look. We’re in this amazing country. And I don’t know about you, but nothing is going to stop me
from enjoying tonight.”

She nodded.

“Because I’m surrounded by my favorite people,” I said, and I squeezed Lisa’s hand for emphasis, “and I’m at my favorite
restaurant.”

Lisa sputtered laughing. No more food was coming, but there was something freeing in that. Because this meal had never been about
us to begin with. It sure as hell wasn’t about the food. And there is something glorious about finally giving up.

[https://miro.medium.com/max/1800/1*4HN0IdIg0Ig--Tb-RykYjg.png]

[https://miro.medium.com/max/1400/1*eGE4FNOvCd2k-PRqut7dqw.png]

We sat through a few more courses including a marshmallow flavored like cuttlefish, and a dish called “frozen air” which literally
melted before you could eat it, which melt like a goddamn metaphor for the night.

And then someone came in and demanded we stand and exit the restaurant. Thinking we were getting kicked out, we gleefully
followed. Instead, we were led across the street, to a dark doorway and into the Bros laboratory. A video of the shirtless kitchen
staff doing extreme sports played on a large screen TV while a chef cut us comically tiny slivers of fake cheese.

Rand was, of course, allergic to it.

The bill arrived. The meal cost more than any other we’d eat during our trip by a magnitude of three. They’d given us balloons
with the restaurant’s name across it and the chef emerged and insisted on posing with us for a Polaroid that we did not ask for.
We were finally released into the night, after every other restaurant had closed, ensuring that no food would be consumed that
evening.

“That was abhorrent,” we all agreed as we shoved the balloons into a dumpster (I’d made everyone take one, with the baffling logic
that they’d somehow help offset the cost of the meal). We howled at how ridiculous it was, and how they’d poisoned Rand. How maybe
we should have known that a restaurant named “Bros” was going to be a disaster.

It was like an awful show that we had front row tickets to. But wasn’t there something glorious about sharing it together, the way
that a terrible experience makes you all closer?

“No,” someone said, and we laughed even harder.

P.S. — The next day, one of the staff tried contacting the only single female member of our party via Instagram messages. “Hey, I
served you last night!” he wrote. She immediately blocked him.

Bros. [https://www.pellegrinobrothers.it/en/], Via degli Acaya, 2, 73100 Lecce LE, Italy

Cost: a rather mortifying 130–200 Euros per person

Note: the TripAdvisor reviews show a lot of elaborate courses, and these were all way, way more food than anything we ate. I
cannot express to you how little we were fed, and I’m not a particularly big eater. Allergy and dietary restrictions were largely
ignored.

Recommendation: Do not eat here. I cannot express this enough. This was single-handedly one of the worse wastes of money in my
entire food and travel writing career bwah ha ha ha ha ha ha oh my god

Cant run on iOS

Describe the bug
When trying to sync before running iOS build. It gives me this error and eventually fails on Xcode as well.
image

To Reproduce
Steps to reproduce the behavior:
Follow as readme

bug: types are not detected by editor

Describe the bug
grafik

To Reproduce

import { Injectable } from '@angular/core';
import '@capacitor-community/text-to-speech';
import { Plugins } from '@capacitor/core';

@Injectable({
  providedIn: 'root',
})
export class TextToSpeechService {
  constructor() {}

  public async speak(): Promise<void> {
    await Plugins.TextToSpeech.
  }
}

Expected behavior
grafik

Additional context
Editor: VS Code 1.54.1

[Android] getSupportedLanguages()

The response of the method getSupportLanguages() returns this:

{
   languages: "[Ljava.lang.Object;@f6680b0"
}

Could anyone please clarify what does that mean? Or is it a bug to show "[Ljava.lang.Object;@f6680b0" as the languages? Thanks.

Documentation: Installation command

Please update the installation command in documentation

change
npm install @capacitor/text-to-speech

to
npm install @capacitor-community/text-to-speech

Thanks

bug: different behavior when `speak` is called again before quitting

Describe the bug
There is different behavior when speak is called again before the previous call is finished.
Android: Aborts and starts with the new call.
Web: Does not abort.
iOS: Aborts and starts with the new call.

To Reproduce
Run speak several times in rapid sequence.
Example sentence: This is a test.

Expected behavior
The platforms should behave in the same way.

Error: Unsupported locale

Describe the bug
TextToSpeech.getSupportedLanguages() returns undefined in web & android platforms not sure about ios.

Workaround
Pass undefined to locale property

Bug: Unsupported Device on Android

Describe the bug

I got "Unsupported Device" on a Huawei Android 11

To Reproduce
Steps to reproduce the behavior:

I reproduced exactly the code from the Readme.
On iOS 12 (iPhone 6) the same code works perfectly.
I added the intent on the Android Manifest and also registered the plugin on MainActivity.java.

Debugging, When I call the "speak" method, I see that "this.speechSynthesis" is null, so I got the error of unsupported device.
Why so?
What can be the reason?

Expected behavior

I expected the APIs to work

Screenshots
image

image

Smartphone (please complete the following information):

  • Huawei P20
  • OS: Android 11
  • Chrome 89

bug: not working in background on iOS

Describe the bug
The speak method does not work on iOS when the app is in the background. No sound is played. No sound is played.

To Reproduce
Send push notification with text to speech to the device

Plugins.TextToSpeech.speak({ text: textFromPush });

Expected behavior
The method should play sound.

Smartphone (please complete the following information):

  • Device: iPhone 12,1
  • OS: iOS 13.5.1

Speak not working!

Plugin not working either on web or even in android devices. Getting error:

ERROR Error:
Uncaught (in promise): TypeError: Failed to set the 'voice' property on 'SpeechSynthesisUtterance': The provided value is not of type 'SpeechSynthesisVoice'.

Also installation commends are wrong:
it should be as per the NPM directory: npm i @capacitor-community/text-to-speech

Speech not working (returning undefined)

Hello I've been trying to get capacitor tts to work on Android for around a week but thus far have been unable to.

It keeps returning this error in logcat:

Line xxxx - Msg: Uncaught (in promise) ReferenceError: speech_function is not defined

speech_function literally follows verbatim the instructions in the docs i.e.:

//capacitor plugin for speech
import { TextToSpeech } from '@capacitor-community/text-to-speech';
let speech_function = async (m_word) => {
await TextToSpeech.stop();

await TextToSpeech.speak({
text: m_word,
lang: 'en_US',
rate: 1.3,
pitch: 0.9,
volume: 1.0,
category: 'ambient',
});
};

The gradle files for the plugin have been included after npx cap sync and then sycning the gradle files with the project, I'm wondering if I missed anything?

[Android] Unable to get supported voices

Describe the bug
As I call TextToSpeech.getSupportedVoices(), the following error appears:
'Error: Cannot find a differ supporting object '[Voice[Name: es-us-x-sfb-local, locale: es_US, quality: 400, latency: 200, requiresNetwork: false, features: [networkTimeoutMs, notInstalled, networkRetriesCount]], Voice[Name: ...'

To Reproduce
Steps to reproduce the behavior:

  1. Import TextToSpeech plugin
  2. Call TextToSpeech.getSupportedVoices()
  3. See error

Expected behavior
return a promise on this object: {voices: SpeechSynthesisVoice[];}

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Win10
  • Browser Chrome
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: Android
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context

bug: Rate option not working on ios

Plugin version:
1.1.1

Platform(s):
ios 14.6, 15

Current behavior:
rate option doesn't change voice speed on ios

Expected behavior:
rate option must change voice speed on ios

Steps to reproduce:

  1. change rate option in speak() method
  2. run application on ios device or simulator
  3. check speak voice speed

Related code:

      await TextToSpeech.speak({
        text: 'Hello'
        rate: 2.0
      });

Other information:
Android and web implementations work good
Capacitor 3

bug: has leaked ServiceConnection

Describe the bug
Got this error message when closing the app:

2021-03-17 16:46:12.644 3856-3856/app E/ActivityThread: Activity app.MainActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@87036b7 that was originally bound here
    android.app.ServiceConnectionLeaked: Activity app.MainActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@87036b7 that was originally bound here
        at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1820)
        at android.app.LoadedApk.getServiceDispatcherCommon(LoadedApk.java:1692)
        at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:1671)
        at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1755)
        at android.app.ContextImpl.bindService(ContextImpl.java:1684)
        at android.content.ContextWrapper.bindService(ContextWrapper.java:705)
        at android.speech.tts.TextToSpeech.connectToEngine(TextToSpeech.java:821)
        at android.speech.tts.TextToSpeech.initTts(TextToSpeech.java:791)
        at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:744)
        at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:723)
        at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:707)
        at com.getcapacitor.community.tts.TextToSpeech.load(TextToSpeech.java:74)
        at com.getcapacitor.PluginHandle.load(PluginHandle.java:72)
        at com.getcapacitor.PluginHandle.<init>(PluginHandle.java:44)
        at com.getcapacitor.Bridge.registerPlugin(Bridge.java:460)
        at com.getcapacitor.Bridge.registerAllPlugins(Bridge.java:424)
        at com.getcapacitor.Bridge.<init>(Bridge.java:170)
        at com.getcapacitor.BridgeActivity.load(BridgeActivity.java:83)
        at com.getcapacitor.BridgeActivity.init(BridgeActivity.java:62)
        at com.getcapacitor.BridgeActivity.init(BridgeActivity.java:48)
        at app.MainActivity.onCreate(MainActivity.java:17)
        at android.app.Activity.performCreate(Activity.java:7820)
        at android.app.Activity.performCreate(Activity.java:7809)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3363)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3527)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2123)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7710)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

To Reproduce
Install this plugin and run/close your app.

Expected behavior
No error message.

bug: TTS not triggered on iOS16

Plugin version:
v2.0.1

Platform(s):
iOS 16

Current behavior:
In iOS 15.5 when running

speak = async (msg) => {
    await TextToSpeech.speak({
      text: msg,
      lang: "en-AU",
      rate: 1.0,
      pitch: 1.0,
      volume: 1.0,
      category: "ambient",
    });
  }; 

or even

getSupportedLanguages()

The text is read fine in <16 but in iOS 16 (I did try en-US too) no longer does and we get errors in the console;

⚡️ To Native -> TextToSpeech getSupportedLanguages 125237587
⚡️ TO JS {"languages":[]}
⚡️ [log] - undefined
⚡️ To Native -> TextToSpeech speak 125237588
ERROR MESSAGE: {"errorMessage":"This language is not supported.","message":"This language is not supported."}
⚡️ [error] - {"errorMessage":"This language is not supported.","message":"This language is not supported."}
2022-09-14 10:02:10.029667+0930 App[78368:14819623] [asset] Failed to get sandbox extensions
2022-09-14 10:02:10.060227+0930 App[78368:14819623] [catalog] Unable to list voice folder
2022-09-14 10:02:10.075312+0930 App[78368:14819623] [catalog] Unable to list voice folder
2022-09-14 10:02:10.077749+0930 App[78368:14819623] [catalog] Unable to list voice folder
2022-09-14 10:02:10.086635+0930 App[78368:14819623] [catalog] Unable to list voice folder

Expected behavior:
Plays as normal in either <16 and 16

Steps to reproduce:
As abive

Related code:
As above

Capacitor doctor:

💊   Capacitor Doctor  💊

Latest Dependencies:

  @capacitor/cli: 4.2.0
  @capacitor/core: 4.2.0
  @capacitor/android: 4.2.0
  @capacitor/ios: 4.2.0

Installed Dependencies:

  @capacitor/cli: 4.1.0
  @capacitor/android: 4.1.0
  @capacitor/ios: 4.1.0
  @capacitor/core: 4.1.0

[success] iOS looking great! 👌
[success] Android looking great! 👌

feat: onEnd event is required

Is your feature request related to a problem? Please describe:

Describe the solution you'd like:

Describe alternatives you've considered:

Additional context:

feat: save to file

Hi all, dont know if is already possible but I didnt find anything...
Is it possible to save the audio file of the speech in some way?

I have a text and I would like to share (for example whatsapp) the audio generated.

Thanks

bug:

Plugin version:
2.1.0

Platform(s):
iOS

Current behavior:
Error when trying to read text when in background mode

Expected behavior:
Read text

Steps to reproduce:
I'm trying to read a remote notification as soon as received, this works flawlessly in active mode, but when the app is in foreground it rejects the speak method with the message "session activation failed"

BTW category is set to 'playback'

I'm assuming, as the app receives the remote notification, it turns the app into active mode and the notification has a higher AV priority, so the request to setActive fails. With the snippet provided it works as expected, but since I'm not an expert, I would like you to address it (if you can)

Related code:
This is my workaround, added some tweaks...

@objc public func speak(_ text: String, _ lang: String, _ rate: Float, _ pitch: Float, _ category: String, _ volume: Float, _ voice : Int, _ call: CAPPluginCall) throws {
        self.synthesizer.stopSpeaking(at: .immediate)

        var avAudioSessionCategory = AVAudioSession.Category.ambient
        if category != "ambient" {
            avAudioSessionCategory = AVAudioSession.Category.playback
        }
        
        if #available(iOS 13.0, *) {
            self.synthesizer.usesApplicationAudioSession = false
        }

        do {
            try AVAudioSession.sharedInstance().setCategory(avAudioSessionCategory, mode: .default, options: AVAudioSession.CategoryOptions.duckOthers)
            try AVAudioSession.sharedInstance().setActive(true)
        } catch {
            // print(error)
        }

        self.calls.append(call)

        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: lang)
        utterance.rate = adjustRate(rate)
        utterance.pitchMultiplier = pitch
        utterance.volume = volume

        //Find the voice associated with the voice parameter if a voice specified. 
        //If the specified voice is not available we will fall back to default voice rather than raising an error. 
        if (voice >= 0) {
            let allVoices = AVSpeechSynthesisVoice.speechVoices()
            if (voice < allVoices.count) {
                utterance.voice = allVoices[voice]
            }
        }

        synthesizer.speak(utterance)
        try AVAudioSession.sharedInstance().setActive(false)
    }

Other information:

Capacitor doctor:

insert the output from `npx cap doctor` here

Android Error: Unsupported device

Current behavior:

Version:
Capacitor v2
TTS 0.2.3

Device:
Android 11
Android 10
Android 9

Whenever I execute the function:

const speak = async () => {
  await TextToSpeech.speak({
    text: 'This is a sample text.',
    locale: 'en_US',
    speechRate: 1.0,
    pitchRate: 1.0,
    volume: 1.0,
    category: 'ambient',
  });
};

Error output:

06-21 03:57:29.328 E/Capacitor/Console(30873): File: https://portal.prosperus.asia/static/js/29.a169ec33.chunk.js - Line 2 - Msg: Uncaught (in promise) Error: Not supported on this device.

Expected behavior:

TTS should work.

Steps to reproduce:

Capacitor v2
TTS 0.2.3 version.

Other information:

Capacitor doctor:

Latest Dependencies:

  @capacitor/cli: 3.0.1    
  @capacitor/core: 3.0.1   
  @capacitor/android: 3.0.1
  @capacitor/electron: 3.0.1
  @capacitor/ios: 3.0.1

Installed Dependencies:

  @capacitor/cli 2.4.7
  @capacitor/ios 2.4.7
  @capacitor/core 2.4.7
  @capacitor/android 2.4.7
  @capacitor/electron not installed

[success] Android looking great!

bug: Delay before Utterance when calling speak() Method

Plugin version: 2.0.1

Platform(s): Web, Android?, Ios?

Current behavior:
When supplying "lang" and "rate" arguments to the "speak()" Method there is a long delay before the utterance starts. This does not happen, when not suppling "lang" or "rate" arguments.

Expected behavior:
No delay before the utterance when calling "speak()", regardless of arguments given.

Steps to reproduce:

  • Install Plugin
  • Create "TTSOptions" Array with "lang" or "rate" specified
  • Call "speak()" Method with those Options

Related code:

// Type definitions of variables used, values are assigned before initialising the "options" Array.
public playBackSpeed: number;
let filteredText: string;

// Initialise variables...

const options: TTSOptions = {
        text: filteredText,
        lang: 'de-DE',
        rate: this.playBackSpeed,
        pitch: this.pitch,
        volume: 1.0,
        category: 'ambient'
      };
      try {
        await TextToSpeech.speak(options);
        this.speaking = false;
      } catch (e) {}

Other information:

Capacitor doctor:

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 4.7.0
  @capacitor/core: 4.7.0
  @capacitor/android: 4.7.0
  @capacitor/ios: 4.7.0

Installed Dependencies:

  @capacitor/cli: 4.4.0
  @capacitor/core: 4.4.0
  @capacitor/ios: 4.4.0
  @capacitor/android: 4.4.0

[success] iOS looking great! 👌
[success] Android looking great! 👌

bug: different behavior with same speech rate

Describe the bug
Speech rate set to 1.
On Android and web, the speed sounds natural.
On iOS it sounds very fast.

To Reproduce

TextToSpeech.speak({
  text: 'Test',
  speechRate: 1.0
});

Expected behavior
The speed should be the same on all platforms.

typo in readme: lang tag

Caught a minor typo in the usage code block in the readme. Language tag contains an underscore where a hyphen should be.

const speak = async () => {
  await TextToSpeech.speak({
    text: 'This is a sample text.',
    lang: 'en_US', // <- Invalid BCP 47 language tag. Should be 'en-US'.
    rate: 1.0,
    pitch: 1.0,
    volume: 1.0,
    category: 'ambient',
  });
};

feat: use device language as default language

Is your feature request related to a problem? Please describe.
There is currently no way to select the default language of the device.
en-US is used as a fallback when no language is selected.

Describe the solution you'd like
The default language of the device should be used.

Describe alternatives you've considered
Add new methods getDefaultLanguage / getDefaultVoice (not sure if this is supported on all platforms).

bug: `speak` method resolves immediately on iOS

Describe the bug
The speak method resolves immediately on iOS.

To Reproduce

const speak = async () => {
  await TextToSpeech.speak({
    text: 'This is a sample text.',
  });
  console.log('resolved');
};

Expected behavior
The speak method should be resolved as soon as the utterance is spoken.

Additional context
v0.2.3

feat: detect muted devices

Plugin version:
2.1.0

Platform(s):
iOS

Current behavior:
iPhones that are silenced with the physical mute button won't play any voice, no warning shown either

Expected behavior:
iPhones would override the silence option, or there would be an isMuted function that returns whether the phone is muted/not on iOS, so a warning can be shown.

Steps to reproduce:

  1. Put an iPhone in muted mode with the physical button
  2. Call the speak function with anything

bug: [iOS] not working in background

Describe the bug
I switch the app to background, then the tts.speak does not work. I got the following error:

OSStatus error 561015905

021-03-14 00:17:52.947145+0800 App[6317:1761621] [AXTTSCommon] Failure starting audio queue alp!
2021-03-14 00:17:55.033473+0800 App[6317:1761621] [AXTTSCommon] _BeginSpeaking: couldn't begin playback

It seems some other guys is suffering the same problem.

Any ideas?

Smartphone (please complete the following information):

  • Device: iPhone 12 mini
  • OS: iOS 14.4

bug: speak() fails on iOS 16.2 - Unable to list voice folder

Plugin version:
2.1.0

Platform(s):
iOS 16.2 (real device, not simulator)

Current behavior:
Nothing can be heard, device log shows errors (see below) after calling speak()

Expected behavior:
Text will be read. No errors in log.

Steps to reproduce:
See related code.

Related code:

const speak = async () => {
    await TextToSpeech.speak({
        text: "How are you doing today?",
        lang: "en-US",
        rate: 1.0,
        pitch: 1.0,
        volume: 1.0,
        category: "ambient",
    });
};

const supported = await TextToSpeech.getSupportedLanguages();
console.log("SUPPORTED:", supported);

console.warn("SPEAKING NOW!");
await speak();
console.warn("SPEAKING DONE!");

Other information:
Error Log:

⚡️  To Native ->  TextToSpeech getSupportedLanguages 17009103
2023-03-17 08:17:11.496292+0100 App[63424:5046446] [Accessibility] WKContentView[@] set up: @ pid: @ MACH_PORT 1585677312
⚡️  TO JS {"languages":["ar-001","bg-BG","ca-ES","cs-CZ","da-DK","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","el-GR","en-AU","en-AU","en-AU","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","
⚡️  [log] - SUPPORTED: {"languages":["ar-001","bg-BG","ca-ES","cs-CZ","da-DK","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","de-DE","el-GR","en-AU","en-AU","en-AU","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-GB","en-IE","en-IN","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-US","en-ZA","es-ES","es-ES","es-ES","es-ES","es-ES","es-ES","es-ES","es-ES","es-ES","es-MX","es-MX","es-MX","es-MX","es-MX","es-MX","es-MX","es-MX","es-MX","fi-FI","fi-FI","fi-FI","fi-FI","fi-FI","fi-FI","fi-FI","fi-FI","fi-FI","fr-CA","fr-CA","fr-CA","fr-CA","fr-CA","fr-CA","fr-CA","fr-CA","fr-CA","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","fr-FR","he-IL","hi-IN","hr-HR","hu-HU","id-ID","it-IT","it-IT","it-IT","it-IT","it-IT","it-IT","it-IT","it-IT","it-IT","ja-JP","ja-JP","ja-JP","ko-KR","ms-MY","nb-NO","nl-BE","nl-NL","pl-PL","pt-BR","pt-BR","pt-BR","pt-BR","pt-BR","pt-BR","pt-BR","pt-BR","pt-BR","pt-PT","ro-RO","ru-RU","sk-SK","sv-SE","th-TH","tr-TR","uk-UA","vi-VN","zh-CN","zh-CN","zh-CN","zh-HK","zh-TW"]}
⚡️  To Native ->  TextToSpeech speak 17009104
⚡️  [warn] - SPEAKING NOW!
2023-03-17 08:17:11.597112+0100 App[63424:5047103] [catalog] Unable to list voice folder
2023-03-17 08:17:11.619811+0100 App[63424:5047103] [catalog] Unable to list voice folder
2023-03-17 08:17:11.624239+0100 App[63424:5047103] [catalog] Unable to list voice folder
2023-03-17 08:17:11.640725+0100 App[63424:5047103] [catalog] Unable to list voice folder
2023-03-17 08:17:11.687712+0100 App[63424:5047102] [catalog] Query for com.apple.MobileAsset.VoiceServices.VoiceResources failed: 2
2023-03-17 08:17:11.707096+0100 App[63424:5047156] [AXTTSCommon] File file:///System/Library/PreinstalledAssetsV2/RequiredByOs/com_apple_MobileAsset_VoiceServices_VoiceResources/cfaf4a2cf3146016631559ddcc471f5654939e74.asset/AssetData/vocalizer-user-dict.dat contained data that was not null terminated
⚡️  TO JS undefined
⚡️  [warn] - SPEAKING DONE!

Might be related to #84, except getSupportedLanguages() returns a valid array (see log).

Capacitor doctor:

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 4.7.1
  @capacitor/core: 4.7.1
  @capacitor/android: 4.7.1
  @capacitor/ios: 4.7.1

Installed Dependencies:

  @capacitor/android: not installed
  @capacitor/cli: 4.7.0
  @capacitor/core: 4.7.0
  @capacitor/ios: 4.7.0

[success] iOS looking great! 👌

bug: pod failed to validate

Describe the bug

[error] Analyzing dependencies
[!] The `CapacitorCommunityTextToSpeech` pod failed to validate due to 2 errors:
    - ERROR | attributes: Missing required attribute `authors`.
    - ERROR | attributes: Missing required attribute `homepage`.
    - WARN  | github_sources: Github repositories should end in `.git`.

feat (settings): Open Native Settings

Is your feature request related to a problem? Please describe:
It would be great to implement a method to launch system's TTS Settings.

Describe the solution you'd like:
A new method like

@PluginMethod
    public void openTTSSettings(PluginCall call) {
        JSObject ret = new JSObject();
        final PackageManager manager = getContext().getPackageManager();
        Intent launchIntent = new Intent("com.android.settings.TTS_SETTINGS");

        try {
            getActivity().startActivity(launchIntent);
            ret.put("completed", true);
        } catch (Exception ex) {
            launchIntent = manager.getLaunchIntentForPackage(url);
            try {
                getActivity().startActivity(launchIntent);
                ret.put("completed", true);
            } catch (Exception expgk) {
                ret.put("completed", false);
            }
        }
        call.resolve(ret);
    }

bug: Weird voice on andriod

Plugin version:

Latest

Platform(s):

Andriod

Current behavior:

Sounding weird on android, not sounding like human

Expected behavior:

To sound like human

Steps to reproduce:

Related code:

export const readOutLoud = async (message) => {
    
        await TextToSpeech.speak({
          
          text: message,
          lang: 'en-GB',
          rate: 0.5,
          pitch: 9,
          volume: 10,
          category: 'ambient',
        });
      } 
      
  };

Other information:

Capacitor doctor:

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 4.1.0
  @capacitor/core: 4.1.0
  @capacitor/android: 4.1.0
  @capacitor/ios: 4.1.0

Installed Dependencies:

  @capacitor/core: 4.1.0
  @capacitor/android: 4.1.0
  @capacitor/cli: 4.1.0
  @capacitor/ios: 4.1.0

[success] iOS looking great! 👌
[success] Android looking great! 👌

voice property should utilize voiceURI instead of an index

Currently, especially on web, the list of available voices can change while the page is open. Uniquely identifying a specific voice (rather than the current system) avoids the risk of playing the wrong voice due to voices getting added, etc, while the page is open.

Additionally, at least on Android, voices are unordered - so this plugin needs to order the voices in a repeatable manner such that they can be located. I'm not actually sure if voices can change while the app is open, however either way, voiceURI would be less complicated.

Ideal Solution: voice property takes a string representing the voiceURI of the voice (or a separate option for voiceURI)

  • The biggest problem here is that, in order to maintain backwards compatibility, such changes would increase the codebase size overall, which may not be ideal.

feat: add support for `getSupportedVoices` on iOS

Is your feature request related to a problem? Please describe.
getSupportedVoices should also be available on iOS.
Currently an empty array is returned.

Describe the solution you'd like
Add support for getSupportedVoices on iOS.

Describe alternatives you've considered
Mark as unsupported in docs.

bug: different behavior with blank `text`

Describe the bug
There are different behaviors with empty text input.
Android: throws error
iOS: "speaks" empty text
Web: throws error

To Reproduce

TextToSpeech.speak({ text: '' });

Expected behavior
All platforms should behave in the same way.

Choose tts engine option

There is problem with samsung devices when using TextToSpeech.speak()

It's because tts engine on samsung it's "Samsung text-to-speech engine" that support only 7 languages by default. Only user can change preffered tts engine to Google one: Settings => General Managment => Text-to-speech => Preffered engine.
When I tried ja-JP there isn't any voice because it isn't installed by default. It doesn't work in browser too.

Can you add option like "engine" to TextToSpeech.speak()? Or tryInstallLocale() to install locale to samsung's tts engine

Android: 11 (the same situation for 10)
Samsung TTS engine: 3.1.02..1

bug: Unable to install after upgrade to capacitor v4

Platform(s):

"@capacitor/core": "^4.0.1",

Current behavior:

ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: ****
npm ERR! Found: @capacitor/[email protected]
npm ERR! node_modules/@capacitor/core
npm ERR! @capacitor/core@"^4.0.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @capacitor/core@"^3.0.0" from @capacitor-community/[email protected]
npm ERR! node_modules/@capacitor-community/text-to-speech
npm ERR! @capacitor-community/text-to-speech@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!

feat: add support for `voice` property

Is your feature request related to a problem? Please describe.
The voice property of the speak method is currently only supported on the web.

Describe the solution you'd like
Add support for Android and iOS.

bug: window.speechSynthesis not found for Android

For Android

if ('speechSynthesis' in window) { this.speechSynthesis = window.speechSynthesis; }

window.speechSynthesis doesn't exist.

I have this result in the developer console
Uncaught (in promise) Error: Not supported on this device.

Does anyone have the same behavior ?

feat: add `isLanguageSupported` method

Is your feature request related to a problem? Please describe.
Add a method (e.g. isLanguageSupported) that checks if a specific language is supported.

Describe the solution you'd like

isLanguageSupported(options: { lang: string }) => Promise<{ supported: boolean }>

Describe alternatives you've considered
No alternative solutions.

[Android] ERR: Unsupported Locale

Describe the bug
speak() function working fine on Web, but not on Android. Got this error:

Unhandled Promise rejection: Unsupported locale ; Zone: <root> ; Task: null ; Value: Error: Unsupported locale
    at Object.fromNative (capacitor-runtime.js:226)
    at <anonymous>:1:18 Error: Unsupported locale
    at Object.fromNative (capacitor-runtime.js:230:14)
    at <anonymous>:1:18

Tried to use getSupportedVoices() function to see what can be used on my Android phone, I got lots of data. Here are the first few data:

[Voice[Name: es-us-x-sfb-local, locale: es_US, quality: 400, latency: 200, requiresNetwork: false, features: [networkTimeoutMs, notInstalled, networkRetriesCount]], Voice[Name: ur-PK-language, locale: ur_PK, quality: 400, latency: 200, requiresNetwork: false, features: [networkTimeoutMs, notInstalled, legacySetLanguageVoice, networkRetriesCount]], ..........

To Reproduce
Steps to reproduce the behavior:

  const option: SpeakOption = {
     text: "This is a sample text.",
     locale: "en_US",
     speechRate: 1.0,
     pitchRate: 1,
     volume: 1.0,
     voice: 10,
     category: "ambient",
   }
   TextToSpeech.speak(option);

Expected behavior
Voice speaking

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Add web support

Is your feature request related to a problem? Please describe.
Web plugin is not supported at the moment.

Describe the solution you'd like
Implement Speech Synthesis on web. Chrome 33+ (mobile and desktop) now support Speech Synthesis API.

Describe alternatives you've considered
N/A

Additional context
N/A

bug:

Plugin version:

version-->

"@capacitor-community/text-to-speech": "^3.0.0",
"react": "^18.2.0",
"@ionic/react": "^6.0.0",

Platform(s):

crashing on both Android and IOS, using Ionic React

Current behavior:
After installing this plugin and after following all the steps to make it run, finally, when I hit the command to run on Android or Ios, it crashes,

ionic capacitor run android -l --external
? Which device would you like to target? Xiaomi M2101K7AG (c2138604)

capacitor sync android
[capacitor] ✔ Copying web assets from build to android/app/src/main/assets/public in 150.07ms
[capacitor] ✔ Creating capacitor.config.json in android/app/src/main/assets in 2.11ms
[capacitor] ✔ copy android in 189.94ms
[capacitor] ✔ Updating Android plugins in 27.15ms
[capacitor] [info] Found 4 Capacitor plugins for android:
[capacitor] @capacitor-community/[email protected]
[capacitor] @capacitor/[email protected]
[capacitor] @capacitor/[email protected]
[capacitor] @capacitor/[email protected]
[capacitor] ✔ update android in 143.79ms
[capacitor] [info] Sync finished in 0.343s
react-scripts start
[react-scripts] Attempting to bind to HOST environment variable: 0.0.0.0
[react-scripts] If this was unintentional, check that you haven't mistakenly set it in your shell.
[react-scripts] Learn more here: https://cra.link/advanced-config
[react-scripts] (node:2480) [DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE] DeprecationWarning: 'onAfterSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
[react-scripts] (Use node --trace-deprecation ... to show where the warning was created)
[react-scripts] (node:2480) [DEP_WEBPACK_DEV_SERVER_ON_BEFORE_SETUP_MIDDLEWARE] DeprecationWarning: 'onBeforeSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
[react-scripts] Starting the development server...
[react-scripts]
[react-scripts] You can now view photo-gallery-capacitor-react in the browser.
[react-scripts] Local: http://localhost:8100
[react-scripts] On Your Network: http://192.168.1.13:8100
[react-scripts] Note that the development build is not optimized.
[react-scripts] To create a production build, use yarn build.

[INFO] Development server running!

   Local: http://localhost:8100
   External: http://192.168.1.13:8100
   
   Use Ctrl+C to quit this process

[react-scripts] webpack compiled successfully

capacitor run android --no-sync --target c2138604
[react-scripts] Files successfully emitted, waiting for typecheck results...
[react-scripts] Issues checking in progress...
[react-scripts] No issues found.
[capacitor] ✖ Running Gradle build - failed!
[capacitor] [error]
[capacitor] > Configure project :app
[capacitor] google-services.json not found, google-services plugin not applied. Push Notifications won't work
[capacitor] WARNING:Using flatDir should be avoided because it doesn't support any meta-data formats.
[capacitor]
[capacitor] > Configure project :capacitor-cordova-android-plugins
[capacitor] WARNING:Using flatDir should be avoided because it doesn't support any meta-data formats.
[capacitor]
[capacitor] > Task :app:preBuild UP-TO-DATE
[capacitor] > Task :app:preDebugBuild UP-TO-DATE
[capacitor] > Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
[capacitor] > Task :capacitor-android:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-android:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-android:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-camera:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-camera:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-camera:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-community-text-to-speech:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-cordova-android-plugins:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-filesystem:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-preferences:preBuild UP-TO-DATE
[capacitor] > Task :capacitor-preferences:preDebugBuild UP-TO-DATE
[capacitor] > Task :capacitor-preferences:compileDebugAidl NO-SOURCE
[capacitor] > Task :app:compileDebugAidl NO-SOURCE
[capacitor] > Task :capacitor-android:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-camera:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-community-text-to-speech:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-cordova-android-plugins:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-filesystem:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-preferences:packageDebugRenderscript NO-SOURCE
[capacitor] > Task :app:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :app:generateDebugBuildConfig UP-TO-DATE
[capacitor] > Task :app:javaPreCompileDebug UP-TO-DATE
[capacitor] > Task :capacitor-android:writeDebugAarMetadata UP-TO-DATE
[capacitor] > Task :capacitor-camera:writeDebugAarMetadata UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:writeDebugAarMetadata UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:writeDebugAarMetadata UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:writeDebugAarMetadata
[capacitor] > Task :capacitor-preferences:writeDebugAarMetadata UP-TO-DATE
[capacitor] > Task :app:checkDebugAarMetadata UP-TO-DATE
[capacitor] > Task :app:generateDebugResValues UP-TO-DATE
[capacitor] > Task :app:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-android:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-android:generateDebugResValues UP-TO-DATE
[capacitor] > Task :capacitor-android:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-android:packageDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-camera:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-camera:generateDebugResValues UP-TO-DATE
[capacitor] > Task :capacitor-camera:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-camera:packageDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-community-text-to-speech:generateDebugResValues UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:packageDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-cordova-android-plugins:generateDebugResValues
[capacitor] > Task :capacitor-cordova-android-plugins:generateDebugResources
[capacitor] > Task :capacitor-cordova-android-plugins:packageDebugResources
[capacitor] > Task :capacitor-filesystem:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-filesystem:generateDebugResValues UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:packageDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-preferences:compileDebugRenderscript NO-SOURCE
[capacitor] > Task :capacitor-preferences:generateDebugResValues UP-TO-DATE
[capacitor] > Task :capacitor-preferences:generateDebugResources UP-TO-DATE
[capacitor] > Task :capacitor-preferences:packageDebugResources UP-TO-DATE
[capacitor] > Task :app:mergeDebugResources UP-TO-DATE
[capacitor] > Task :app:mapDebugSourceSetPaths UP-TO-DATE
[capacitor] > Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
[capacitor] > Task :app:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-android:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-android:processDebugManifest UP-TO-DATE
[capacitor] > Task :capacitor-camera:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-camera:processDebugManifest UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:processDebugManifest UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:extractDeepLinksDebug
[capacitor] > Task :capacitor-filesystem:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:processDebugManifest UP-TO-DATE
[capacitor] > Task :capacitor-preferences:extractDeepLinksDebug UP-TO-DATE
[capacitor] > Task :capacitor-preferences:processDebugManifest UP-TO-DATE
[capacitor] > Task :capacitor-android:compileDebugLibraryResources UP-TO-DATE
[capacitor] > Task :capacitor-android:parseDebugLocalResources UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:processDebugManifest
[capacitor] > Task :capacitor-android:generateDebugRFile UP-TO-DATE
[capacitor] > Task :capacitor-camera:compileDebugLibraryResources UP-TO-DATE
[capacitor] > Task :capacitor-camera:parseDebugLocalResources UP-TO-DATE
[capacitor] > Task :capacitor-camera:generateDebugRFile UP-TO-DATE
[capacitor] > Task :app:processDebugMainManifest UP-TO-DATE
[capacitor] > Task :app:processDebugManifest UP-TO-DATE
[capacitor] > Task :app:processDebugManifestForPackage UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:compileDebugLibraryResources UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:parseDebugLocalResources UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:generateDebugRFile UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:compileDebugLibraryResources
[capacitor] > Task :capacitor-filesystem:compileDebugLibraryResources UP-TO-DATE
[capacitor] > Task :capacitor-filesystem:parseDebugLocalResources UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:parseDebugLocalResources
[capacitor] > Task :capacitor-filesystem:generateDebugRFile UP-TO-DATE
[capacitor] > Task :capacitor-preferences:compileDebugLibraryResources UP-TO-DATE
[capacitor] > Task :capacitor-preferences:parseDebugLocalResources UP-TO-DATE
[capacitor] > Task :capacitor-preferences:generateDebugRFile UP-TO-DATE
[capacitor] > Task :capacitor-android:generateDebugBuildConfig UP-TO-DATE
[capacitor] > Task :capacitor-android:javaPreCompileDebug UP-TO-DATE
[capacitor] > Task :capacitor-android:compileDebugJavaWithJavac UP-TO-DATE
[capacitor] > Task :capacitor-android:bundleLibCompileToJarDebug UP-TO-DATE
[capacitor] > Task :capacitor-camera:generateDebugBuildConfig UP-TO-DATE
[capacitor] > Task :capacitor-camera:javaPreCompileDebug UP-TO-DATE
[capacitor] > Task :capacitor-cordova-android-plugins:generateDebugRFile
[capacitor] > Task :capacitor-camera:compileDebugJavaWithJavac UP-TO-DATE
[capacitor] > Task :capacitor-camera:bundleLibCompileToJarDebug UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:generateDebugBuildConfig UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:javaPreCompileDebug UP-TO-DATE
[capacitor] > Task :capacitor-community-text-to-speech:compileDebugJavaWithJavac FAILED
[capacitor]
[capacitor] FAILURE: Build failed with an exception.
[capacitor]
[capacitor] * What went wrong:
[capacitor] Execution failed for task ':capacitor-community-text-to-speech:compileDebugJavaWithJavac'.
[capacitor] > error: invalid source release: 17
[capacitor]
[capacitor] * Try:
[capacitor] > Run with --stacktrace option to get the stack trace.
[capacitor] > Run with --info or --debug option to get more log output.
[capacitor] > Run with --scan to get full insights.
[capacitor]
[capacitor] * Get more help at https://help.gradle.org
[capacitor]
[capacitor] BUILD FAILED in 1s
[capacitor] 70 actionable tasks: 9 executed, 61 up-to-date
[capacitor]
[ERROR] An error occurred while running subprocess capacitor.

    capacitor run android --no-sync --target c2138604 exited with exit code
    1.
    
    Re-running this command with the --verbose flag may provide more
    information.

Expected behavior:
As I follow all the required steps, it should run properly and convert text to speech,

NOTE: I have even created a new bare ionic react app as a tabs starter template, also crashing in it.

Steps to reproduce:
Here are the steps to reproduce,
-> Create an ionic react app as a tabs starter template.
-> yarn add @capacitor-community/text-to-speech
-> npx cap sync
-> ionic capacitor copy android
-> ionic capacitor run android -l --external

Other information:
I am using the Ionic react app with capacitor and, I was having issues in my app, then I created a new template and the same issue is reproducing on my end, and one thing more, I install this package with yarn because using npm it is not installed on my end.

Capacitor doctor:

insert the output from `npx cap doctor` here

 npx cap doctor
💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 5.0.4
  @capacitor/core: 5.0.4
  @capacitor/android: 5.0.4
  @capacitor/ios: 5.0.4

Installed Dependencies:

  @capacitor/cli: 4.8.0
  @capacitor/android: 4.8.0
  @capacitor/ios: 4.8.0
  @capacitor/core: 4.8.0

[success] iOS looking great! 👌
[success] Android looking great! 👌

bug: [Android] Error - Unsupported locale on Samsung smartphones

Describe the bug
Hi, got Unsupported locale while using this plugin on Samsung devices. Using getSupportedLanguages() on these devices returns ISO 639‑2 (or -3) standard language code. Screenshot linked below.

Expected behavior
I expect getSupportedLanguages() returns standardize language codes to use in locale property in speak function.

Screenshots
image

Smartphone:

  • Device: [Galaxy A8, Galaxy A41 ]
  • OS: [Android 9 and Android 10]

Additional context
I am using Capacitor 2 and text-to-speech v0.2.3, as in Readme specified.

Workaround
As workaround, i made it work commenting the supportedLocales check here below and hard coding standardize IETF language tag code like "en-US", but it is not a stable workaround obviously:
image

Android voice names should be unique

Voice names on Android are often identical - they merely utilize the display language and display country. There should be some information included that at least makes them unique and distinguishable to users.

bug: `speechRate` and `pitchRate` ignored on Android

Describe the bug
speechRate and pitchRate are ignored on Android.

To Reproduce

TextToSpeech.speak({ 
  text: 'Test',
  speechRate: 2.0,
  pitchRate: 2.0
});

Expected behavior
speechRate and pitchRate should not be ignored.

feat: capacitor 5 support

Is your feature request related to a problem? Please describe:

This plugin does not work with capacitor 5 and is trying to load capacitor ^4.0.0.

Describe the solution you'd like:

I'm assuming it's just a package.json/package-lock.json update? But may require some migration work.

Describe alternatives you've considered:

None at the moment.

Additional context:

feat: speak method should use the internal queue of utterances

Is your feature request related to a problem? Please describe.
Some times we could get a text to speak while the previous one is not finished. Currently, each time we call speak() method will cause the queue is flushed and the previous one is stopped immediately.

Describe the solution you'd like
I propose to use the internal queue of utterances, like it is described in the apple document:

The speech synthesizer maintains a queue of utterances that it speaks. If the synthesizer isn’t currently speaking, calling speak(_:) begins speaking that utterance immediately (or begin waiting through its preUtteranceDelay if set). If the synthesizer is speaking, the synthesizer adds utterances to a queue and speaks them in the order received.

Describe alternatives you've considered
Or we can resolve the speak method only after the text is really spoken but not just after the call in invoked immediately.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.