34

Một thời gian trước, tôi phát hiện ra rằng playEarcon()never producesonUtteranceCompleted().Điều gì trong TtsService có thể giải thích việc thiếu onUtteranceCompleted() cho playEarcon()?

Lúc đó tôi chỉ giải thích các tài liệu mà nói: "Được gọi khi một lời nói đã được tổng hợp" như onUtteranceCompleted() là không áp dụng cho kết nối tai nghe bởi vì, một earcon là không thực sự là một kết quả của TTS tổng hợp.

Nhưng nhìn lại mã nguồn của Android, tôi chỉ đơn giản là không tìm được lời giải thích nào có thể biện minh cho diễn giải của tôi.

Một vài sự thật về my test jig:

  1. onUtteranceCompleted() luôn đến cho lời nói ID trước earcon. Đó là lời nói là một bài phát biểu TTS bình thường, không phải là một tai nghe.
  2. Đèn hiệu sau hiện phát ra (tức là chính xác như dự định).
  3. onUtteranceCompleted() cho biểu tượng tai đó không bao giờ xuất hiện. Đây là hành vi rất nhất quán và có thể tái sản xuất.

Delving sâu vào mã nguồn TtsService, có vẻ như là chỉ có 2 phương pháp mà có thể ảnh hưởng đến sự xuất hiện (hoặc không có) của onUtteranceCompleted():

  1. TtsService.processSpeechQueue()
  2. TtsService.onCompletion()

Nếu bạn kiểm tra mã đó, bạn sẽ thấy rằng một ứng cử viên thứ 3, TtsService.getSoundResource() bị loại trừ (chịu trách nhiệm về việc thiếu onUtteranceComplete cho e của tôi arcon) vì thực tế # 2 ở trên: Các earcon luôn luôn chơi, do đó getSoundResource() không thể trả về null.

Sử dụng cùng một logic, các ứng cử viên 1st, TtsService.processSpeechQueue(), cũng có thể được loại trừ khả năng, cho một thực tế tương tự # 2: earcon luôn đóng, vì thế mà 2 tuyên bố quan trọng sau đây luôn thực hiện:

1108 mPlayer.setOnCompletionListener(this); 
... 
1111 mPlayer.start(); 

vì vậy, chúng tôi chỉ còn ứng cử viên thứ 2, TtsService.onCompletion(), như một lời giải thích có thể cho lý do tại sao một playEarcon()never producesonUtteranceCompleted():

public void onCompletion(MediaPlayer arg0) { 
    // mCurrentSpeechItem may become null if it is stopped at the same 
    // time it completes. 
    SpeechItem currentSpeechItemCopy = mCurrentSpeechItem; 
    if (currentSpeechItemCopy != null) { 
    String callingApp = currentSpeechItemCopy.mCallingApp; 
    ArrayList<String> params = currentSpeechItemCopy.mParams; 
    String utteranceId = ""; 
    if (params != null) { 
     for (int i = 0; i < params.size() - 1; i = i + 2) { 
     String param = params.get(i); 
     if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)) { 
      utteranceId = params.get(i + 1); 
     } 
     } 
    } 
    if (utteranceId.length() > 0) { 
     dispatchUtteranceCompletedCallback(utteranceId, callingApp); 
    } 
    } 
    processSpeechQueue(); 
} 

Trong đó, chỉ có 2 điều kiện đó sẽ thất bại trong việc p roduce dispatchUtteranceCompletedCallback():

  1. currentSpeechItemCopy == null
  2. utteranceId.length() == 0

Nhưng tôi biết chắc chắn rằng điều kiện # 2 có thể được loại bỏ vì tôi đăng nhập tất cả utteranceIds và earcon chắc chắn ở đó.

Ngoài ra, kiểm tra toàn bộ hệ thống đăng nhập:

Log.v(SERVICE_TAG, "TTS callback: dispatch started"); 

Các thiếu onUtteranceCompleted() thể là kết quả của dispatchUtteranceCompletedCallback() không được gọi, nhưng nó cũng có thể là kết quả của mCallbacksMap.get(packageName) trở về null.

Vì vậy, chúng tôi là trái lại với 2 khả năng, cả hai đều không làm cho tôi nhiều ý nghĩa:

  1. Vào thời điểm của một onCompletion() earcon được gọi, earcon của mCurrentSpeechItem là null. Nhưng tại sao?
  2. mCallbacksMap trống. Nó là gì và khi nào nó có được dân cư?

Bất kỳ đề xuất hoặc giải thích nào khác để giải quyết bí ẩn này?

+1

Chúng tôi có cùng một vấn đề, giải pháp thay thế là thêm lời nói trống sau biểu tượng tai nghe. Nó cũng giống như các phiên bản API mới hơn (16) * do * tạo ra gọi lại cho earcons, xem xét điều này. –

+1

Ngoài ra còn có một điều kiện khó chịu trong 'TextToSpeech' contstructor khiến trình xử lý' onInit' truy cập NULL (khoảng 1% cơ hội) cho động cơ TTS, vì nó không có tham số gọi lại! Nó thực sự gọi 'onInit' của bạn trước khi hàm tạo kết thúc thực hiện. Điều này là rất nghiêm trọng, bởi vì họ mong đợi bạn thực hiện khởi tạo ('setOnUtteranceComplete',' addEarcon') trong 'onInit'. –

+1

Đã kiểm tra các trình giả lập và 'playEarcon' hiện gửi một cuộc gọi lại khi nó được thực hiện xong. Đây là API 15 trở lên. Bạn có thể sử dụng workaround tôi đã đề cập trong bình luận trước cho các API thấp hơn. –

Trả lời

1

Kiểm tra android.speech.tts.TextToSpeech#playEarcon() tại dòng 807. Đối số params được truyền cho dịch vụ text-to-speech binder là null, có nghĩa là dịch vụ không bao giờ nhận được ID phát âm của bạn.

public int playEarcon(String earcon, int queueMode, 
     HashMap<String,String> params) { 
    synchronized (mStartLock) { 
     ... 
     result = mITts.playEarcon(mPackageName, earcon, queueMode, null); 
    } 
    ... 
} 
Các vấn đề liên quan