/** stop all streams from being cast to the server */
  void doUnpublish() {
    for (String key : mLocalStream.keySet()) {
      final StreamDescription stream = mLocalStream.get(key);
      if (stream != null && stream.isLocal()) {
        stream.pc.removeStream(lMS);

        for (RoomObserver obs : mObservers) {
          obs.onStreamRemoved(stream);
        }

        if (mObservers.size() == 0) {
          destroy(stream);
        }
      }
    }
    mLocalStream.clear();

    if (lMS != null) {
      lMS.dispose();
    }
    if (mVideoCapturer != null) {
      mVideoCapturer.dispose();
    }

    lMS = null;
    mVideoCapturer = null;
    if (mVideoSource != null && !mVideoStopped) {
      mVideoSource.stop();
    }
    mVideoSource = null;
  }
 void sendConfirmation() {
   JSONObject p0 = mStream.toJsonOffer("ok");
   try {
     p0.put("streamId", mStream.getId());
     p0.put("messageType", "OK");
     p0.put("offererSessionId", mOffererSessionId);
     p0.put("answererSessionId", mAnswererSessionId);
     p0.put("seq", 1);
     // p0.put("sdp", " ");
   } catch (JSONException e) {
   }
   sendSDPSocket(mSignalChannel, p0, p0, null);
 }
        @Override
        public void onEvent(JSONArray args, Acknowledge ack) {
          // [{"data":true,"id":331051653483882560,"screen":"","audio":true,"video":true}]
          log("mOnAddStream");

          try {
            StreamDescription stream = StreamDescription.parseJson(args.getJSONObject(0));

            boolean isLocal = mLocalStream.get(stream.getId()) != null;
            if (!isLocal) {
              mRemoteStream.put(stream.getId(), stream);
              triggerStreamAdded(stream);
            }
          } catch (JSONException e) {
          }
        }
 @Override
 public void onAddStream(final MediaStream media) {
   if (mSdpObserver.isLocal()) {
     return;
   }
   if (media.videoTracks.size() == 1 && mDesc != null) {
     ((StreamDescription) mDesc).setMedia(media);
     triggerMediaAvailable(mDesc);
   }
 }
  @Override
  public void disable(final StreamDescriptionInterface param0) {
    final StreamDescription stream = (StreamDescription) param0;
    if (stream.isLocal()) {
      return;
    }
    sVcHandler.post(
        new Runnable() {
          @Override
          public void run() {
            sendMessageSocket("unsubscribe", stream.getId(), null);
            stream.detachRenderer();

            stream.pc.close();
            stream.pc.dispose();
            stream.onDisable();
          }
        });
  }
  /** begin streaming to server - MUST run on VcThread */
  void doPublish(VideoStreamsView view) {
    if (mVideoCapturer != null) {
      return;
    }

    MediaConstraints videoConstraints = new MediaConstraints();
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", "320"));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight", "240"));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxFrameRate", "10"));
    MediaConstraints audioConstraints = new MediaConstraints();
    audioConstraints.optional.add(
        new MediaConstraints.KeyValuePair("googEchoCancellation2", "true"));
    audioConstraints.optional.add(
        new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
    lMS = sFactory.createLocalMediaStream("ARDAMS");

    if (videoConstraints != null) {
      mVideoCapturer = getVideoCapturer();
      mVideoSource = sFactory.createVideoSource(mVideoCapturer, videoConstraints);
      VideoTrack videoTrack = sFactory.createVideoTrack("ARDAMSv0", mVideoSource);
      lMS.addTrack(videoTrack);
    }
    if (audioConstraints != null) {
      AudioTrack audioTrack =
          sFactory.createAudioTrack("ARDAMSa0", sFactory.createAudioSource(audioConstraints));
      lMS.addTrack(audioTrack);
      audioTrack.setEnabled(false);
    }

    StreamDescription stream = new StreamDescription("", false, true, true, false, null, mNick);
    MediaConstraints pcConstraints = makePcConstraints();
    MyPcObserver pcObs = new MyPcObserver(new LicodeSdpObserver(stream, true), stream);

    PeerConnection pc = sFactory.createPeerConnection(mIceServers, pcConstraints, pcObs);
    pc.addStream(lMS, new MediaConstraints());

    stream.setMedia(lMS);
    if (view != null) {
      stream.attachRenderer(new VideoCallbacks(view, VideoStreamsView.LOCAL_STREAM_ID));
    }
    stream.initLocal(pc, pcObs.getSdpObserver());
  }
  void doSubscribe(final StreamDescription stream) {
    if (stream.isLocal()) {
      return;
    }

    if (stream.getMedia() != null) {
      // already subscribed!
      triggerMediaAvailable(stream);
      return;
    }

    // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging.
    // NOTE: this _must_ happen while |factory| is alive!
    // Logging.enableTracing("logcat:",
    // EnumSet.of(Logging.TraceLevel.TRACE_ALL),
    // Logging.Severity.LS_SENSITIVE);

    MyPcObserver pcObs = new MyPcObserver(new LicodeSdpObserver(stream, false), stream);
    PeerConnection pc = sFactory.createPeerConnection(mIceServers, makePcConstraints(), pcObs);

    stream.initRemote(pc, pcObs.getSdpObserver());
  }
    void sendLocalDescription() {
      JSONObject desc = null;
      if (mIsPublish) {
        desc = mStream.toJsonOffer("offer");
      } else {
        desc = mStream.toJsonOffer(null);
        try {
          desc.put("streamId", mStream.getId());
        } catch (JSONException e) {
        }
      }
      JSONObject p1 = new JSONObject();
      try {
        p1.put("messageType", "OFFER");
        p1.put("sdp", mLocalSdp.description);
        p1.put("tiebreaker", (int) (Math.random() * (Integer.MAX_VALUE - 2)) + 1);
        p1.put("offererSessionId", mOffererSessionId); // hardcoded in
        // Licode?
        p1.put("seq", 1); // should not be hardcoded, but works for now
      } catch (JSONException e) {
      }
      log("SdpObserver#sendLocalDescription; to: " + mSignalChannel + "; msg: " + p1.toString());
      sendSDPSocket(
          mSignalChannel,
          desc,
          p1,
          new Acknowledge() {
            @Override
            public void acknowledge(JSONArray arg0) {
              log("SdpObserver#sendLocalDescription#sendSDPSocket#Acknowledge: " + arg0.toString());

              String streamId = null;
              SessionDescription remoteSdp = null;
              try {
                // log(arg0.getString(0));
                // JSONObject jsonAnswer = arg0.getJSONObject(0);
                // licode server sends answer as string which is
                // basically a json string, though
                JSONObject jsonAnswer = new JSONObject(arg0.getString(0));
                boolean answer = "ANSWER".equals(jsonAnswer.getString("messageType"));
                if (!answer) {
                  log("SdpObserver: expected ANSWER, got: " + jsonAnswer.getString("messageType"));
                }
                remoteSdp = new SessionDescription(Type.ANSWER, jsonAnswer.getString("sdp"));

                if (mIsPublish) {
                  streamId = arg0.getString(1);
                }

                mAnswererSessionId = jsonAnswer.getInt("answererSessionId");
              } catch (JSONException e1) {
              }

              if (mIsPublish) {
                mStream.setId(streamId);
                mLocalStream.put(streamId, mStream);
              }

              final SessionDescription finalRemoteSdp = remoteSdp;
              mActivity.runOnUiThread(
                  new Runnable() {
                    @Override
                    public void run() {
                      mStream.pc.setRemoteDescription(LicodeSdpObserver.this, finalRemoteSdp);
                    }
                  });
            }
          });
    }
 private void startConnecting() {
   mStream.pc.createOffer(this, mStream.sdpConstraints());
 }
 public boolean isLocal() {
   return mStream == null ? false : mStream.isLocal();
 }
 void removeStream(StreamDescription stream) {
   stream.onClosing();
   triggerStreamRemoved(stream);
 }
 @Override
 public void attachRenderer(StreamDescriptionInterface stream, VideoStreamsView mVsv) {
   ((StreamDescription) stream)
       .attachRenderer(new LicodeConnector.VideoCallbacks(mVsv, stream.getId()));
 }