Attempt to make audio and speech discovery more robust.
This commit is contained in:
1 parent
a27f274099
commit
dc945ff392
21 files changed
+1314
-60
No files matched your search
+56
-13
@@ -43,8 +43,20 @@ type Rejection struct{ Code string }
|
||||
func (r *Rejection) Error() string { return "Speech Dispatcher rejected a command: " + r.Code }
|
||||
|
||||
type wire struct {
|
||||
conn net.Conn
|
||||
reader *bufio.Reader
|
||||
conn net.Conn
|
||||
reader *bufio.Reader
|
||||
stopContext func() bool
|
||||
}
|
||||
|
||||
func (w *wire) detach_context() {
|
||||
if w.stopContext != nil {
|
||||
w.stopContext()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *wire) close() {
|
||||
w.detach_context()
|
||||
_ = w.conn.Close()
|
||||
}
|
||||
|
||||
func (w *wire) reply() ([]string, error) {
|
||||
@@ -102,11 +114,14 @@ func connect_options(options Options) (*wire, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return connect_endpoint(endpoint, options.autospawn, automatic_server_address(options.Socket))
|
||||
return connect_endpoint(options.context, endpoint, options.autospawn, automatic_server_address(options.Socket))
|
||||
}
|
||||
|
||||
func connect_endpoint(endpoint serverAddress, autospawn, systemFallback bool) (*wire, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*commandTimeout)
|
||||
func connect_endpoint(parent context.Context, endpoint serverAddress, autospawn, systemFallback bool) (*wire, error) {
|
||||
if parent == nil {
|
||||
parent = context.Background()
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(parent, 3*commandTimeout)
|
||||
defer cancel()
|
||||
dialer := &net.Dialer{Timeout: commandTimeout}
|
||||
dial := serverDialer(dialer.DialContext)
|
||||
@@ -123,7 +138,7 @@ func connect_endpoint(endpoint serverAddress, autospawn, systemFallback bool) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &wire{conn: conn, reader: bufio.NewReaderSize(conn, 4096)}, nil
|
||||
return &wire{conn: conn, reader: bufio.NewReaderSize(conn, 4096), stopContext: context.AfterFunc(parent, func() { _ = conn.Close() })}, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@@ -132,11 +147,13 @@ type Client struct {
|
||||
sendMu sync.Mutex
|
||||
controlMu sync.Mutex
|
||||
closeOnce sync.Once
|
||||
options Options
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
// Only Prepare enables startup during its prerequisite selection queries.
|
||||
autospawn bool
|
||||
context context.Context
|
||||
Socket string
|
||||
Rate int
|
||||
Pitch *int
|
||||
@@ -174,15 +191,15 @@ func Open(options Options) (*Client, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := connect_endpoint(endpoint, true, automatic_server_address(options.Socket))
|
||||
data, err := connect_endpoint(options.context, endpoint, true, automatic_server_address(options.Socket))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connect Speech Dispatcher at %s: %w", endpoint.address, err)
|
||||
}
|
||||
client := &Client{data: data}
|
||||
client := &Client{data: data, options: options}
|
||||
fail := func(err error) (*Client, error) {
|
||||
data.conn.Close()
|
||||
data.close()
|
||||
if client.control != nil {
|
||||
client.control.conn.Close()
|
||||
client.control.close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -229,13 +246,31 @@ func Open(options Options) (*Client, error) {
|
||||
if endpoint.network == "unix" {
|
||||
endpoint.address = data.conn.RemoteAddr().String()
|
||||
}
|
||||
client.control, err = connect_endpoint(endpoint, false, false)
|
||||
client.control, err = connect_endpoint(options.context, endpoint, false, false)
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
if _, err := client.control.command(`SET SELF CLIENT_NAME "fenrir:fenrir:control"`); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
data.detach_context()
|
||||
client.control.detach_context()
|
||||
if options.context != nil && options.context.Err() != nil {
|
||||
client.abort()
|
||||
return nil, options.context.Err()
|
||||
}
|
||||
client.options.context = nil
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Reopen reconnects only the selected server and synthesis options.
|
||||
func (c *Client) Reopen(ctx context.Context) (Transport, error) {
|
||||
options := c.options
|
||||
options.context = ctx
|
||||
client, err := Open(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -315,8 +350,16 @@ func (c *Client) Cancel() error {
|
||||
func (c *Client) Close() {
|
||||
c.closeOnce.Do(func() {
|
||||
// Closing the data socket releases a blocked sender before cancellation.
|
||||
c.data.conn.Close()
|
||||
c.data.close()
|
||||
c.Cancel()
|
||||
c.control.conn.Close()
|
||||
c.control.close()
|
||||
})
|
||||
}
|
||||
|
||||
// abort releases blocked initialization commands without another SSIP request.
|
||||
func (c *Client) abort() {
|
||||
_ = c.data.conn.Close()
|
||||
if c.control != nil {
|
||||
_ = c.control.conn.Close()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user