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 /** DEPRECATED: 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 }