Skip to content

Commit b38b205

Browse files
committed
feat(ios): allow to customize audio session (for background playback)
1 parent 5e310fe commit b38b205

File tree

3 files changed

+57
-22
lines changed

3 files changed

+57
-22
lines changed

src/index.d.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,32 @@ export interface SpeakOptions {
3737
locale?: string;
3838
language?: string;
3939
finishedCallback?: Function;
40+
41+
/**
42+
* Callback to execute when info is emitted from the player.
43+
* @returns {Object} An object containing the native values for the info callback.
44+
*/
45+
infoCallback?: Function;
46+
47+
/**
48+
* iOS: The category for playing recorded music or other sounds that are central to the successful use of your app.
49+
* https://developer.apple.com/documentation/avfaudio/avaudiosessioncategory?language=objc
50+
*/
51+
sessionCategory?: string;
52+
53+
/**
54+
* iOS: Audio session mode identifiers.
55+
* https://developer.apple.com/documentation/avfaudio/avaudiosessionmode
56+
*/
57+
sessionMode?: string;
58+
59+
/**
60+
* iOS: Cases that indicate the possible route-sharing policies for an audio session.
61+
* https://developer.apple.com/documentation/avfaudio/avaudiosessionroutesharingpolicy
62+
*/
63+
sessionRouteSharingPolicy?: AVAudioSessionRouteSharingPolicy;
64+
65+
audioMixing?: boolean;
4066
}
4167

4268
export interface Language {

src/texttospeech.android.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,11 @@ export class TNSTextToSpeech {
103103
}
104104

105105
private speakText(options: SpeakOptions) {
106-
if (this.isString(options.locale) && this.isValidLocale(options.locale)) {
107-
const localeArray = options.locale.split('-');
108-
const locale = new java.util.Locale(localeArray[0], localeArray[1]);
106+
const localeStr = options.locale || options.language;
107+
if (localeStr) {
108+
const localeArray = localeStr.split('-');
109+
const locale = new java.util.Locale(localeArray[0], localeArray[1] || localeStr.toUpperCase());
109110
this._tts.setLanguage(locale);
110-
} else if (this.isString(options.language)) {
111-
let locale = null;
112-
if (this.isValidLocale(options.language)) {
113-
// only for backwards compatbility with old API
114-
const languageArray = options.language.split('-');
115-
locale = new java.util.Locale(languageArray[0], languageArray[1]);
116-
} else {
117-
locale = new java.util.Locale(options.language);
118-
}
119-
if (locale) {
120-
this._tts.setLanguage(locale);
121-
}
122111
}
123112

124113
if (!this.isBoolean(options.queue)) {

src/texttospeech.ios.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,26 @@ export class TNSTextToSpeech {
5959

6060
this._lastOptions = options;
6161

62-
this.delegate.doneCallback = options.finishedCallback;
62+
const needsAudioSession = options.sessionCategory || options.sessionMode || options.sessionRouteSharingPolicy || options.audioMixing;
63+
const audioSession = AVAudioSession.sharedInstance();
64+
65+
if (needsAudioSession) {
66+
audioSession.setCategoryModeRouteSharingPolicyOptionsError(
67+
options.sessionCategory || AVAudioSessionCategoryAmbient,
68+
options.sessionMode || AVAudioSessionModeDefault,
69+
options.sessionRouteSharingPolicy || AVAudioSessionRouteSharingPolicy.LongForm,
70+
options.audioMixing ? AVAudioSessionCategoryOptions.MixWithOthers : AVAudioSessionCategoryOptions.DuckOthers,
71+
//@ts-ignore
72+
null
73+
);
74+
audioSession.setActiveError(true);
75+
}
76+
this.delegate.doneCallback = () => {
77+
if (needsAudioSession) {
78+
audioSession.setActiveError(false);
79+
}
80+
options?.finishedCallback?.();
81+
};
6382

6483
// valid values for pitch are 0.5 to 2.0
6584
if (!isNumber(options.pitch)) {
@@ -72,7 +91,7 @@ export class TNSTextToSpeech {
7291

7392
// valid values are AVSpeechUtteranceMinimumSpeechRate to AVSpeechUtteranceMaximumSpeechRate
7493
if (!isNumber(options.speakRate)) {
75-
options.speakRate = AVSpeechUtteranceMaximumSpeechRate / 4.0; // default rate is way too fast
94+
options.speakRate = AVSpeechUtteranceMaximumSpeechRate / 2.5; // default rate is way too fast
7695
} else if (options.speakRate < AVSpeechUtteranceMinimumSpeechRate) {
7796
options.speakRate = AVSpeechUtteranceMinimumSpeechRate;
7897
} else if (options.speakRate > AVSpeechUtteranceMaximumSpeechRate) {
@@ -88,12 +107,13 @@ export class TNSTextToSpeech {
88107

89108
const speechUtterance = AVSpeechUtterance.alloc().initWithString(options.text);
90109

91-
if (isString(options.locale) && this.isValidLocale(options.locale)) {
92-
speechUtterance.voice = AVSpeechSynthesisVoice.voiceWithLanguage(options.locale);
93-
} else if (isString(options.language) && this.isValidLocale(options.language)) {
94-
speechUtterance.voice = AVSpeechSynthesisVoice.voiceWithLanguage(options.language);
110+
let localeStr = options.locale || options.language;
111+
if (localeStr) {
112+
if (localeStr.indexOf('-') === -1) {
113+
localeStr = localeStr + '-' + localeStr.toUpperCase();
114+
}
115+
speechUtterance.voice = AVSpeechSynthesisVoice.voiceWithLanguage(localeStr);
95116
}
96-
97117
speechUtterance.pitchMultiplier = options.pitch;
98118
speechUtterance.volume = options.volume;
99119
speechUtterance.rate = options.speakRate;

0 commit comments

Comments
 (0)