mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
98_Text2Speech: new server mode to serve audiofile for requestors
git-svn-id: https://svn.fhem.de/fhem/trunk@13633 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
2f9adecd2d
commit
b070c83a17
@ -1,5 +1,6 @@
|
||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||
# Do not insert empty lines here, update check depends on it.
|
||||
- feature: 98_Text2Speech: new server mode to serve audiofile for requestors
|
||||
- feature: at+notify: extend the FHEMWEB Wizard with a simple command modifier
|
||||
- feature: 42_SYSMON: support ssh login with public key
|
||||
- bugfix: 10_EQ3BT: fix lastChangeBy reading
|
||||
|
@ -5,7 +5,7 @@
|
||||
# 98_Text2Speech.pm
|
||||
#
|
||||
# written by Tobias Faust 2013-10-23
|
||||
# e-mail: tobias dot faust at online dot de
|
||||
# e-mail: tobias dot faust at gmx dot net
|
||||
#
|
||||
##############################################
|
||||
|
||||
@ -163,6 +163,7 @@ sub Text2Speech_Initialize($)
|
||||
" TTS_VolumeAdjust".
|
||||
" TTS_noStatisticsLog:1,0".
|
||||
" TTS_Language:".join(",", sort keys %{$language{"Google"}}).
|
||||
" TTS_SpeakAsFastAsPossible:1,0".
|
||||
" ".$readingFnAttributes;
|
||||
}
|
||||
|
||||
@ -204,6 +205,10 @@ sub Text2Speech_Define($$)
|
||||
$hash->{portpassword} = $a[3] if(@a == 4);
|
||||
|
||||
$hash->{MODE} = "REMOTE";
|
||||
} elsif (lc($dev) eq "none") {
|
||||
# Ein DummyDevice, Serverdevice. Nur Generierung der mp3 TTS Dateien
|
||||
$hash->{MODE} = "SERVER";
|
||||
undef $hash->{ALSADEVICE};
|
||||
} else {
|
||||
# Ein Alsadevice ist angegeben
|
||||
# pruefen, ob Alsa-Device in /etc/asound.conf definiert ist
|
||||
@ -254,21 +259,24 @@ sub Text2Speech_Attr(@) {
|
||||
return "wrong delemiter syntax: [+-]a[lfn]. \n".
|
||||
" Example 1: +an~\n".
|
||||
" Example 2: +al." if($value !~ m/^([+-]a[lfn]){0,1}(.){1}$/i);
|
||||
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
|
||||
} elsif ($a[2] eq "TTS_Ressource") {
|
||||
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
|
||||
} elsif ($a[2] eq "TTS_CacheFileDir") {
|
||||
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
|
||||
} elsif ($a[2] eq "TTS_SpeakAsFastAsPossible") {
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
|
||||
} elsif ($a[2] eq "TTS_UseMP3Wrap") {
|
||||
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
return "Attribute TTS_UseMP3Wrap is required by Attribute TTS_SentenceAppendix! Please delete it first."
|
||||
if(($a[0] eq "del") && (AttrVal($hash->{NAME}, "TTS_SentenceAppendix", undef)));
|
||||
|
||||
} elsif ($a[2] eq "TTS_SentenceAppendix") {
|
||||
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
|
||||
return "This Attribute is only available in direct or server mode" if($hash->{MODE} !~ m/(DIRECT|SERVER)/ );
|
||||
return "Attribute TTS_UseMP3Wrap is required!" unless(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", undef));
|
||||
|
||||
my $file = $TTS_CacheFileDir ."/". $value;
|
||||
@ -444,10 +452,11 @@ sub Text2Speech_Set($@)
|
||||
}
|
||||
|
||||
# Abbruch falls Disabled
|
||||
return undef if(AttrVal($hash->{NAME}, "disable", "0") eq "1");
|
||||
return "no set cmd on a disabled device !" if(IsDisabled($me));
|
||||
|
||||
if($cmd eq "tts") {
|
||||
|
||||
if($hash->{MODE} eq "DIRECT") {
|
||||
if($hash->{MODE} eq "DIRECT" || $hash->{MODE} eq "SERVER") {
|
||||
readingsSingleUpdate($hash, "playing", "1", 1);
|
||||
Text2Speech_PrepareSpeech($hash, join(" ", @a));
|
||||
$hash->{helper}{RUNNING_PID} = BlockingCall("Text2Speech_DoIt", $hash, "Text2Speech_Done", $TTS_TimeOut, "Text2Speech_AbortFn", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
|
||||
@ -789,40 +798,70 @@ sub Text2Speech_DoIt($) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
if(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0)) {
|
||||
# benutze das Tool MP3Wrap um bereits einzelne vorhandene Sprachdateien
|
||||
# zusammenzuführen. Ziel: sauberer Sprachfluss
|
||||
my @Mp3WrapFiles;
|
||||
my @Mp3WrapText;
|
||||
|
||||
$TTS_SentenceAppendix = $myFileTemplateDir ."/". $TTS_SentenceAppendix if($TTS_SentenceAppendix);
|
||||
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_SentenceAppendix));
|
||||
my @Mp3WrapFiles;
|
||||
my @Mp3WrapText;
|
||||
|
||||
$TTS_SentenceAppendix = $myFileTemplateDir ."/". $TTS_SentenceAppendix if($TTS_SentenceAppendix);
|
||||
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_SentenceAppendix));
|
||||
|
||||
#Abspielliste erstellen
|
||||
foreach my $t (@{$hash->{helper}{Text2Speech}}) {
|
||||
if(-e $TTS_CacheFileDir."/".$t) { $filename = $t;} else {$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $t) . ".mp3";} # falls eine bestimmte mp3-Datei gespielt werden soll
|
||||
#Abspielliste erstellen
|
||||
foreach my $t (@{$hash->{helper}{Text2Speech}}) {
|
||||
if(-e $t) {
|
||||
# falls eine bestimmte mp3-Datei mit absolutem Pfad gespielt werden soll
|
||||
$filename = $t;
|
||||
$file = $filename;
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||
} elsif(-e $TTS_CacheFileDir."/".$t) {
|
||||
# falls eine bestimmte mp3-Datei mit relativem Pfad gespielt werden soll
|
||||
$filename = $t;
|
||||
$file = $TTS_CacheFileDir."/".$filename;
|
||||
if(-e $file) {
|
||||
push(@Mp3WrapFiles, $file);
|
||||
push(@Mp3WrapText, $t);
|
||||
} else {last;}
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||
} else {
|
||||
$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $t) . ".mp3";
|
||||
$file = $TTS_CacheFileDir."/".$filename;
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Textbaustein ist keine direkte MP3 Datei, ermittle MD5 CacheNamen: $filename";
|
||||
}
|
||||
|
||||
if(-e $file) {
|
||||
push(@Mp3WrapFiles, $file);
|
||||
push(@Mp3WrapText, $t);
|
||||
} else {
|
||||
# es befindet sich noch Text zum Download in der Queue
|
||||
if (AttrVal($hash->{NAME}, "TTS_SpeakAsFastAsPossible", 0) == 0) {
|
||||
Text2Speech_Download($hash, $file, $t);
|
||||
if(-e $file) {
|
||||
push(@Mp3WrapFiles, $file);
|
||||
push(@Mp3WrapText, $t);
|
||||
}
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
push(@Mp3WrapFiles, $TTS_SentenceAppendix) if($TTS_SentenceAppendix);
|
||||
last if (AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0) == 0);
|
||||
# ohne mp3wrap darf nur ein Textbaustein verarbeitet werden
|
||||
}
|
||||
|
||||
if(scalar(@Mp3WrapFiles) >= 2) {
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". join(" ", @Mp3WrapText);
|
||||
push(@Mp3WrapFiles, $TTS_SentenceAppendix) if($TTS_SentenceAppendix);
|
||||
|
||||
if(scalar(@Mp3WrapFiles) >= 2 && AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0) == 1) {
|
||||
# benutze das Tool MP3Wrap um bereits einzelne vorhandene Sprachdateien
|
||||
# zusammenzuführen. Ziel: sauberer Sprachfluss
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". join(" ", @Mp3WrapText);
|
||||
|
||||
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapFiles));
|
||||
my $Mp3WrapFile = $TTS_CacheFileDir ."/". $Mp3WrapPrefix . "_MP3WRAP.mp3";
|
||||
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapFiles));
|
||||
my $Mp3WrapFile = $TTS_CacheFileDir ."/". $Mp3WrapPrefix . "_MP3WRAP.mp3";
|
||||
|
||||
if(! -e $Mp3WrapFile) {
|
||||
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapFiles);
|
||||
$cmd .= " >/dev/null" if($verbose < 5);
|
||||
if(! -e $Mp3WrapFile) {
|
||||
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapFiles);
|
||||
$cmd .= " >/dev/null" if($verbose < 5);
|
||||
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: " .$cmd;
|
||||
system($cmd);
|
||||
}
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: " .$cmd;
|
||||
system($cmd);
|
||||
}
|
||||
|
||||
if ($hash->{MODE} ne "SERVER") {
|
||||
# im Falls Server, nicht die Datei abspielen
|
||||
if(-e $Mp3WrapFile) {
|
||||
$cmd = Text2Speech_BuildMplayerCmdString($hash, $Mp3WrapFile);
|
||||
$cmd .= " >/dev/null" if($verbose < 5);
|
||||
@ -832,30 +871,15 @@ sub Text2Speech_DoIt($) {
|
||||
} else {
|
||||
Log3 $hash->{NAME}, 2, "Text2Speech: Mp3Wrap Datei konnte nicht angelegt werden.";
|
||||
}
|
||||
|
||||
return $hash->{NAME} ."|".
|
||||
($TTS_SentenceAppendix ? scalar(@Mp3WrapFiles)-1: scalar(@Mp3WrapFiles)) ."|".
|
||||
$Mp3WrapFile;
|
||||
}
|
||||
|
||||
return $hash->{NAME} ."|".
|
||||
($TTS_SentenceAppendix ? scalar(@Mp3WrapFiles)-1: scalar(@Mp3WrapFiles)) ."|".
|
||||
$Mp3WrapFile;
|
||||
}
|
||||
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite jetzt den Text: ". $hash->{helper}{Text2Speech}[0];
|
||||
|
||||
if(-e $hash->{helper}{Text2Speech}[0]) {
|
||||
# falls eine bestimmte mp3-Datei mit absolutem Pfad gespielt werden soll
|
||||
$filename = $hash->{helper}{Text2Speech}[0];
|
||||
$file = $filename;
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||
} elsif(-e $TTS_CacheFileDir."/".$hash->{helper}{Text2Speech}[0]) {
|
||||
# falls eine bestimmte mp3-Datei mit relativem Pfad gespielt werden soll
|
||||
$filename = $hash->{helper}{Text2Speech}[0];
|
||||
$file = $TTS_CacheFileDir."/".$filename;
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: $filename als direkte MP3 Datei erkannt!";
|
||||
} else {
|
||||
$filename = md5_hex($language{$TTS_Ressource}{$TTS_Language} ."|". $hash->{helper}{Text2Speech}[0]) . ".mp3";
|
||||
$file = $TTS_CacheFileDir."/".$filename;
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Textbaustein ist keine direkte MP3 Datei, ermittle MD5 CacheNamen: $filename";
|
||||
}
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite jetzt den Text: ". $hash->{helper}{Text2Speech}[0];
|
||||
|
||||
if(! -e $file) { # Datei existiert noch nicht im Cache
|
||||
Text2Speech_Download($hash, $file, $hash->{helper}{Text2Speech}[0]);
|
||||
@ -863,7 +887,9 @@ sub Text2Speech_DoIt($) {
|
||||
Log3 $hash->{NAME}, 4, "Text2Speech: $file gefunden, kein Download";
|
||||
}
|
||||
|
||||
if(-e $file) { # Datei existiert jetzt
|
||||
if(-e $file && $hash->{MODE} ne "SERVER") {
|
||||
# Datei existiert jetzt
|
||||
# im Falls Server, nicht die Datei abspielen
|
||||
$cmd = Text2Speech_BuildMplayerCmdString($hash, $file);
|
||||
$cmd .= " >/dev/null" if($verbose < 5);
|
||||
|
||||
@ -899,6 +925,8 @@ sub Text2Speech_Done($) {
|
||||
push(@text, $hash->{helper}{Text2Speech}[$i]);
|
||||
}
|
||||
Text2Speech_WriteStats($hash, 1, $filename, join(" ", @text)) if (AttrVal($hash->{NAME},"TTS_noStatisticsLog", "0")==0);
|
||||
|
||||
readingsSingleUpdate($hash, "lastFilename", $filename, 1);
|
||||
}
|
||||
|
||||
delete($hash->{helper}{RUNNING_PID});
|
||||
@ -1024,6 +1052,14 @@ sub Text2Speech_WriteStats($$$$){
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Server Device</b>
|
||||
<ul>
|
||||
In case of an usage of an Server, only the mp3 file will be generated.It makes no sence to use the attribute <i>TTS_speakAsFastAsPossible</i>.
|
||||
Its recommend, to use the attribute <i>TTS_useMP3Wrap</i>. Otherwise only the last audiobrick will be shown is reading <i>lastFilename</i>.
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
@ -1143,6 +1179,13 @@ sub Text2Speech_WriteStats($$$$){
|
||||
please take care to cleanup your cachedirectory by yourself.
|
||||
</li>
|
||||
|
||||
<li>TTS_speakAsFastAsPossible<br>
|
||||
Trying to get an speach as fast as possible. In case of not present audiobricks, you can hear a short break.
|
||||
The audiobrick will be download at this time. In case of an presentation of all audiobricks at local cache,
|
||||
this attribute has no impact.<br>
|
||||
Attribute only valid in case of an local or server instance.
|
||||
</li>
|
||||
|
||||
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
|
||||
|
||||
<li><a href="#disable">disable</a><br>
|
||||
@ -1179,9 +1222,10 @@ sub Text2Speech_WriteStats($$$$){
|
||||
<ul>
|
||||
<b>Local : </b><code>define <name> Text2Speech <alsadevice></code><br>
|
||||
<b>Remote: </b><code>define <name> Text2Speech <host>[:<portnr>][:SSL] [portpassword]</code>
|
||||
<b>Server : </b><code>define <name> Text2Speech none</code><br>
|
||||
<p>
|
||||
Das Modul wandelt Text mittels verschiedener Provider/Ressourcen in Sprache um. Dabei kann das Device als
|
||||
Remote oder Lokales Device konfiguriert werden.
|
||||
Remote, Lokales Device oder als Server konfiguriert werden.
|
||||
</p>
|
||||
|
||||
<li>
|
||||
@ -1226,6 +1270,15 @@ sub Text2Speech_WriteStats($$$$){
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Server Device</b>
|
||||
<ul>
|
||||
Im Falle der Verwendung als Server, wird nur die MP3 Datei erstellt und als Reading lastFilename dargestellt. Es macht keinen Sinn
|
||||
hier das Attribut <i>TTS_speakAsFastAsPossible</i> zu verwenden. Die Verwendung des Attributes <i>TTS_useMP3Wrap</i> wird dringend empfohlen.
|
||||
Ansonsten wird hier nur der letzte Teiltext als mp3 Datei im Reading dargestellt.
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
@ -1256,7 +1309,7 @@ sub Text2Speech_WriteStats($$$$){
|
||||
Hintergrund ist die Tatsache, das die Google Sprachengine nur 100Zeichen zulässt.<br>
|
||||
Im Standard wird nach jedem Satzende geteilt. Ist ein einzelner Satz länger als 100 Zeichen,
|
||||
so wird zusätzlich nach Kommata, Semikolon und dem Verbindungswort <i>und</i> geteilt.<br>
|
||||
Achtung: Nur bei einem lokal definierter Text2Speech Instanz möglich und nur Nutzung der Google Sprachengine relevant!
|
||||
Achtung: Nur bei einem lokal definierter Text2Speech Instanz möglich und nur bei Nutzung der Google Sprachengine relevant!
|
||||
</li>
|
||||
|
||||
<li>TTS_Ressource<br>
|
||||
@ -1356,6 +1409,13 @@ sub Text2Speech_WriteStats($$$$){
|
||||
Wenn dieses hier dektiviert wird muss sich der User selbst darum kuemmern.
|
||||
</li>
|
||||
|
||||
<li>TTS_speakAsFastAsPossible<br>
|
||||
Es wird versucht, so schnell als möglich eine Sprachausgabe zu erzielen. Bei Sprachbausteinen die nicht bereits lokal vorliegen,
|
||||
ist eine kurze Pause wahrnehmbar. Dann wird der benötigte Sprachbaustein nachgeladen. Liegen alle Sprachbausteine im Cache vor,
|
||||
so hat dieses Attribut keine Auswirkung.<br>
|
||||
Attribut nur verfügbar bei einer lokalen oder Server Instanz
|
||||
</li>
|
||||
|
||||
<li><a href="#readingFnAttributes">readingFnAttributes</a>
|
||||
</li><br>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user