ex

Fork of mbed-os-example-mbed5-blinky by mbed-os-examples

Committer:
TMBOY
Date:
Tue Jul 18 16:34:48 2017 +0800
Revision:
45:2aa9f933c8d2
?

Who changed what in which revision?

UserRevisionLine numberNew contents of line
TMBOY 45:2aa9f933c8d2 1 /*
TMBOY 45:2aa9f933c8d2 2 * Copyright (c) 2017 Baidu, Inc. All Rights Reserved.
TMBOY 45:2aa9f933c8d2 3 *
TMBOY 45:2aa9f933c8d2 4 * Licensed under the Apache License, Version 2.0 (the "License");
TMBOY 45:2aa9f933c8d2 5 * you may not use this file except in compliance with the License.
TMBOY 45:2aa9f933c8d2 6 * You may obtain a copy of the License at
TMBOY 45:2aa9f933c8d2 7 *
TMBOY 45:2aa9f933c8d2 8 * http://www.apache.org/licenses/LICENSE-2.0
TMBOY 45:2aa9f933c8d2 9 *
TMBOY 45:2aa9f933c8d2 10 * Unless required by applicable law or agreed to in writing, software
TMBOY 45:2aa9f933c8d2 11 * distributed under the License is distributed on an "AS IS" BASIS,
TMBOY 45:2aa9f933c8d2 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
TMBOY 45:2aa9f933c8d2 13 * See the License for the specific language governing permissions and
TMBOY 45:2aa9f933c8d2 14 * limitations under the License.
TMBOY 45:2aa9f933c8d2 15 */
TMBOY 45:2aa9f933c8d2 16 package com.baidu.duer.dcs.devicemodule.voiceoutput;
TMBOY 45:2aa9f933c8d2 17
TMBOY 45:2aa9f933c8d2 18 import com.baidu.duer.dcs.devicemodule.system.HandleDirectiveException;
TMBOY 45:2aa9f933c8d2 19 import com.baidu.duer.dcs.devicemodule.voiceoutput.message.SpeakPayload;
TMBOY 45:2aa9f933c8d2 20 import com.baidu.duer.dcs.devicemodule.voiceoutput.message.SpeechLifecyclePayload;
TMBOY 45:2aa9f933c8d2 21 import com.baidu.duer.dcs.devicemodule.voiceoutput.message.VoiceOutputStatePayload;
TMBOY 45:2aa9f933c8d2 22 import com.baidu.duer.dcs.framework.BaseDeviceModule;
TMBOY 45:2aa9f933c8d2 23 import com.baidu.duer.dcs.framework.IMessageSender;
TMBOY 45:2aa9f933c8d2 24 import com.baidu.duer.dcs.framework.IResponseListener;
TMBOY 45:2aa9f933c8d2 25 import com.baidu.duer.dcs.framework.message.ClientContext;
TMBOY 45:2aa9f933c8d2 26 import com.baidu.duer.dcs.framework.message.Directive;
TMBOY 45:2aa9f933c8d2 27 import com.baidu.duer.dcs.framework.message.Event;
TMBOY 45:2aa9f933c8d2 28 import com.baidu.duer.dcs.framework.message.Header;
TMBOY 45:2aa9f933c8d2 29 import com.baidu.duer.dcs.framework.message.MessageIdHeader;
TMBOY 45:2aa9f933c8d2 30 import com.baidu.duer.dcs.systeminterface.IMediaPlayer;
TMBOY 45:2aa9f933c8d2 31 import com.baidu.duer.dcs.util.LogUtil;
TMBOY 45:2aa9f933c8d2 32
TMBOY 45:2aa9f933c8d2 33 import java.io.ByteArrayInputStream;
TMBOY 45:2aa9f933c8d2 34 import java.io.InputStream;
TMBOY 45:2aa9f933c8d2 35 import java.util.ArrayList;
TMBOY 45:2aa9f933c8d2 36 import java.util.Collections;
TMBOY 45:2aa9f933c8d2 37 import java.util.LinkedList;
TMBOY 45:2aa9f933c8d2 38 import java.util.List;
TMBOY 45:2aa9f933c8d2 39
TMBOY 45:2aa9f933c8d2 40 /**
TMBOY 45:2aa9f933c8d2 41 * Voice Output模块处理并执行服务下发的Speak指令,上报SpeechStarted、SpeechFinished事件,以及维护自身的端状态
TMBOY 45:2aa9f933c8d2 42 * <p>
TMBOY 45:2aa9f933c8d2 43 * Created by guxiuzhong@baidu.com on 2017/5/31.
TMBOY 45:2aa9f933c8d2 44 */
TMBOY 45:2aa9f933c8d2 45 public class VoiceOutputDeviceModule extends BaseDeviceModule {
TMBOY 45:2aa9f933c8d2 46 private static final String TAG = VoiceOutputDeviceModule.class.getSimpleName();
TMBOY 45:2aa9f933c8d2 47 // 播放回调
TMBOY 45:2aa9f933c8d2 48 private final List<IVoiceOutputListener> voiceOutputListeners;
TMBOY 45:2aa9f933c8d2 49 // 播放队列
TMBOY 45:2aa9f933c8d2 50 private final LinkedList<SpeakPayload> speakQueue = new LinkedList<>();
TMBOY 45:2aa9f933c8d2 51 // 语音播放的播放器
TMBOY 45:2aa9f933c8d2 52 private final IMediaPlayer mediaPlayer;
TMBOY 45:2aa9f933c8d2 53 private SpeechState speechState = SpeechState.FINISHED;
TMBOY 45:2aa9f933c8d2 54
TMBOY 45:2aa9f933c8d2 55 // 上一次的token
TMBOY 45:2aa9f933c8d2 56 private String lastSpeakToken = "";
TMBOY 45:2aa9f933c8d2 57
TMBOY 45:2aa9f933c8d2 58 // 当前播放状态
TMBOY 45:2aa9f933c8d2 59 private enum SpeechState {
TMBOY 45:2aa9f933c8d2 60 PLAYING,
TMBOY 45:2aa9f933c8d2 61 FINISHED
TMBOY 45:2aa9f933c8d2 62 }
TMBOY 45:2aa9f933c8d2 63
TMBOY 45:2aa9f933c8d2 64 public VoiceOutputDeviceModule(IMediaPlayer mediaPlayer,
TMBOY 45:2aa9f933c8d2 65 IMessageSender messageSender) {
TMBOY 45:2aa9f933c8d2 66 super(ApiConstants.NAMESPACE, messageSender);
TMBOY 45:2aa9f933c8d2 67 this.mediaPlayer = mediaPlayer;
TMBOY 45:2aa9f933c8d2 68 this.mediaPlayer.addMediaPlayerListener(mediaPlayerListener);
TMBOY 45:2aa9f933c8d2 69 this.voiceOutputListeners = Collections.synchronizedList(new ArrayList<IVoiceOutputListener>());
TMBOY 45:2aa9f933c8d2 70 }
TMBOY 45:2aa9f933c8d2 71
TMBOY 45:2aa9f933c8d2 72 @Override
TMBOY 45:2aa9f933c8d2 73 public ClientContext clientContext() {
TMBOY 45:2aa9f933c8d2 74 String namespace = ApiConstants.NAMESPACE;
TMBOY 45:2aa9f933c8d2 75 String name = ApiConstants.Events.SpeechState.NAME;
TMBOY 45:2aa9f933c8d2 76 Header header = new Header(namespace, name);
TMBOY 45:2aa9f933c8d2 77 VoiceOutputStatePayload payload = new VoiceOutputStatePayload(lastSpeakToken,
TMBOY 45:2aa9f933c8d2 78 mediaPlayer.getCurrentPosition(),
TMBOY 45:2aa9f933c8d2 79 speechState.name());
TMBOY 45:2aa9f933c8d2 80 return new ClientContext(header, payload);
TMBOY 45:2aa9f933c8d2 81 }
TMBOY 45:2aa9f933c8d2 82
TMBOY 45:2aa9f933c8d2 83 @Override
TMBOY 45:2aa9f933c8d2 84 public void handleDirective(Directive directive) throws HandleDirectiveException {
TMBOY 45:2aa9f933c8d2 85 String directiveName = directive.getName();
TMBOY 45:2aa9f933c8d2 86 LogUtil.d(TAG, "rawMessage:" + directive.rawMessage);
TMBOY 45:2aa9f933c8d2 87 LogUtil.d(TAG, "directiveName:" + directiveName);
TMBOY 45:2aa9f933c8d2 88 if (directiveName.equals(ApiConstants.Directives.Speak.NAME)) {
TMBOY 45:2aa9f933c8d2 89 SpeakPayload speak = (SpeakPayload) directive.payload;
TMBOY 45:2aa9f933c8d2 90 handleSpeak(speak);
TMBOY 45:2aa9f933c8d2 91 } else {
TMBOY 45:2aa9f933c8d2 92 String message = "VoiceOutput cannot handle the directive";
TMBOY 45:2aa9f933c8d2 93 throw (new HandleDirectiveException(
TMBOY 45:2aa9f933c8d2 94 HandleDirectiveException.ExceptionType.UNSUPPORTED_OPERATION, message));
TMBOY 45:2aa9f933c8d2 95 }
TMBOY 45:2aa9f933c8d2 96 }
TMBOY 45:2aa9f933c8d2 97
TMBOY 45:2aa9f933c8d2 98 private void handleSpeak(SpeakPayload speak) {
TMBOY 45:2aa9f933c8d2 99 speakQueue.add(speak);
TMBOY 45:2aa9f933c8d2 100 // 如果已经有了,就只入队列,等待下一次的调度
TMBOY 45:2aa9f933c8d2 101 if (speakQueue.size() == 1) {
TMBOY 45:2aa9f933c8d2 102 startSpeech();
TMBOY 45:2aa9f933c8d2 103 }
TMBOY 45:2aa9f933c8d2 104 }
TMBOY 45:2aa9f933c8d2 105
TMBOY 45:2aa9f933c8d2 106 private void startSpeech() {
TMBOY 45:2aa9f933c8d2 107 final SpeakPayload speak = speakQueue.getFirst();
TMBOY 45:2aa9f933c8d2 108 if (null != speak) {
TMBOY 45:2aa9f933c8d2 109 lastSpeakToken = speak.token;
TMBOY 45:2aa9f933c8d2 110 InputStream inputStream = new ByteArrayInputStream(speak.attachedContent);
TMBOY 45:2aa9f933c8d2 111 mediaPlayer.play(new IMediaPlayer.MediaResource(inputStream));
TMBOY 45:2aa9f933c8d2 112 }
TMBOY 45:2aa9f933c8d2 113 }
TMBOY 45:2aa9f933c8d2 114
TMBOY 45:2aa9f933c8d2 115 private IMediaPlayer.IMediaPlayerListener mediaPlayerListener = new IMediaPlayer.SimpleMediaPlayerListener() {
TMBOY 45:2aa9f933c8d2 116 @Override
TMBOY 45:2aa9f933c8d2 117 public void onPrepared() {
TMBOY 45:2aa9f933c8d2 118 super.onPrepared();
TMBOY 45:2aa9f933c8d2 119 speechState = SpeechState.PLAYING;
TMBOY 45:2aa9f933c8d2 120 sendStartedEvent(lastSpeakToken);
TMBOY 45:2aa9f933c8d2 121 fireOnVoiceOutputStarted();
TMBOY 45:2aa9f933c8d2 122 }
TMBOY 45:2aa9f933c8d2 123
TMBOY 45:2aa9f933c8d2 124 @Override
TMBOY 45:2aa9f933c8d2 125 public void onStopped() {
TMBOY 45:2aa9f933c8d2 126 super.onStopped();
TMBOY 45:2aa9f933c8d2 127 speakQueue.clear();
TMBOY 45:2aa9f933c8d2 128 }
TMBOY 45:2aa9f933c8d2 129
TMBOY 45:2aa9f933c8d2 130 @Override
TMBOY 45:2aa9f933c8d2 131 public void onError(String error, IMediaPlayer.ErrorType errorType) {
TMBOY 45:2aa9f933c8d2 132 super.onError(error, errorType);
TMBOY 45:2aa9f933c8d2 133 finishedSpeechItem();
TMBOY 45:2aa9f933c8d2 134 }
TMBOY 45:2aa9f933c8d2 135
TMBOY 45:2aa9f933c8d2 136 @Override
TMBOY 45:2aa9f933c8d2 137 public void onCompletion() {
TMBOY 45:2aa9f933c8d2 138 LogUtil.d(TAG, " IMediaPlayer onCompletion");
TMBOY 45:2aa9f933c8d2 139 finishedSpeechItem();
TMBOY 45:2aa9f933c8d2 140 }
TMBOY 45:2aa9f933c8d2 141 };
TMBOY 45:2aa9f933c8d2 142
TMBOY 45:2aa9f933c8d2 143 /**
TMBOY 45:2aa9f933c8d2 144 * 播放完一条后开始下一条的处理
TMBOY 45:2aa9f933c8d2 145 */
TMBOY 45:2aa9f933c8d2 146 private void finishedSpeechItem() {
TMBOY 45:2aa9f933c8d2 147 speakQueue.poll();
TMBOY 45:2aa9f933c8d2 148 LogUtil.d(TAG, "finishedSpeechItem speakQueue size :" + speakQueue.size());
TMBOY 45:2aa9f933c8d2 149 if (speakQueue.isEmpty()) {
TMBOY 45:2aa9f933c8d2 150 speechState = SpeechState.FINISHED;
TMBOY 45:2aa9f933c8d2 151 sendFinishedEvent(lastSpeakToken);
TMBOY 45:2aa9f933c8d2 152 fireOnVoiceOutputFinished();
TMBOY 45:2aa9f933c8d2 153 } else {
TMBOY 45:2aa9f933c8d2 154 startSpeech();
TMBOY 45:2aa9f933c8d2 155 }
TMBOY 45:2aa9f933c8d2 156 }
TMBOY 45:2aa9f933c8d2 157
TMBOY 45:2aa9f933c8d2 158 @Override
TMBOY 45:2aa9f933c8d2 159 public void release() {
TMBOY 45:2aa9f933c8d2 160 if (mediaPlayer != null) {
TMBOY 45:2aa9f933c8d2 161 mediaPlayer.release();
TMBOY 45:2aa9f933c8d2 162 mediaPlayer.removeMediaPlayerListener(mediaPlayerListener);
TMBOY 45:2aa9f933c8d2 163 }
TMBOY 45:2aa9f933c8d2 164 if (isSpeaking()) {
TMBOY 45:2aa9f933c8d2 165 speechState = SpeechState.FINISHED;
TMBOY 45:2aa9f933c8d2 166 }
TMBOY 45:2aa9f933c8d2 167 speakQueue.clear();
TMBOY 45:2aa9f933c8d2 168 voiceOutputListeners.clear();
TMBOY 45:2aa9f933c8d2 169 }
TMBOY 45:2aa9f933c8d2 170
TMBOY 45:2aa9f933c8d2 171 public boolean isSpeaking() {
TMBOY 45:2aa9f933c8d2 172 return speechState == SpeechState.PLAYING;
TMBOY 45:2aa9f933c8d2 173 }
TMBOY 45:2aa9f933c8d2 174
TMBOY 45:2aa9f933c8d2 175 /**
TMBOY 45:2aa9f933c8d2 176 * 播放开始时上报的事件
TMBOY 45:2aa9f933c8d2 177 *
TMBOY 45:2aa9f933c8d2 178 * @param token token 一条speak的唯一标识
TMBOY 45:2aa9f933c8d2 179 */
TMBOY 45:2aa9f933c8d2 180 private void sendStartedEvent(String token) {
TMBOY 45:2aa9f933c8d2 181 String namespace = ApiConstants.NAMESPACE;
TMBOY 45:2aa9f933c8d2 182 String name = ApiConstants.Events.SpeechStarted.NAME;
TMBOY 45:2aa9f933c8d2 183 MessageIdHeader header = new MessageIdHeader(namespace, name);
TMBOY 45:2aa9f933c8d2 184 Event event = new Event(header, new SpeechLifecyclePayload(token));
TMBOY 45:2aa9f933c8d2 185 messageSender.sendEvent(event);
TMBOY 45:2aa9f933c8d2 186 }
TMBOY 45:2aa9f933c8d2 187
TMBOY 45:2aa9f933c8d2 188 /**
TMBOY 45:2aa9f933c8d2 189 * 播放结束时上报的事件
TMBOY 45:2aa9f933c8d2 190 *
TMBOY 45:2aa9f933c8d2 191 * @param token token 一条speak的唯一标识
TMBOY 45:2aa9f933c8d2 192 */
TMBOY 45:2aa9f933c8d2 193 private void sendFinishedEvent(String token) {
TMBOY 45:2aa9f933c8d2 194 String namespace = ApiConstants.NAMESPACE;
TMBOY 45:2aa9f933c8d2 195 String name = ApiConstants.Events.SpeechFinished.NAME;
TMBOY 45:2aa9f933c8d2 196 MessageIdHeader header = new MessageIdHeader(namespace, name);
TMBOY 45:2aa9f933c8d2 197 Event event = new Event(header, new SpeechLifecyclePayload(token));
TMBOY 45:2aa9f933c8d2 198 messageSender.sendEvent(event, new IResponseListener() {
TMBOY 45:2aa9f933c8d2 199 @Override
TMBOY 45:2aa9f933c8d2 200 public void onSucceed(int statusCode) {
TMBOY 45:2aa9f933c8d2 201 // 没有新的语音speak-stream
TMBOY 45:2aa9f933c8d2 202 if (statusCode == 204) {
TMBOY 45:2aa9f933c8d2 203 mediaPlayer.setActive(false);
TMBOY 45:2aa9f933c8d2 204 } else {
TMBOY 45:2aa9f933c8d2 205 mediaPlayer.setActive(true);
TMBOY 45:2aa9f933c8d2 206 }
TMBOY 45:2aa9f933c8d2 207 }
TMBOY 45:2aa9f933c8d2 208
TMBOY 45:2aa9f933c8d2 209 @Override
TMBOY 45:2aa9f933c8d2 210 public void onFailed(String errorMessage) {
TMBOY 45:2aa9f933c8d2 211 mediaPlayer.setActive(false);
TMBOY 45:2aa9f933c8d2 212 }
TMBOY 45:2aa9f933c8d2 213 });
TMBOY 45:2aa9f933c8d2 214 }
TMBOY 45:2aa9f933c8d2 215
TMBOY 45:2aa9f933c8d2 216 private void fireOnVoiceOutputStarted() {
TMBOY 45:2aa9f933c8d2 217 for (IVoiceOutputListener listener : voiceOutputListeners) {
TMBOY 45:2aa9f933c8d2 218 listener.onVoiceOutputStarted();
TMBOY 45:2aa9f933c8d2 219 }
TMBOY 45:2aa9f933c8d2 220 }
TMBOY 45:2aa9f933c8d2 221
TMBOY 45:2aa9f933c8d2 222 private void fireOnVoiceOutputFinished() {
TMBOY 45:2aa9f933c8d2 223 for (IVoiceOutputListener listener : voiceOutputListeners) {
TMBOY 45:2aa9f933c8d2 224 listener.onVoiceOutputFinished();
TMBOY 45:2aa9f933c8d2 225 }
TMBOY 45:2aa9f933c8d2 226 }
TMBOY 45:2aa9f933c8d2 227
TMBOY 45:2aa9f933c8d2 228 /**
TMBOY 45:2aa9f933c8d2 229 * 添加播放监听
TMBOY 45:2aa9f933c8d2 230 *
TMBOY 45:2aa9f933c8d2 231 * @param listener listener
TMBOY 45:2aa9f933c8d2 232 */
TMBOY 45:2aa9f933c8d2 233 public void addVoiceOutputListener(IVoiceOutputListener listener) {
TMBOY 45:2aa9f933c8d2 234 this.voiceOutputListeners.add(listener);
TMBOY 45:2aa9f933c8d2 235 }
TMBOY 45:2aa9f933c8d2 236
TMBOY 45:2aa9f933c8d2 237 /**
TMBOY 45:2aa9f933c8d2 238 * 播报监听器接口
TMBOY 45:2aa9f933c8d2 239 */
TMBOY 45:2aa9f933c8d2 240 public interface IVoiceOutputListener {
TMBOY 45:2aa9f933c8d2 241 /**
TMBOY 45:2aa9f933c8d2 242 * 开始播放时回调
TMBOY 45:2aa9f933c8d2 243 */
TMBOY 45:2aa9f933c8d2 244 void onVoiceOutputStarted();
TMBOY 45:2aa9f933c8d2 245
TMBOY 45:2aa9f933c8d2 246 /**
TMBOY 45:2aa9f933c8d2 247 * 播放完成时回调
TMBOY 45:2aa9f933c8d2 248 */
TMBOY 45:2aa9f933c8d2 249 void onVoiceOutputFinished();
TMBOY 45:2aa9f933c8d2 250 }
TMBOY 45:2aa9f933c8d2 251 }