001/*
002 * Copyright (c) 2011-2017 Nexmo Inc
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020 * THE SOFTWARE.
021 */
022package com.nexmo.client.voice;
023
024
025import com.nexmo.client.*;
026import com.nexmo.client.voice.ncco.Ncco;
027
028/**
029 * A client for talking to the Nexmo Voice API. The standard way to obtain an instance of this class is to use {@link
030 * NexmoClient#getVoiceClient()}.
031 */
032public class VoiceClient extends AbstractClient {
033    protected final CallsEndpoint calls;
034    protected final StreamsEndpoint streams;
035    protected final TalkEndpoint talk;
036    protected final DtmfEndpoint dtmf;
037    protected final DownloadRecordingEndpoint downloadRecording;
038
039    /**
040     * Constructor.
041     *
042     * @param httpWrapper (required) shared HTTP wrapper object used for making REST calls.
043     */
044    public VoiceClient(HttpWrapper httpWrapper) {
045        super(httpWrapper);
046
047        calls = new CallsEndpoint(httpWrapper);
048        streams = new StreamsEndpoint(httpWrapper);
049        talk = new TalkEndpoint(httpWrapper);
050        dtmf = new DtmfEndpoint(httpWrapper);
051        downloadRecording = new DownloadRecordingEndpoint(httpWrapper);
052    }
053
054    /**
055     * Begin a call to a phone number.
056     *
057     * @param callRequest Describing the call to be made.
058     *
059     * @return A CallEvent describing the initial state of the call, containing the {@code uuid} required to interact
060     * with the ongoing phone call.
061     *
062     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
063     * @throws NexmoResponseParseException if the response from the API could not be parsed.
064     */
065    public CallEvent createCall(Call callRequest) throws NexmoResponseParseException, NexmoClientException {
066        return calls.post(callRequest);
067    }
068
069    /**
070     * Obtain the first page of CallInfo objects, representing the most recent calls initiated by {@link
071     * #createCall(Call)}.
072     *
073     * @return A CallInfoPage representing the response from the Nexmo Voice API.
074     *
075     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
076     * @throws NexmoResponseParseException if the response from the API could not be parsed.
077     */
078    public CallInfoPage listCalls() throws NexmoResponseParseException, NexmoClientException {
079        return this.listCalls(null);
080    }
081
082    /**
083     * Obtain the first page of CallInfo objects matching the query described by {@code filter}, representing the most
084     * recent calls initiated by {@link #createCall(Call)}.
085     *
086     * @param filter (optional) A filter describing which calls to be listed.
087     *
088     * @return A CallInfoPage representing the response from the Nexmo Voice API.
089     *
090     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
091     * @throws NexmoResponseParseException if the response from the API could not be parsed.
092     */
093    public CallInfoPage listCalls(CallsFilter filter) throws NexmoResponseParseException, NexmoClientException {
094        return calls.get(filter);
095    }
096
097    /**
098     * Look up the status of a single call initiated by {@link #createCall(Call)}.
099     *
100     * @param uuid (required) The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This
101     *             value can be obtained with {@link CallEvent#getUuid()}
102     *
103     * @return A CallInfo object, representing the response from the Nexmo Voice API.
104     *
105     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
106     * @throws NexmoResponseParseException if the response from the API could not be parsed.
107     */
108    public CallInfo getCallDetails(String uuid) throws NexmoResponseParseException, NexmoClientException {
109        return calls.get(uuid);
110    }
111
112    /**
113     * Send DTMF codes to an ongoing call.
114     *
115     * @param uuid   (required) The UUID of the call, obtained from the object returned by {@link #createCall(Call)}.
116     *               This value can be obtained with {@link CallEvent#getUuid()}
117     * @param digits (required) A string specifying the digits to be sent to the call. Valid characters are the digits
118     *               {@code 1-9</tt>, <tt>#</tt>, <tt>*</tt>, with the special character <tt>p} indicating a short pause
119     *               between tones.
120     *
121     * @return A CallInfo object, representing the response from the Nexmo Voice API.
122     *
123     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
124     * @throws NexmoResponseParseException if the response from the API could not be parsed.
125     */
126    public DtmfResponse sendDtmf(String uuid, String digits) throws NexmoResponseParseException, NexmoClientException {
127        return dtmf.put(uuid, digits);
128    }
129
130    /**
131     * Modify an ongoing call.
132     * <p>
133     * This method modifies an ongoing call, identified by "uuid". Modifications to the call can be one of:
134     * <ul>
135     * <li>Terminate the call (hangup)
136     * <li>Mute a call leg (mute)
137     * <li>Unmute a call leg (unmute)
138     * <li>Earmuff a call leg (earmuff)
139     * <li>Unearmuff a call leg (unearmuff)
140     * </ul>
141     *
142     * @param uuid   The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
143     *               can be obtained with {@link CallEvent#getUuid()}
144     * @param action One of: "hangup", "mute", "unmute", "earmuff", "unearmuff"
145     *
146     * @return A ModifyCallResponse object, representing the response from the Nexmo Voice API.
147     *
148     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
149     * @throws NexmoResponseParseException if the response from the API could not be parsed.
150     */
151    public ModifyCallResponse modifyCall(String uuid, ModifyCallAction action) throws NexmoResponseParseException, NexmoClientException {
152        return this.modifyCall(new CallModifier(uuid, action));
153    }
154
155    /**
156     * Modify an ongoing call using a CallModifier object.
157     * <p>
158     * In most cases, you will want to use {@link #modifyCall(String, ModifyCallAction)} or {@link #transferCall(String,
159     * String)} instead of this method.
160     *
161     * @param modifier A CallModifier describing the modification to be made.
162     *
163     * @return A ModifyCallResponse object, representing the response from the Nexmo Voice API.
164     *
165     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
166     * @throws NexmoResponseParseException if the response from the API could not be parsed.
167     */
168    public ModifyCallResponse modifyCall(CallModifier modifier) throws NexmoResponseParseException, NexmoClientException {
169        return calls.put(modifier);
170    }
171
172    /**
173     * Transfer a call to a different NCCO endpoint.
174     *
175     * @param uuid    The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
176     *                can be obtained with {@link CallEvent#getUuid()}
177     * @param nccoUrl The URL of the NCCO endpoint the call should be transferred to
178     *
179     * @return A ModifyCallResponse object, representing the response from the Nexmo Voice API.
180     *
181     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
182     * @throws NexmoResponseParseException if the response from the API could not be parsed.
183     */
184    public ModifyCallResponse transferCall(String uuid, String nccoUrl) throws NexmoResponseParseException, NexmoClientException {
185        return this.modifyCall(CallModifier.transferCall(uuid, nccoUrl));
186    }
187
188    /**
189     * Transfer a call to a different NCCO.
190     *
191     * @param uuid The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value can
192     *             be obtained with {@link CallEvent#getUuid()}
193     * @param ncco The new NCCO that will be used in the call.
194     *
195     * @return A ModifyCallResponse object, representing the response from the Nexmo Voice API.
196     *
197     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
198     * @throws NexmoResponseParseException if the response from the API could not be parsed.
199     */
200    public ModifyCallResponse transferCall(String uuid, Ncco ncco) throws NexmoResponseParseException, NexmoClientException {
201        return this.modifyCall(CallModifier.transferCall(uuid, ncco));
202    }
203
204    /**
205     * Stream audio to an ongoing call.
206     *
207     * @param uuid      The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
208     *                  can be obtained with {@link CallEvent#getUuid()}
209     * @param streamUrl A URL of an audio file in MP3 or 16-bit WAV format, to be streamed to the call.
210     * @param loop      The number of times to repeat the audio. The default value is {@code 1}, or you can use {@code
211     *                  0} to indicate that the audio should be repeated indefinitely.
212     *
213     * @return The data returned from the Voice API
214     *
215     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
216     * @throws NexmoResponseParseException if the response from the API could not be parsed.
217     */
218    public StreamResponse startStream(String uuid, String streamUrl, int loop) throws NexmoResponseParseException, NexmoClientException {
219        return streams.put(new StreamRequest(uuid, streamUrl, loop));
220    }
221
222    /**
223     * Stream audio to an ongoing call.
224     *
225     * @param uuid      The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
226     *                  can be obtained with {@link CallEvent#getUuid()}
227     * @param streamUrl A URL of an audio file in MP3 or 16-bit WAV format, to be streamed to the call.
228     *
229     * @return The data returned from the Voice API.
230     *
231     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
232     * @throws NexmoResponseParseException if the response from the API could not be parsed.
233     */
234    public StreamResponse startStream(String uuid, String streamUrl) throws NexmoResponseParseException, NexmoClientException {
235        return streams.put(new StreamRequest(uuid, streamUrl, 1));
236    }
237
238    /**
239     * Stop the audio being streamed into a call.
240     *
241     * @param uuid The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value can
242     *             be obtained with {@link CallEvent#getUuid()}
243     *
244     * @return The data returned from the Voice API
245     *
246     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
247     * @throws NexmoResponseParseException if the response from the API could not be parsed.
248     */
249    public StreamResponse stopStream(String uuid) throws NexmoResponseParseException, NexmoClientException {
250        return streams.delete(uuid);
251    }
252
253    /**
254     * Send a synthesized speech message to an ongoing call.
255     * <p>
256     * The message will only play once, spoken with the default voice of Kimberly.
257     *
258     * @param uuid The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value can
259     *             be obtained with {@link CallEvent#getUuid()}
260     * @param text The message to be spoken to the call participants.
261     *
262     * @return The data returned from the Voice API.
263     *
264     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
265     * @throws NexmoResponseParseException if the response from the API could not be parsed.
266     */
267    public TalkResponse startTalk(String uuid, String text) throws NexmoResponseParseException, NexmoClientException {
268        return talk.put(new TalkRequest(uuid, text));
269    }
270
271    /**
272     * Send a synthesized speech message to an ongoing call.
273     *
274     * @param uuid      The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
275     *                  can be obtained with {@link CallEvent#getUuid()}
276     * @param text      The message to be spoken to the call participants.
277     * @param voiceName The voice to be used to speak the message.
278     *
279     * @return The data returned from the Voice API.
280     *
281     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
282     * @throws NexmoResponseParseException if the response from the API could not be parsed.
283     */
284    public TalkResponse startTalk(String uuid, String text, VoiceName voiceName) throws NexmoResponseParseException, NexmoClientException {
285        return talk.put(new TalkRequest(uuid, text, voiceName));
286    }
287
288    /**
289     * Send a synthesized speech message to an ongoing call.
290     * <p>
291     * The message will be spoken with the default voice of Kimberly.
292     *
293     * @param uuid The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value can
294     *             be obtained with {@link CallEvent#getUuid()}
295     * @param text The message to be spoken to the call participants.
296     * @param loop The number of times to repeat the message. The default value is {@code 1}, or you can use {@code 0}
297     *             to indicate that the message should be repeated indefinitely.
298     *
299     * @return The data returned from the Voice API.
300     *
301     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
302     * @throws NexmoResponseParseException if the response from the API could not be parsed.
303     */
304    public TalkResponse startTalk(String uuid, String text, int loop) throws NexmoResponseParseException, NexmoClientException {
305        return talk.put(new TalkRequest(uuid, text, loop));
306    }
307
308    /**
309     * Send a synthesized speech message to an ongoing call.
310     *
311     * @param uuid      The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value
312     *                  can be obtained with {@link CallEvent#getUuid()}
313     * @param text      The message to be spoken to the call participants.
314     * @param voiceName The voice to be used to speak the message.
315     * @param loop      The number of times to repeat the message. The default value is {@code 1}, or you can use {@code
316     *                  0} to indicate that the message should be repeated indefinitely.
317     *
318     * @return The data returned from the Voice API.
319     *
320     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
321     * @throws NexmoResponseParseException if the response from the API could not be parsed.
322     */
323    public TalkResponse startTalk(String uuid, String text, VoiceName voiceName, int loop) throws NexmoResponseParseException, NexmoClientException {
324        return talk.put(new TalkRequest(uuid, text, voiceName, loop));
325    }
326
327    /**
328     * Stop the message being spoken into a call.
329     *
330     * @param uuid The UUID of the call, obtained from the object returned by {@link #createCall(Call)}. This value can
331     *             be obtained with {@link CallEvent#getUuid()}
332     *
333     * @return The data returned from the Voice API
334     *
335     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
336     * @throws NexmoResponseParseException if the response from the API could not be parsed.
337     */
338    public TalkResponse stopTalk(String uuid) throws NexmoResponseParseException, NexmoClientException {
339        return talk.delete(uuid);
340    }
341
342    /**
343     * Download a recording, given the recordingUrl provided from the webhook callback.
344     * <p>
345     * This returns a {@link Recording} object which can provide an InputStream of the byte data, or can be used to save
346     * directly to file.
347     *
348     * @param recordingUrl The recordingUrl provided by the webhook callback
349     *
350     * @return A Recording object, providing access to the recording's bytes
351     *
352     * @throws NexmoClientException        if there was a problem with the Nexmo request or response objects.
353     * @throws NexmoResponseParseException if the response from the API could not be parsed.
354     */
355    public Recording downloadRecording(String recordingUrl) throws NexmoResponseParseException, NexmoClientException {
356        return this.downloadRecording.execute(recordingUrl);
357    }
358}