/**
   * Notification that the playback with the given id has ended.
   *
   * @param id the id
   */
  void playEnded(final String id) {
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("speech with id '" + id + "' ended");
    }

    synchronized (speakables) {
      final QueuedSpeakable queuedSpeakable = speakables.poll();
      if (queuedSpeakable == null) {
        return;
      }
      final SpeakableText speakable = queuedSpeakable.getSpeakable();
      final SynthesizedOutputEvent event = new OutputEndedEvent(this, sessionId, speakable);
      synchronized (listeners) {
        for (SynthesizedOutputListener listener : listeners) {
          listener.outputStatusChanged(event);
        }
      }

      if (speakables.isEmpty()) {
        LOGGER.info("BML queue is empty");
        final SynthesizedOutputEvent emptyEvent = new QueueEmptyEvent(this, sessionId);
        synchronized (listeners) {
          for (SynthesizedOutputListener listener : listeners) {
            listener.outputStatusChanged(emptyEvent);
          }
        }
      } else {
        sendNextSpeakable();
      }
    }
  }
 /** Sends the next speakable to Avatar. */
 private void sendNextSpeakable() {
   final QueuedSpeakable next = speakables.peek();
   final SpeakableText speakable = next.getSpeakable();
   final String utterance;
   final SsmlDocument document;
   if (speakable instanceof SpeakableSsmlText) {
     final SpeakableSsmlText ssml = (SpeakableSsmlText) speakable;
     document = ssml.getDocument();
     final Speak speak = document.getSpeak();
     utterance = speak.getTextContent();
   } else {
     utterance = speakable.getSpeakableText();
     document = null;
   }
   ErrorEvent error = null;
   try {
     final String bml = createBML(utterance, document);
     sendToAvatar(bml);
   } catch (SocketException e) {
     error = new BadFetchError(e.getMessage(), e);
   } catch (UnknownHostException e) {
     error = new BadFetchError(e.getMessage(), e);
   } catch (IOException e) {
     error = new BadFetchError(e.getMessage(), e);
   } catch (XMLStreamException e) {
     error = new BadFetchError(e.getMessage(), e);
   }
   if (error != null) {
     synchronized (listeners) {
       for (SynthesizedOutputListener listener : listeners) {
         listener.outputError(error);
       }
     }
   }
 }