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    }