Reset master to testing content
This commit is contained in:
1 parent
0f2587b719
commit
42afa2a56c
1483 files changed
+145308
-938069
No files matched your search
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package speech
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SpeakAndWait uses SSIP BEGIN/END/CANCEL events, not the SPEAK queue
|
||||
// acknowledgement, to pace continuous reading and report its current position.
|
||||
// Protocol: https://github.com/brailcom/speechd/blob/master/doc/ssip.texi
|
||||
func (client *Client) SpeakAndWait(ctx context.Context, text string, began func()) (result error) {
|
||||
client.mutex.Lock()
|
||||
defer client.mutex.Unlock()
|
||||
if client.conn == nil {
|
||||
return errors.New("speech client is not connected")
|
||||
}
|
||||
if err := client.sendCommand(ctx, []string{"SET", "SELF", "NOTIFICATION", "ALL", "on"}); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if client.conn != nil {
|
||||
cleanup, cancel := context.WithTimeout(context.Background(), client.ioTimeout)
|
||||
defer cancel()
|
||||
if err := client.sendCommand(cleanup, []string{"SET", "SELF", "NOTIFICATION", "ALL", "off"}); err != nil {
|
||||
result = errors.Join(result, err)
|
||||
_ = client.conn.Close()
|
||||
client.conn, client.reader = nil, nil
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err := client.speak(ctx, text); err != nil {
|
||||
return err
|
||||
}
|
||||
conn := client.conn
|
||||
// A spoken line may take much longer than the command I/O timeout.
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
return err
|
||||
}
|
||||
done := make(chan struct{})
|
||||
stop := context.AfterFunc(ctx, func() {
|
||||
defer close(done)
|
||||
cleanup, cancel := context.WithTimeout(context.Background(), client.ioTimeout)
|
||||
defer cancel()
|
||||
_ = client.Cancel(cleanup)
|
||||
// Allow the final cancellation notification to be drained, preserving
|
||||
// the speaking connection for subsequent focus announcements.
|
||||
_ = conn.SetReadDeadline(time.Now().Add(client.ioTimeout))
|
||||
})
|
||||
defer func() {
|
||||
if !stop() {
|
||||
<-done
|
||||
}
|
||||
}()
|
||||
started := false
|
||||
for {
|
||||
event, err := readReply(client.reader)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
client.conn, client.reader = nil, nil
|
||||
return errors.Join(ctx.Err(), err)
|
||||
}
|
||||
switch event.code {
|
||||
case 701:
|
||||
if !started && ctx.Err() == nil && began != nil {
|
||||
began()
|
||||
}
|
||||
started = true
|
||||
case 702:
|
||||
return ctx.Err()
|
||||
case 703:
|
||||
return context.Canceled
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user