    001    package com.skype.api;
    002
    003    import java.io.IOException;
    004    import java.util.*;
    005    import com.skype.ipc.*;
    006    /**
    007     * Wrapper class that includes voicemail-specific methods and properties. In the Skype Conversation API, Voicemail is actually something of a misnomer for what would be more accurately called Voice Message. <br><br>The traditional Voicemail use case involves recording a voice message when an incoming call does not get answered in a pre-determined amount of time. In the Skype Conversation API, voicemail does not depend on a call going unanswered - you can post a voice message asynchronously into any dialog conversation at any time. <br><br>In fact, a high-level action flow directing unanswered incoming live sessions to voicemail is not something provided by the Conversation API - implementation of this use case is largely up to your UI. <br><br>The fact that your UI must retrieve incoming Voicemails by monitoring changes to a Conversation instance's Messages illustrates this conceptual difference between traditional voicemail and voice messages. The message type Message.POSTED_VOICE_MESSAGE indicates that a Message instance should be handled as a voice message instead of by displaying its body text in the Conversation UI. Message.GetVoiceMessage enables you to retrieve the associated Voicemail instance; Voicemail.StartPlayback enables you to listen to the message audio. <br><br>To put it another way, the object chain goes like this:  <br>@code <br>Contact->Conversation->Message->Voicemail  <br></CODE>  <br><br>There are three basic types of Voicemail objects: <br> - INCOMING - received voice messages that can be retrieved from Message objects; <br> - OUTGOING - outbound voice messages that can be created with Conversation.StartVoiceMessage; <br> - GREETING - voice messages that represent auto-answer greetings, either recorded by the user (CUSTOM_GREETING) or included as part of SkypeKit (DEFAULT_GREETING). This is the audio that gets played back to sender of the voice message before he can start recording his voice message. <br><br>Before trying to send out a voicemail, you should ensure that target Contact has the capability to receive them. Use Contact.GetCapabilityStatus to check for Contact.CAPABILITY_CAN_BE_SENT_VM. <br><br>Recording and Sending a Voice Message <br><br>The first step is to obtain a dialog Conversation with the target Contact. In that conversation, you can initiate the outgoing voice message with Conversation.StartVoiceMessage <br><br>Note that this call does not return an actual Voicemail object. To catch when an object gets created, you will need to check Conversation.P_ACTIVE_VM_ID property updates. <br><br>After invoking Conversation.StartVoiceMessage, SkypeKit instantiates a Voicemail instance for the target Contact's greeting (with type CUSTOM_GREETING or DEFAULT_GREETING). At this point, the Conversation.P_ACTIVE_VM_ID property update fires, newVM contains a reference to the greeting, and playback of the greeting for the sender starts automatically.  <br><br>Once the greeting playback finishes, SkypeKit instantiates a second Voicemail instance for the outgoing voice message. At this point, the Conversation.P_ACTIVE_VM_ID property update fires again, newVM now contains a reference to the outgoing message, and recording starts automatically. If you want to include notification and/or error handling for whether this message was sent successfully, you should make a copy of newVM now. <br><br>Once the user finishes (or abandons) recording of their message, they want to either send the message or to cancel it. To send the message, use Conversation.PostVoiceMessage; to cancel the message, use Conversation.LeaveLiveSession. <br><br>Both of these actions results in the Conversation.P_ACTIVE_VM_ID property update firing for a third time, setting the value to NULL. However, the Voicemail object will actually continue its existence past this point. Saving a reference to the message's Voicemail object when you start recording it enables you to keep receiving Voicemail property updates. This in turn enables your UI to check whether voice message send succeeded or failed. <br><br>The relevant terminal state Voicemail.P_STATUS property values are: <br> - Voicemail.CANCELLED - recording and/or sending of this message was cancelled <br> - Voicemail.UPLOADED - message sent <br> - Voicemail.FAILED - message could not be sent <br><br>Receiving and Playing Back a Voice Message <br><br>On the remote side, the Voicemail appears as a Message object of type Message.POSTED_VOICE_MESSAGE. The message's author property contains the Skype Name of the Voicemail originator, and its BodyXml property contains the message length and title text in following format: <br><br>@code <br><voicemail alt="Sent voicemail to people in this conversation."><message length="5" ></message></voicemail>  <br></CODE> <br><br>Receiver side UI can then retrieve the Voicemail object from the message with Message.GetVoiceMessage and <br>start local playback with Message.StartPlayback. <br>
    008     */
    009
    010
    011    public class Voicemail extends SkypeObject {
    012
    013
    014            public interface VoicemailListener {
    015                    /** This event gets called when there are changes to Voicemail properties defined in Voicemail.PROPERTY  */
    016                    public void OnPropertyChange(SkypeObject obj, PROPERTY prop, Object value);
    017
    018            }
    019
    020            public Voicemail(int oid, Skype skype) {
    021                    super(oid,skype);
    022            }
    023
    024            private static final int MODULE_ID = 7;
    025
    026            public static final int moduleID() {
    027                    return MODULE_ID;
    028            }
    029
    030            /** Properties of the Voicemail class */
    031            public enum PROPERTY {
    032
    033                    /** type: TYPE */
    034                    type(100),
    035
    036                    /** registered username of the other party, type: String */
    037                    partner_handle(101),
    038
    039                    /** user's display name of the other party, type: String */
    040                    partner_dispname(102),
    041
    042                    /** type: STATUS */
    043                    status(103),
    044
    045                    /** type: FAILUREREASON */
    046                    failurereason(104),
    047
    048                    /** subject line, type: String */
    049                    subject(105),
    050
    051                    /** timestamp of creation, type: int */
    052                    timestamp(106),
    053
    054                    /** duration in seconds, type: int */
    055                    duration(107),
    056
    057                    /** max allowed duration in seconds, type: int */
    058                    allowed_duration(108),
    059
    060                    /** VM playback progress in seconds, type: int */
    061                    playback_progress(109),
    062
    063                    /** CONVERSATION_ID of corresponding conversation, type: Conversation */
    064                    convo_id(830),
    065
    066                    /** GUID of the message that the VM is tied to, type: byte[] */
    067                    chatmsg_guid(831);
    068
    069                    private static final Map<Integer,PROPERTY> lookup = new HashMap<Integer,PROPERTY>();
    070
    071                    static {
    072                            for(PROPERTY s : EnumSet.allOf(PROPERTY.class))
    073                                    lookup.put(s.getId(), s);
    074                    }
    075
    076                    private final int id;
    077
    078                    private PROPERTY(int value) {
    079                            this.id = value;
    080                    }
    081
    082                    public int getId() { return id; }
    083
    084                    public static PROPERTY get(int code) {
    085                            return lookup.get(code);
    086                    }
    087
    088                    public static PROPERTY fromString(String s) {
    089                            for (PROPERTY p : lookup.values()) {
    090                                    if (p.toString() == s) {
    091                                            return p;
    092                                    }
    093                            }
    094                            return null;
    095                    }
    096            }
    097
    098            public Object GetPropertyAsEnum(int propid) {
    099                    return PROPERTY.get(propid);
    100            }
    101
    102            public String GetStrProperty(PROPERTY prop) {
    103                    //check in propcache if so then return
    104                    if (mPropCache.containsKey(new Integer(prop.id))){
    105                            String value =  (String)mPropCache.get(prop.id);
    106                            if (value != null && !(value.length() == 0) ){
    107                                    return value;
    108                            }
    109                    }
    110                    //else get from skypekit...
    111                    GetPropertyRequest request = new GetPropertyRequest(7, mObjectId, prop.id);
    112
    113                    String string = null;
    114                    GetPropertyResponse r = skype.GetProperty(request);
    115                    if (r != null){
    116                            string = r.GetAsString();
    117                    }
    118
    119                    if (string != null)
    120                    {
    121                            mPropCache.put(new Integer(prop.id), string);
    122                    }
    123                    return string;
    124            }
    125
    126            public int GetIntProperty(PROPERTY prop) {
    127                    //check in propcache if so then return
    128                    if (mPropCache.containsKey(new Integer(prop.id))){
    129                            int value = ((Integer)mPropCache.get(prop.id)).intValue();
    130                            if (value != 0){
    131                                    return value;
    132                            }
    133                    }
    134                    //else get from skypekit...
    135                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
    136
    137                    Integer integer = null;
    138                    GetPropertyResponse r = skype.GetProperty(request);
    139                    if (r != null){
    140                            integer  = r.GetAsInt();
    141                    }
    142
    143                    if (integer != null)
    144                    {
    145                            mPropCache.put(new Integer(prop.id), integer);
    146                            return integer.intValue();
    147                    }
    148                    else
    149                    {
    150                            return 0;
    151                    }
    152            }
    153
    154            public boolean GetBooleanProperty(PROPERTY prop) {
    155                    //check in propcache if so then return
    156                    if (mPropCache.containsKey(new Integer(prop.id))){
    157                            return ((Boolean)mPropCache.get(prop.id)).booleanValue();
    158                    }
    159                    //else get from skypekit...
    160                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
    161
    162                    Boolean boolResp = null;
    163                    GetPropertyResponse r = skype.GetProperty(request);
    164                    if (r != null){
    165                            boolResp  = r.GetAsBoolean();
    166                    }
    167
    168                    if (boolResp != null)
    169                    {
    170                            mPropCache.put(new Integer(prop.id), boolResp);
    171                            return boolResp.booleanValue();
    172                    }
    173                    else
    174                    {
    175                            return false;
    176                    }
    177            }
    178
    179            public byte [] GetBinProperty(PROPERTY prop) {
    180                    //get from skypekit...
    181                    GetPropertyRequest request = new GetPropertyRequest(7, mObjectId, prop.id);
    182
    183                    byte [] data = null;
    184                    GetPropertyResponse r = skype.GetProperty(request);
    185                    if (r != null) {
    186                            data = r.GetAsBinary();
    187                    }
    188                    return data;
    189            }
    190
    191            /**
    192             */
    193            public enum TYPE {
    194
    195                    /** */
    196                    INCOMING(1),
    197
    198                    /** */
    199                    DEFAULT_GREETING(4),
    200
    201                    /** */
    202                    CUSTOM_GREETING(2),
    203
    204                    /** */
    205                    OUTGOING(3);
    206
    207                    private static final Map<Integer,TYPE> lookup = new HashMap<Integer,TYPE>();
    208
    209                    static {
    210                            for(TYPE s : EnumSet.allOf(TYPE.class))
    211                                    lookup.put(s.getId(), s);
    212                    }
    213
    214                    private final int id;
    215
    216                    private TYPE(int value) {
    217                            this.id = value;
    218                    }
    219
    220                    public int getId() { return id; }
    221
    222                    public static TYPE get(int code) {
    223                            return lookup.get(code);
    224                    }
    225
    226                    public static TYPE fromString(String s) {
    227                            for (TYPE p : lookup.values()) {
    228                                    if (p.toString() == s) {
    229                                            return p;
    230                                    }
    231                            }
    232                            return null;
    233                    }
    234            }
    235
    236            /**
    237             */
    238            public enum STATUS {
    239
    240                    /** */
    241                    NOTDOWNLOADED(1),
    242
    243                    /** */
    244                    DOWNLOADING(2),
    245
    246                    /** */
    247                    UNPLAYED(3),
    248
    249                    /** */
    250                    BUFFERING(4),
    251
    252                    /** */
    253                    PLAYING(5),
    254
    255                    /** */
    256                    PLAYED(6),
    257
    258                    /** */
    259                    BLANK(7),
    260
    261                    /** */
    262                    RECORDING(8),
    263
    264                    /** */
    265                    RECORDED(9),
    266
    267                    /** */
    268                    UPLOADING(10),
    269
    270                    /** */
    271                    UPLOADED(11),
    272
    273                    /** */
    274                    DELETING(12),
    275
    276                    /** */
    277                    FAILED(13),
    278
    279                    /** */
    280                    DELETING_FAILED(14),
    281
    282                    /** */
    283                    CHECKING(15),
    284
    285                    /** */
    286                    CANCELLED(16);
    287
    288                    private static final Map<Integer,STATUS> lookup = new HashMap<Integer,STATUS>();
    289
    290                    static {
    291                            for(STATUS s : EnumSet.allOf(STATUS.class))
    292                                    lookup.put(s.getId(), s);
    293                    }
    294
    295                    private final int id;
    296
    297                    private STATUS(int value) {
    298                            this.id = value;
    299                    }
    300
    301                    public int getId() { return id; }
    302
    303                    public static STATUS get(int code) {
    304                            return lookup.get(code);
    305                    }
    306
    307                    public static STATUS fromString(String s) {
    308                            for (STATUS p : lookup.values()) {
    309                                    if (p.toString() == s) {
    310                                            return p;
    311                                    }
    312                            }
    313                            return null;
    314                    }
    315            }
    316
    317            /**
    318             */
    319            public enum FAILUREREASON {
    320
    321                    /** */
    322                    MISC_ERROR(1),
    323
    324                    /** */
    325                    CONNECT_ERROR(2),
    326
    327                    /** */
    328                    NO_VOICEMAIL_CAPABILITY(3),
    329
    330                    /** */
    331                    NO_SUCH_VOICEMAIL(4),
    332
    333                    /** */
    334                    FILE_READ_ERROR(5),
    335
    336                    /** */
    337                    FILE_WRITE_ERROR(6),
    338
    339                    /** */
    340                    RECORDING_ERROR(7),
    341
    342                    /** */
    343                    PLAYBACK_ERROR(8),
    344
    345                    /** */
    346                    NO_PERMISSION(9),
    347
    348                    /** receiver turned off voicemail*/
    349                    RECEIVER_DISABLED_VOICEMAIL(10),
    350
    351                    /** receiver has not authorized you and privacy is not set to anyone*/
    352                    SENDER_NOT_AUTHORIZED(11),
    353
    354                    /** receiver blocked sender*/
    355                    SENDER_BLOCKED(12);
    356
    357                    private static final Map<Integer,FAILUREREASON> lookup = new HashMap<Integer,FAILUREREASON>();
    358
    359                    static {
    360                            for(FAILUREREASON s : EnumSet.allOf(FAILUREREASON.class))
    361                                    lookup.put(s.getId(), s);
    362                    }
    363
    364                    private final int id;
    365
    366                    private FAILUREREASON(int value) {
    367                            this.id = value;
    368                    }
    369
    370                    public int getId() { return id; }
    371
    372                    public static FAILUREREASON get(int code) {
    373                            return lookup.get(code);
    374                    }
    375
    376                    public static FAILUREREASON fromString(String s) {
    377                            for (FAILUREREASON p : lookup.values()) {
    378                                    if (p.toString() == s) {
    379                                            return p;
    380                                    }
    381                            }
    382                            return null;
    383                    }
    384            }
    385
    386            /**
    387             *Start recording your own auto-answer greeting message (leave message after the beep...) only. Recording of outgoing Voicemail messages start automatically (using Conversation.StartVoiceMessage) after playback of the remote side greeting message has finished. <br>
    388             */
    389            public void StartRecording() {
    390
    391                    Request request = null;
    392                    try {
    393                            request = new XCallRequest(7,3);
    394                    } catch (IOException e) {
    395                            e.printStackTrace();
    396                            if (skype.errorListener != null)
    397                                    skype.errorListener.OnSkypeKitFatalError();
    398                    }
    399                    request.addParm('O',0,mObjectId);
    400
    401                    skype.XCall((XCallRequest)request);
    402            }
    403
    404            /**
    405             *Stop recording of your own auto-answer greeting message only. To stop recording of and send an outgoing Voicemail, use Conversation.PostVoiceMessage. <br>
    406             */
    407            public void StopRecording() {
    408
    409                    Request request = null;
    410                    try {
    411                            request = new XCallRequest(7,4);
    412                    } catch (IOException e) {
    413                            e.printStackTrace();
    414                            if (skype.errorListener != null)
    415                                    skype.errorListener.OnSkypeKitFatalError();
    416                    }
    417                    request.addParm('O',0,mObjectId);
    418
    419                    skype.XCall((XCallRequest)request);
    420            }
    421
    422            /**
    423             *Initiates playback of a voice message <br>
    424             */
    425            public void StartPlayback() {
    426
    427                    Request request = null;
    428                    try {
    429                            request = new XCallRequest(7,5);
    430                    } catch (IOException e) {
    431                            e.printStackTrace();
    432                            if (skype.errorListener != null)
    433                                    skype.errorListener.OnSkypeKitFatalError();
    434                    }
    435                    request.addParm('O',0,mObjectId);
    436
    437                    skype.XCall((XCallRequest)request);
    438            }
    439
    440            /**
    441             *Terminates playback of a voice message <br>
    442             */
    443            public void StopPlayback() {
    444
    445                    Request request = null;
    446                    try {
    447                            request = new XCallRequest(7,6);
    448                    } catch (IOException e) {
    449                            e.printStackTrace();
    450                            if (skype.errorListener != null)
    451                                    skype.errorListener.OnSkypeKitFatalError();
    452                    }
    453                    request.addParm('O',0,mObjectId);
    454
    455                    skype.XCall((XCallRequest)request);
    456            }
    457
    458            /**
    459             *first from server, and then the local copy
    460             */
    461            public void Delete() {
    462
    463                    Request request = null;
    464                    try {
    465                            request = new XCallRequest(7,7);
    466                    } catch (IOException e) {
    467                            e.printStackTrace();
    468                            if (skype.errorListener != null)
    469                                    skype.errorListener.OnSkypeKitFatalError();
    470                    }
    471                    request.addParm('O',0,mObjectId);
    472
    473                    skype.XCall((XCallRequest)request);
    474            }
    475
    476            /**
    477             *Canceling recording of your own auto-answer greeting message. To stop recording of and cancel an outgoing Voicemail, use Conversation.LeaveLiveSession. <br>
    478             */
    479            public void Cancel() {
    480
    481                    Request request = null;
    482                    try {
    483                            request = new XCallRequest(7,8);
    484                    } catch (IOException e) {
    485                            e.printStackTrace();
    486                            if (skype.errorListener != null)
    487                                    skype.errorListener.OnSkypeKitFatalError();
    488                    }
    489                    request.addParm('O',0,mObjectId);
    490
    491                    skype.XCall((XCallRequest)request);
    492            }
    493
    494            /**
    495             *check if we can send voicemail (unauth,blocked,no priv etc cases). only OUTGOING
    496             * @return result
    497             */
    498            public boolean CheckPermission() {
    499
    500                    Request request = null;
    501                    try {
    502                            request = new XCallRequest(7,13);
    503                    } catch (IOException e) {
    504                            e.printStackTrace();
    505                            if (skype.errorListener != null)
    506                                    skype.errorListener.OnSkypeKitFatalError();
    507                    }
    508                    request.addParm('O',0,mObjectId);
    509
    510                    Response r = skype.XCall((XCallRequest)request);
    511
    512                    if (r.isErrCall())
    513                            return false;
    514
    515                    boolean result = false;
    516                    result = r.GetAsBoolean(1);
    517                    return result;
    518            }
    519
    520
    521    }