Skip to content

Commit a8f01a1

Browse files
authored
Merge branch 'main' into dev/errors
2 parents 4325d60 + 323b102 commit a8f01a1

12 files changed

Lines changed: 290 additions & 271 deletions

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<name>DashScope Java SDK</name>
4141
<groupId>com.alibaba</groupId>
4242
<artifactId>dashscope-sdk-java</artifactId>
43-
<version>2.22.25</version>
43+
<version>2.22.28</version>
4444

4545
<properties>
4646
<maven.compiler.source>8</maven.compiler.source>

src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeCallback.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,13 @@ public void onOpen() {}
1717

1818
/** Will be called when the connection is closed. */
1919
public abstract void onClose(int code, String reason);
20+
21+
/**
22+
* Will be called when the websocket connection fails, e.g. network disconnected, connect timeout,
23+
* or other io exceptions. Default implementation does nothing, override it to be notified of such
24+
* errors.
25+
*
26+
* @param throwable the exception that caused the failure.
27+
*/
28+
public void onError(Throwable throwable) {}
2029
}

src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeConversation.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,10 @@ private void sendMessage(ByteString message) {
379379
@Override
380380
public void onOpen(WebSocket webSocket, Response response) {
381381
isOpen.set(true);
382-
connectLatch.get().countDown();
382+
CountDownLatch latch = connectLatch.get();
383+
if (latch != null && latch.getCount() > 0) {
384+
latch.countDown();
385+
}
383386
log.debug("WebSocket opened");
384387
callback.onOpen();
385388
}
@@ -439,15 +442,28 @@ public void onMessage(WebSocket webSocket, String text) {
439442
@Override
440443
public void onClosed(WebSocket webSocket, int code, String reason) {
441444
isOpen.set(false);
442-
connectLatch.get().countDown();
445+
CountDownLatch latch = connectLatch.get();
446+
if (latch != null && latch.getCount() > 0) {
447+
latch.countDown();
448+
}
443449
log.debug("WebSocket closed: " + code + ", " + reason);
444450
callback.onClose(code, reason);
445451
}
446452

447453
@Override
448454
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
449-
connectLatch.get().countDown();
450-
log.error("WebSocket failed: " + t.getMessage());
455+
isOpen.set(false);
456+
isClosed.set(true);
457+
CountDownLatch cLatch = connectLatch.get();
458+
if (cLatch != null) {
459+
cLatch.countDown();
460+
}
461+
CountDownLatch dLatch = disconnectLatch.get();
462+
if (dLatch != null) {
463+
dLatch.countDown();
464+
}
465+
log.error("WebSocket failed: " + t.getMessage(), t);
466+
callback.onError(t);
451467
}
452468

453469
@Override

src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String>
239239
return duplexApi
240240
.duplexCall(
241241
StreamInputTtsParamWithStream.fromStreamInputTtsParam(
242-
this.parameters, inputStream, preRequestId, false))
242+
this.parameters, inputStream, preRequestId, false, this.canceled))
243243
.filter(item -> item.getEvent() != WebSocketEventType.TASK_STARTED.getValue())
244244
.map(SpeechSynthesisResult::fromDashScopeResult)
245245
.filter(item -> !canceled.get())
@@ -292,7 +292,8 @@ public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
292292
},
293293
BackpressureStrategy.BUFFER),
294294
preRequestId,
295-
true))
295+
true,
296+
this.canceled))
296297
.filter(item -> item.getEvent() != WebSocketEventType.TASK_STARTED.getValue())
297298
.map(SpeechSynthesisResult::fromDashScopeResult)
298299
.doOnNext(
@@ -368,7 +369,7 @@ private void startStream(boolean enableSsml) {
368369
try {
369370
duplexApi.duplexCall(
370371
SpeechSynthesizer.StreamInputTtsParamWithStream.fromStreamInputTtsParam(
371-
this.parameters, textFrames, preRequestId, enableSsml),
372+
this.parameters, textFrames, preRequestId, enableSsml, this.canceled),
372373
new ResultCallback<DashScopeResult>() {
373374
// private Sentence lastSentence = null;
374375

@@ -441,9 +442,6 @@ public void onEvent(DashScopeResult message) {
441442
@Override
442443
public void onComplete() {
443444
log.debug("[TtsV2] onComplete");
444-
if (canceled.get()) {
445-
return;
446-
}
447445
synchronized (SpeechSynthesizer.this) {
448446
state = SpeechSynthesisState.IDLE;
449447
}
@@ -802,11 +800,19 @@ private static class StreamInputTtsParamWithStream extends SpeechSynthesisParam
802800

803801
@NonNull private Flowable<TextStreamItem> textStream;
804802

803+
/**
804+
* Shared reference to the outer {@link SpeechSynthesizer}'s canceled flag. When set to true
805+
* before the finish-task message is sent, the finish-task message will carry
806+
* payload.input.directive="cancel" to notify the server to discard remaining audio.
807+
*/
808+
private AtomicBoolean canceled;
809+
805810
public static StreamInputTtsParamWithStream fromStreamInputTtsParam(
806811
SpeechSynthesisParam param,
807812
Flowable<TextStreamItem> textStream,
808813
String preRequestId,
809-
boolean enableSsml) {
814+
boolean enableSsml,
815+
AtomicBoolean canceled) {
810816
return StreamInputTtsParamWithStream.builder()
811817
.headers(param.getHeaders())
812818
.parameters(param.getParameters())
@@ -817,9 +823,15 @@ public static StreamInputTtsParamWithStream fromStreamInputTtsParam(
817823
.model(param.getModel())
818824
.voice(param.getVoice())
819825
.apiKey(param.getApiKey())
826+
.canceled(canceled)
820827
.build();
821828
}
822829

830+
@Override
831+
public String getDirective() {
832+
return (canceled != null && canceled.get()) ? "cancel" : null;
833+
}
834+
823835
@Override
824836
public Flowable<Object> getStreamingData() {
825837
return textStream

src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ public void sendText(String text) {
212212
}
213213

214214
public void stopSynthesizer() {
215-
sendTaskMessage("finish-task", new JsonObject());
215+
JsonObject input = new JsonObject();
216+
if (canceled.get()) {
217+
input.addProperty("directive", "cancel");
218+
}
219+
sendTaskMessage("finish-task", input);
216220
}
217221

218222
@Override
@@ -423,6 +427,7 @@ private void startStream(boolean enableSsml) throws NoApiKeyException, Interrupt
423427
connect();
424428
} else {
425429
startStreamTimeStamp = System.currentTimeMillis();
430+
canceled.set(false);
426431
}
427432

428433
checkConnectStatus(); // check websocket connection, if socket is closed.

src/main/java/com/alibaba/dashscope/base/FullDuplexServiceParam.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,16 @@ public void putHeader(String key, String value) {
4545
headers.put(key, value);
4646
}
4747
}
48+
49+
/**
50+
* The directive to be carried in payload.input.directive when sending the finish-task message.
51+
* Subclasses can override this method to instruct the server with special semantics (e.g.
52+
* "cancel") when the finish-task message is sent. Returns null by default, meaning no directive
53+
* will be added.
54+
*
55+
* @return the directive string, or null if none.
56+
*/
57+
public String getDirective() {
58+
return null;
59+
}
4860
}

0 commit comments

Comments
 (0)