001/**
002 *
003 * Copyright 2003-2005 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingleold.packet;
018
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.Iterator;
022import java.util.List;
023
024import org.jivesoftware.smack.packet.ExtensionElement;
025
026import org.jivesoftware.smackx.jingleold.media.PayloadType;
027
028/**
029 * Jingle content description.
030 *
031 * @author Alvaro Saurin
032 */
033public abstract class JingleContentDescription implements ExtensionElement {
034
035    // static
036
037    public static final String NODENAME = "description";
038
039    // non-static
040
041    private final List<JinglePayloadType> payloads = new ArrayList<>();
042
043    /**
044     * Creates a content description..
045     */
046    public JingleContentDescription() {
047        super();
048    }
049
050    /**
051     * Returns the XML element name of the element.
052     *
053     * @return the XML element name of the element.
054     */
055    @Override
056    public String getElementName() {
057        return NODENAME;
058    }
059
060    /**
061     * Return the namespace.
062     *
063     * @return The namespace
064     */
065    @Override
066    public abstract String getNamespace();
067
068    /**
069     * Adds a audio payload type to the packet.
070     *
071     * @param pt the audio payload type to add.
072     */
073    public void addJinglePayloadType(final JinglePayloadType pt) {
074        synchronized (payloads) {
075            payloads.add(pt);
076        }
077    }
078
079    /**
080     * Adds a list of payloads to the packet.
081     *
082     * @param pts the payloads to add.
083     */
084    public void addAudioPayloadTypes(final List<PayloadType.Audio> pts) {
085        synchronized (payloads) {
086            Iterator<PayloadType.Audio> ptIter = pts.iterator();
087            while (ptIter.hasNext()) {
088                PayloadType.Audio pt = ptIter.next();
089                addJinglePayloadType(new JinglePayloadType.Audio(pt));
090            }
091        }
092    }
093
094    /**
095     * Returns an Iterator for the audio payloads in the packet.
096     *
097     * @return an Iterator for the audio payloads in the packet.
098     */
099    public Iterator<JinglePayloadType> getJinglePayloadTypes() {
100        return Collections.unmodifiableList(getJinglePayloadTypesList()).iterator();
101    }
102
103    /**
104     * Returns a list for the audio payloads in the packet.
105     *
106     * @return a list for the audio payloads in the packet.
107     */
108    public List<JinglePayloadType> getJinglePayloadTypesList() {
109        synchronized (payloads) {
110            return new ArrayList<>(payloads);
111        }
112    }
113
114    /**
115     * Return the list of Payload types contained in the description.
116     *
117     * @return a list of PayloadType.Audio
118     */
119    public List<PayloadType.Audio> getAudioPayloadTypesList() {
120        ArrayList<PayloadType.Audio> result = new ArrayList<>();
121        Iterator<JinglePayloadType> jinglePtsIter = getJinglePayloadTypes();
122
123        while (jinglePtsIter.hasNext()) {
124            JinglePayloadType jpt = jinglePtsIter.next();
125            if (jpt instanceof JinglePayloadType.Audio) {
126                JinglePayloadType.Audio jpta = (JinglePayloadType.Audio) jpt;
127                result.add((PayloadType.Audio) jpta.getPayloadType());
128            }
129        }
130
131        return result;
132    }
133
134    /**
135     * Returns a count of the audio payloads in the Jingle packet.
136     *
137     * @return the number of audio payloads in the Jingle packet.
138     */
139    public int getJinglePayloadTypesCount() {
140        synchronized (payloads) {
141            return payloads.size();
142        }
143    }
144
145    /**
146     * Convert a Jingle description to XML.
147     *
148     * @return a string with the XML representation
149     */
150    @Override
151    public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
152        StringBuilder buf = new StringBuilder();
153
154        synchronized (payloads) {
155            if (payloads.size() > 0) {
156                buf.append('<').append(getElementName());
157                buf.append(" xmlns=\"").append(getNamespace()).append("\" >");
158
159                Iterator<JinglePayloadType> pt = payloads.listIterator();
160                while (pt.hasNext()) {
161                    JinglePayloadType pte = pt.next();
162                    buf.append(pte.toXML());
163                }
164                buf.append("</").append(getElementName()).append('>');
165            }
166        }
167
168        return buf.toString();
169    }
170
171    /**
172     * Jingle audio description.
173     */
174    public static class Audio extends JingleContentDescription {
175
176        public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp";
177
178        public Audio() {
179            super();
180        }
181
182        /**
183         * Utility constructor, with a JinglePayloadType.
184         *
185         * @param pt the payload type.
186         */
187        @SuppressWarnings("this-escape")
188        public Audio(final JinglePayloadType pt) {
189            super();
190            addJinglePayloadType(pt);
191        }
192
193        @Override
194        public String getNamespace() {
195            return NAMESPACE;
196        }
197    }
198
199    /**
200     * A payload type, contained in a descriptor.
201     *
202     * @author Alvaro Saurin
203     */
204    public static class JinglePayloadType {
205
206        public static final String NODENAME = "payload-type";
207
208        private PayloadType payload;
209
210        /**
211         * Create a payload type.
212         *
213         * @param payload the payload
214         */
215        public JinglePayloadType(final PayloadType payload) {
216            super();
217            this.payload = payload;
218        }
219
220        /**
221         * Create an empty payload type.
222         */
223        public JinglePayloadType() {
224            this(null);
225        }
226
227        /**
228         * Returns the XML element name of the element.
229         *
230         * @return the XML element name of the element.
231         */
232        public static String getElementName() {
233            return NODENAME;
234        }
235
236        /**
237         * Get the payload represented.
238         *
239         * @return the payload
240         */
241        public PayloadType getPayloadType() {
242            return payload;
243        }
244
245        /**
246         * Set the payload represented.
247         *
248         * @param payload the payload to set
249         */
250        public void setPayload(final PayloadType payload) {
251            this.payload = payload;
252        }
253
254        protected String getChildAttributes() {
255            return null;
256        }
257
258        public String toXML() {
259            StringBuilder buf = new StringBuilder();
260
261            if (payload != null) {
262                buf.append('<').append(getElementName()).append(' ');
263
264                // We covert here the payload type to XML
265                if (payload.getId() != PayloadType.INVALID_PT) {
266                    buf.append(" id=\"").append(payload.getId()).append('"');
267                }
268                if (payload.getName() != null) {
269                    buf.append(" name=\"").append(payload.getName()).append('"');
270                }
271                if (payload.getChannels() != 0) {
272                    buf.append(" channels=\"").append(payload.getChannels()).append('"');
273                }
274                if (getChildAttributes() != null) {
275                    buf.append(getChildAttributes());
276                }
277                buf.append("/>");
278            }
279            return buf.toString();
280        }
281
282        /**
283         * Audio payload type element.
284         */
285        public static class Audio extends JinglePayloadType {
286            public Audio(final PayloadType.Audio audio) {
287                super(audio);
288            }
289
290            @Override
291            protected String getChildAttributes() {
292                StringBuilder buf = new StringBuilder();
293                PayloadType pt = getPayloadType();
294                if (pt instanceof PayloadType.Audio) {
295                    PayloadType.Audio pta = (PayloadType.Audio) pt;
296
297                    buf.append(" clockrate=\"").append(pta.getClockRate()).append("\" ");
298                }
299                return buf.toString();
300            }
301        }
302    }
303}