    001    package com.skype.api;
    002
    003    import java.io.IOException;
    004    import java.util.*;
    005    import com.skype.ipc.*;
    006    /**
    007     * This class contains basic video control functionality for live conversations with video. Basically, Video objects represent specific Participant's video state in a live Conversation. The Video class can represent both local (outgoing) and remote (incoming) video streams. Note that as of SkypeKit SDK version 3.2, this class no longer handles video rendering in the UI. Currently available SkypeKit runtimes do not support multi-party video. The API however is designed with future compatibility in mind, so the Video class is attached to Participant class rather than Conversation class. Once multi-party video will become available for SkypeKit, the logic should go like this: <br><br>Let there be 4-way live conversation C and participants P1, P2, P3 and P4. P1 is the local user. Remote participants P2 and P3 are capable of sending video. Remote user P4 is not capable of sending video. You would then end up with 4 video objects: V1, V2, V3 and V0. <br><br> - C->P1->V1-> outgoing video stream <br> - C->P2->V2-> incoming video stream 1 <br> - C->P3->V3-> incoming video stream 2 <br> - C->P4-> no video object as participant P4 does not advertise supporting video <br> - V0-> local webcam preview - this is not attached to any particular conversation, however the corresponding video object can be retrieved with Skype.GetPreviewVideo method. <br><br>As getting from a live conversation to running video streams involves three classes, it can be somewhat less than obvious. The basic state transition logic goes like this: <br><br>You start out with a Conversation, that suddenly becomes live <br><br>CONVERSATION.LOCAL_LIVESTATUS = IM_LIVE <br>At this point you have access to participant list of that conversation. The next step will be to catch Partcipant property changes for PARTICIPANT.VIDEO_STATUS to see if any of the people in conversation have Video available. Note that you should not make assumptions on when this availability happens. Remote users may switch their video on-off as they please. <br><br>PARTICIPANT.VIDEO_STATUS = VIDEO_AVAILABLE <br>If you get to VIDEO_AVAILABLE (not necessarily for all Participants), you can retrieve Video object, with Participant.GetVideo method. <br><br>Now you will need to handle Video.STATUS property changes. In case of successful video call, the sequence of Video.STATUS and Participant.VIDEO_STATUS changes for each Participant and Video object should look like this: <br><br> - Video.STATUS = AVAILABLE <br> - Video.STATUS = STARTING <br> - Video.STATUS = CHECKING_SUBSCRIPTION <br> - Video.STATUS = STARTING <br><br>Participant.VIDEO_STATUS = VIDEO_CONNECTING <br> - Video.STATUS = RUNNING <br> - Participant.VIDEO_STATUS = STREAMING <br>Both Video.STATUS == RUNNING and Participant.VIDEO_STATUS == STREAMING are indicative that the video for that particular participant is up and running, and your UI should update itself accordingly. <br><br>NB! Note that it is not enough to check for Video.STATUS property updates. By the time you obtain the Video object in your client, it may already it may already have progressed to a further status. You should always check the status property immediately after obtaining the Video object. <br>
    008     */
    009
    010
    011    public class Video extends SkypeObject {
    012
    013
    014            public interface VideoListener {
    015                    /** This event gets called when there are changes to Video properties defined in Video.PROPERTY  */
    016                    public void OnPropertyChange(SkypeObject obj, PROPERTY prop, Object value);
    017
    018                    public void OnCaptureRequestCompleted(SkypeObject obj, int requestId, boolean isSuccessful, byte[] image, int width, int height);
    019
    020                    /**called when the video stops*/
    021                    public void OnLastFrameCapture(SkypeObject obj, byte[] image, int width, int height);
    022
    023            }
    024
    025            public Video(int oid, Skype skype) {
    026                    super(oid,skype);
    027            }
    028
    029            private static final int MODULE_ID = 11;
    030
    031            public static final int moduleID() {
    032                    return MODULE_ID;
    033            }
    034
    035            /** Properties of the Video class */
    036            public enum PROPERTY {
    037
    038                    /** Video.STATUS, type: STATUS */
    039                    status(130),
    040
    041                    /** 'errorcode errortext' , type: String */
    042                    error(131),
    043
    044                    /** space-separated string of tokens, type: String */
    045                    debuginfo(132),
    046
    047                    /** This property does not currently work, always containing an empty string. For desktop video, you can get the frame dimensions from the video frame buffers API instead - the buffer struct retrieved with ipc.getFrame() or ipc.getNewFrame() has width and height fields, which you can then use in your UI. With RTP video solutions, you already have the frame sizes in your videohost code. Communicating these to the UI process is currently up to you. <br>, type: String */
    048                    dimensions(133),
    049
    050                    /** Indicates whether the video object is streaming webcam video or screensharing session, values: MEDIA_SCREENSHARING, MEDIA_VIDEO <br>, type: MEDIATYPE */
    051                    media_type(134),
    052
    053                    /** conference id to be able to identify remote/local video in the same call, type: int */
    054                    convo_id(1104),
    055
    056                    /** device path used by video object, type: String */
    057                    device_path(1105);
    058
    059                    private static final Map<Integer,PROPERTY> lookup = new HashMap<Integer,PROPERTY>();
    060
    061                    static {
    062                            for(PROPERTY s : EnumSet.allOf(PROPERTY.class))
    063                                    lookup.put(s.getId(), s);
    064                    }
    065
    066                    private final int id;
    067
    068                    private PROPERTY(int value) {
    069                            this.id = value;
    070                    }
    071
    072                    public int getId() { return id; }
    073
    074                    public static PROPERTY get(int code) {
    075                            return lookup.get(code);
    076                    }
    077
    078                    public static PROPERTY fromString(String s) {
    079                            for (PROPERTY p : lookup.values()) {
    080                                    if (p.toString() == s) {
    081                                            return p;
    082                                    }
    083                            }
    084                            return null;
    085                    }
    086            }
    087
    088            public Object GetPropertyAsEnum(int propid) {
    089                    return PROPERTY.get(propid);
    090            }
    091
    092            public String GetStrProperty(PROPERTY prop) {
    093                    //check in propcache if so then return
    094                    if (mPropCache.containsKey(new Integer(prop.id))){
    095                            String value =  (String)mPropCache.get(prop.id);
    096                            if (value != null && !(value.length() == 0) ){
    097                                    return value;
    098                            }
    099                    }
    100                    //else get from skypekit...
    101                    GetPropertyRequest request = new GetPropertyRequest(11, mObjectId, prop.id);
    102
    103                    String string = null;
    104                    GetPropertyResponse r = skype.GetProperty(request);
    105                    if (r != null){
    106                            string = r.GetAsString();
    107                    }
    108
    109                    if (string != null)
    110                    {
    111                            mPropCache.put(new Integer(prop.id), string);
    112                    }
    113                    return string;
    114            }
    115
    116            public int GetIntProperty(PROPERTY prop) {
    117                    //check in propcache if so then return
    118                    if (mPropCache.containsKey(new Integer(prop.id))){
    119                            int value = ((Integer)mPropCache.get(prop.id)).intValue();
    120                            if (value != 0){
    121                                    return value;
    122                            }
    123                    }
    124                    //else get from skypekit...
    125                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
    126
    127                    Integer integer = null;
    128                    GetPropertyResponse r = skype.GetProperty(request);
    129                    if (r != null){
    130                            integer  = r.GetAsInt();
    131                    }
    132
    133                    if (integer != null)
    134                    {
    135                            mPropCache.put(new Integer(prop.id), integer);
    136                            return integer.intValue();
    137                    }
    138                    else
    139                    {
    140                            return 0;
    141                    }
    142            }
    143
    144            public boolean GetBooleanProperty(PROPERTY prop) {
    145                    //check in propcache if so then return
    146                    if (mPropCache.containsKey(new Integer(prop.id))){
    147                            return ((Boolean)mPropCache.get(prop.id)).booleanValue();
    148                    }
    149                    //else get from skypekit...
    150                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
    151
    152                    Boolean boolResp = null;
    153                    GetPropertyResponse r = skype.GetProperty(request);
    154                    if (r != null){
    155                            boolResp  = r.GetAsBoolean();
    156                    }
    157
    158                    if (boolResp != null)
    159                    {
    160                            mPropCache.put(new Integer(prop.id), boolResp);
    161                            return boolResp.booleanValue();
    162                    }
    163                    else
    164                    {
    165                            return false;
    166                    }
    167            }
    168
    169            public byte [] GetBinProperty(PROPERTY prop) {
    170                    //get from skypekit...
    171                    GetPropertyRequest request = new GetPropertyRequest(11, mObjectId, prop.id);
    172
    173                    byte [] data = null;
    174                    GetPropertyResponse r = skype.GetProperty(request);
    175                    if (r != null) {
    176                            data = r.GetAsBinary();
    177                    }
    178                    return data;
    179            }
    180
    181            /** Setupkey SETUPKEY_VIDEO_DEVICE type:string  <br>Selected video device name <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
    182            public static final String VIDEO_DEVICE = "Lib/Video/Device";
    183
    184            /** Setupkey SETUPKEY_VIDEO_DEVICE_PATH type:string  <br>Currently selected video device path. <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
    185            public static final String VIDEO_DEVICE_PATH = "Lib/Video/DevicePath";
    186
    187            /** Setupkey SETUPKEY_VIDEO_AUTOSEND type:int  <br>Setting this to 1 starts sending video automatically when call starts <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
    188            public static final String VIDEO_AUTOSEND = "Lib/Video/AutoSend";
    189
    190            /** Setupkey SETUPKEY_VIDEO_DISABLE type:int  <br>Setting this to 1 disables all video functionality. <br>This setup key is machine-specific and affects all local accounts. <br> */
    191            public static final String VIDEO_DISABLE = "*Lib/Video/Disable";
    192
    193            /** Setupkey SETUPKEY_VIDEO_RECVPOLICY type:string default value:"contacts" <br>noone | contacts | callpolicy <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
    194            public static final String VIDEO_RECVPOLICY = "Lib/Video/RecvPolicy";
    195
    196            /** Setupkey SETUPKEY_VIDEO_ADVERTPOLICY type:string default value:"contacts" <br>noone | contacts | everyone <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
    197            public static final String VIDEO_ADVERTPOLICY = "Lib/Video/AdvertPolicy";
    198
    199            /**
    200             */
    201            public enum STATUS {
    202
    203                    /** */
    204                    NOT_AVAILABLE(0),
    205
    206                    /** */
    207                    AVAILABLE(1),
    208
    209                    /** */
    210                    STARTING(2),
    211
    212                    /** */
    213                    REJECTED(3),
    214
    215                    /** */
    216                    RUNNING(4),
    217
    218                    /** */
    219                    STOPPING(5),
    220
    221                    /** */
    222                    PAUSED(6),
    223
    224                    /** */
    225                    NOT_STARTED(7),
    226
    227                    /** */
    228                    HINT_IS_VIDEOCALL_RECEIVED(8),
    229
    230                    /** */
    231                    UNKNOWN(9),
    232
    233                    /** */
    234                    RENDERING(10),
    235
    236                    /** */
    237                    CHECKING_SUBSCRIPTION(11),
    238
    239                    /** */
    240                    SWITCHING_DEVICE(12);
    241
    242                    private static final Map<Integer,STATUS> lookup = new HashMap<Integer,STATUS>();
    243
    244                    static {
    245                            for(STATUS s : EnumSet.allOf(STATUS.class))
    246                                    lookup.put(s.getId(), s);
    247                    }
    248
    249                    private final int id;
    250
    251                    private STATUS(int value) {
    252                            this.id = value;
    253                    }
    254
    255                    public int getId() { return id; }
    256
    257                    public static STATUS get(int code) {
    258                            return lookup.get(code);
    259                    }
    260
    261                    public static STATUS fromString(String s) {
    262                            for (STATUS p : lookup.values()) {
    263                                    if (p.toString() == s) {
    264                                            return p;
    265                                    }
    266                            }
    267                            return null;
    268                    }
    269            }
    270
    271            /**
    272             */
    273            public enum MEDIATYPE {
    274
    275                    /** */
    276                    MEDIA_SCREENSHARING(1),
    277
    278                    /** */
    279                    MEDIA_VIDEO(0);
    280
    281                    private static final Map<Integer,MEDIATYPE> lookup = new HashMap<Integer,MEDIATYPE>();
    282
    283                    static {
    284                            for(MEDIATYPE s : EnumSet.allOf(MEDIATYPE.class))
    285                                    lookup.put(s.getId(), s);
    286                    }
    287
    288                    private final int id;
    289
    290                    private MEDIATYPE(int value) {
    291                            this.id = value;
    292                    }
    293
    294                    public int getId() { return id; }
    295
    296                    public static MEDIATYPE get(int code) {
    297                            return lookup.get(code);
    298                    }
    299
    300                    public static MEDIATYPE fromString(String s) {
    301                            for (MEDIATYPE p : lookup.values()) {
    302                                    if (p.toString() == s) {
    303                                            return p;
    304                                    }
    305                            }
    306                            return null;
    307                    }
    308            }
    309
    310            /**
    311             */
    312            public enum VIDEO_DEVICE_CAPABILITY {
    313
    314                    /** */
    315                    VIDEOCAP_HQ_CAPABLE(0),
    316
    317                    /** */
    318                    VIDEOCAP_HQ_CERTIFIED(1),
    319
    320                    /** */
    321                    VIDEOCAP_REQ_DRIVERUPDATE(2),
    322
    323                    /** */
    324                    VIDEOCAP_USB_HIGHSPEED(3);
    325
    326                    private static final Map<Integer,VIDEO_DEVICE_CAPABILITY> lookup = new HashMap<Integer,VIDEO_DEVICE_CAPABILITY>();
    327
    328                    static {
    329                            for(VIDEO_DEVICE_CAPABILITY s : EnumSet.allOf(VIDEO_DEVICE_CAPABILITY.class))
    330                                    lookup.put(s.getId(), s);
    331                    }
    332
    333                    private final int id;
    334
    335                    private VIDEO_DEVICE_CAPABILITY(int value) {
    336                            this.id = value;
    337                    }
    338
    339                    public int getId() { return id; }
    340
    341                    public static VIDEO_DEVICE_CAPABILITY get(int code) {
    342                            return lookup.get(code);
    343                    }
    344
    345                    public static VIDEO_DEVICE_CAPABILITY fromString(String s) {
    346                            for (VIDEO_DEVICE_CAPABILITY p : lookup.values()) {
    347                                    if (p.toString() == s) {
    348                                            return p;
    349                                    }
    350                            }
    351                            return null;
    352                    }
    353            }
    354
    355            /**
    356             * @param windowh
    357             */
    358            public void SetScreen( int windowh) {
    359
    360                    Request request = null;
    361                    try {
    362                            request = new XCallRequest(11,1);
    363                    } catch (IOException e) {
    364                            e.printStackTrace();
    365                            if (skype.errorListener != null)
    366                                    skype.errorListener.OnSkypeKitFatalError();
    367                    }
    368                    request.addParm('O',0,mObjectId);
    369                    request.addParm('u',1,windowh);
    370
    371                    skype.XCall((XCallRequest)request);
    372            }
    373
    374            /**
    375             *This method starts either video send or video receive, depending on whether the video object is sender or receiver. In case of desktop video, the receiver side needs to instantiate a renderer object and associate it with the receiveing video (Video.SetRemoteRendererId).  <br>
    376             */
    377            public void Start() {
    378
    379                    Request request = null;
    380                    try {
    381                            request = new XCallRequest(11,2);
    382                    } catch (IOException e) {
    383                            e.printStackTrace();
    384                            if (skype.errorListener != null)
    385                                    skype.errorListener.OnSkypeKitFatalError();
    386                    }
    387                    request.addParm('O',0,mObjectId);
    388
    389                    skype.XCall((XCallRequest)request);
    390            }
    391
    392            /**
    393             *This method stops either video send or video receive, depending on whether the video object is sender or receiver. In case of desktop video, the receiver side needs to dis-associate the video object from the renderer, by calling Video.SetRemoteRendererId(0).  <br>
    394             */
    395            public void Stop() {
    396
    397                    Request request = null;
    398                    try {
    399                            request = new XCallRequest(11,3);
    400                    } catch (IOException e) {
    401                            e.printStackTrace();
    402                            if (skype.errorListener != null)
    403                                    skype.errorListener.OnSkypeKitFatalError();
    404                    }
    405                    request.addParm('O',0,mObjectId);
    406
    407                    skype.XCall((XCallRequest)request);
    408            }
    409
    410            /**
    411             * @return SubmitCaptureRequestResult
    412             */
    413            public SubmitCaptureRequestResult SubmitCaptureRequest() {
    414
    415                    Request request = null;
    416                    try {
    417                            request = new XCallRequest(11,11);
    418                    } catch (IOException e) {
    419                            e.printStackTrace();
    420                            if (skype.errorListener != null)
    421                                    skype.errorListener.OnSkypeKitFatalError();
    422                    }
    423                    request.addParm('O',0,mObjectId);
    424
    425                    Response r = skype.XCall((XCallRequest)request);
    426
    427                    if (r.isErrCall())
    428                            return null;
    429
    430                    SubmitCaptureRequestResult result = new SubmitCaptureRequestResult();
    431
    432                    boolean ret = false;
    433                    ret = r.GetAsBoolean(1);
    434                    result.ret = ret;
    435
    436                    int requestId = 0;
    437                    requestId = r.GetAsInt(2);
    438                    result.requestId = requestId;
    439
    440                    return result;
    441            }
    442
    443            public class SubmitCaptureRequestResult {
    444                    public boolean ret;
    445                    public int requestId;
    446            }
    447
    448            /**
    449             *This method has no known effect in current version. <br>
    450             * @param x0
    451             * @param y0
    452             * @param width
    453             * @param height
    454             * @param monitorNumber
    455             * @param windowHandle
    456             */
    457            public void SetScreenCaptureRectangle( int x0, int y0, int width, int height, int monitorNumber, int windowHandle) {
    458
    459                    Request request = null;
    460                    try {
    461                            request = new XCallRequest(11,5);
    462                    } catch (IOException e) {
    463                            e.printStackTrace();
    464                            if (skype.errorListener != null)
    465                                    skype.errorListener.OnSkypeKitFatalError();
    466                    }
    467                    request.addParm('O',0,mObjectId);
    468                    request.addParm('i',1,x0);
    469                    request.addParm('i',2,y0);
    470                    request.addParm('u',3,width);
    471                    request.addParm('u',4,height);
    472                    request.addParm('i',5,monitorNumber);
    473                    request.addParm('u',6,windowHandle);
    474
    475                    skype.XCall((XCallRequest)request);
    476            }
    477
    478            /**
    479             * @param x0
    480             * @param y0
    481             * @param width
    482             * @param height
    483             */
    484            public void SetRenderRectangle( int x0, int y0, int width, int height) {
    485
    486                    Request request = null;
    487                    try {
    488                            request = new XCallRequest(11,6);
    489                    } catch (IOException e) {
    490                            e.printStackTrace();
    491                            if (skype.errorListener != null)
    492                                    skype.errorListener.OnSkypeKitFatalError();
    493                    }
    494                    request.addParm('O',0,mObjectId);
    495                    request.addParm('i',1,x0);
    496                    request.addParm('i',2,y0);
    497                    request.addParm('u',3,width);
    498                    request.addParm('u',4,height);
    499
    500                    skype.XCall((XCallRequest)request);
    501            }
    502
    503            /**
    504             *This method has no effect in current version. <br>
    505             * @param mediaType
    506             * @param webcamName
    507             * @param devicePath
    508             * @param updateSetup
    509             */
    510            public void SelectVideoSource( Video.MEDIATYPE mediaType, String webcamName, String devicePath, boolean updateSetup) {
    511
    512                    Request request = null;
    513                    try {
    514                            request = new XCallRequest(11,7);
    515                    } catch (IOException e) {
    516                            e.printStackTrace();
    517                            if (skype.errorListener != null)
    518                                    skype.errorListener.OnSkypeKitFatalError();
    519                    }
    520                    request.addParm('O',0,mObjectId);
    521                    request.addParm('e',1,mediaType.getId());
    522                    request.addParm('S',2,webcamName);
    523                    request.addParm('S',3,devicePath);
    524                    request.addParm('b',4,updateSetup);
    525
    526                    skype.XCall((XCallRequest)request);
    527            }
    528
    529            /**
    530             * @return GetCurrentVideoDeviceResult
    531             */
    532            public GetCurrentVideoDeviceResult GetCurrentVideoDevice() {
    533
    534                    Request request = null;
    535                    try {
    536                            request = new XCallRequest(11,10);
    537                    } catch (IOException e) {
    538                            e.printStackTrace();
    539                            if (skype.errorListener != null)
    540                                    skype.errorListener.OnSkypeKitFatalError();
    541                    }
    542                    request.addParm('O',0,mObjectId);
    543
    544                    Response r = skype.XCall((XCallRequest)request);
    545
    546                    if (r.isErrCall())
    547                            return null;
    548
    549                    GetCurrentVideoDeviceResult result = new GetCurrentVideoDeviceResult();
    550
    551                    MEDIATYPE mediatype = null;
    552                    mediatype = MEDIATYPE.get(r.GetAsInt(1));
    553                    result.mediatype = mediatype;
    554
    555                    String deviceName = null;
    556                    deviceName = r.GetAsString(2);
    557                    result.deviceName = deviceName;
    558
    559                    String devicePath = null;
    560                    devicePath = r.GetAsString(3);
    561                    result.devicePath = devicePath;
    562
    563                    return result;
    564            }
    565
    566            public class GetCurrentVideoDeviceResult {
    567                    public MEDIATYPE mediatype;
    568                    public String deviceName;
    569                    public String devicePath;
    570            }
    571
    572
    573    }