1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* StreamInformation implementation */
18
19#include "sles_allinclusive.h"
20
21static XAresult IStreamInformation_QueryMediaContainerInformation( XAStreamInformationItf self,
22        XAMediaContainerInformation * info /* [out] */)
23{
24    XA_ENTER_INTERFACE
25
26    if (NULL == info) {
27        result = XA_RESULT_PARAMETER_INVALID;
28        XA_LEAVE_INTERFACE
29    }
30
31#ifdef ANDROID
32    IStreamInformation *thiz = (IStreamInformation *) self;
33    interface_lock_shared(thiz);
34    // always storing container info at index 0, as per spec
35    *info = thiz->mStreamInfoTable.itemAt(0).containerInfo;
36    interface_unlock_shared(thiz);
37    // even though the pointer to the media container info is returned, the values aren't set
38    //  for the actual container in this version, they are simply initialized to defaults
39    //  (see IStreamInformation_init)
40    result = XA_RESULT_SUCCESS;
41#else
42    SL_LOGE("QueryMediaContainerInformation is unsupported");
43    memset(info, 0, sizeof(XAMediaContainerInformation));
44    result = XA_RESULT_FEATURE_UNSUPPORTED;
45#endif
46
47    XA_LEAVE_INTERFACE
48}
49
50
51static XAresult IStreamInformation_QueryStreamType( XAStreamInformationItf self,
52        XAuint32 streamIndex, /* [in] */
53        XAuint32 *domain)     /* [out] */
54{
55    XA_ENTER_INTERFACE
56
57    if (NULL == domain) {
58        result = XA_RESULT_PARAMETER_INVALID;
59        XA_LEAVE_INTERFACE;
60    }
61
62#ifndef ANDROID
63    *domain = XA_DOMAINTYPE_UNKNOWN;
64#else
65    if (0 == streamIndex) {
66        // stream 0 is reserved for the container
67        result = XA_RESULT_PARAMETER_INVALID;
68        *domain = XA_DOMAINTYPE_UNKNOWN;
69    } else {
70        IStreamInformation *thiz = (IStreamInformation *) self;
71
72        interface_lock_shared(thiz);
73
74        XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
75        // streams in the container are numbered 1..nbStreams
76        if (streamIndex <= nbStreams) {
77            result = XA_RESULT_SUCCESS;
78            *domain = thiz->mStreamInfoTable.itemAt(streamIndex).domain;
79        } else {
80            SL_LOGE("Querying stream type for stream %d, only %d streams available",
81                    streamIndex, nbStreams);
82            result = XA_RESULT_PARAMETER_INVALID;
83        }
84
85        interface_unlock_shared(thiz);
86    }
87#endif
88
89    XA_LEAVE_INTERFACE
90}
91
92
93static XAresult IStreamInformation_QueryStreamInformation( XAStreamInformationItf self,
94        XAuint32 streamIndex, /* [in] */
95        void * info)          /* [out] */
96{
97    XA_ENTER_INTERFACE
98
99    if (NULL == info) {
100        result = XA_RESULT_PARAMETER_INVALID;
101    } else {
102
103#ifndef ANDROID
104        result = XA_RESULT_FEATURE_UNSUPPORTED;
105#else
106
107        IStreamInformation *thiz = (IStreamInformation *) self;
108
109        interface_lock_shared(thiz);
110
111        XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
112        // stream 0 is the container, and other streams in the container are numbered 1..nbStreams
113        if (streamIndex <= nbStreams) {
114            result = XA_RESULT_SUCCESS;
115            const StreamInfo& streamInfo = thiz->mStreamInfoTable.itemAt((size_t)streamIndex);
116
117            switch (streamInfo.domain) {
118            case XA_DOMAINTYPE_CONTAINER:
119                *(XAMediaContainerInformation *)info = streamInfo.containerInfo;
120                break;
121            case XA_DOMAINTYPE_AUDIO:
122                *(XAAudioStreamInformation *)info = streamInfo.audioInfo;
123                break;
124            case XA_DOMAINTYPE_VIDEO:
125                *(XAVideoStreamInformation *)info = streamInfo.videoInfo;
126                break;
127            case XA_DOMAINTYPE_IMAGE:
128                *(XAImageStreamInformation *)info = streamInfo.imageInfo;
129                break;
130            case XA_DOMAINTYPE_TIMEDTEXT:
131                *(XATimedTextStreamInformation *)info = streamInfo.textInfo;
132                break;
133            case XA_DOMAINTYPE_MIDI:
134                *(XAMIDIStreamInformation *)info = streamInfo.midiInfo;
135                break;
136            case XA_DOMAINTYPE_VENDOR:
137                *(XAVendorStreamInformation *)info = streamInfo.vendorInfo;
138                break;
139            default:
140                SL_LOGE("StreamInformation::QueryStreamInformation index %u has "
141                        "unknown domain %u", streamIndex, streamInfo.domain);
142                result = XA_RESULT_INTERNAL_ERROR;
143                break;
144            }
145
146        } else {
147            SL_LOGE("Querying stream type for stream %d, only %d streams available",
148                    streamIndex, nbStreams);
149            result = XA_RESULT_PARAMETER_INVALID;
150        }
151
152        interface_unlock_shared(thiz);
153#endif
154
155    }
156
157    XA_LEAVE_INTERFACE
158}
159
160
161static XAresult IStreamInformation_QueryStreamName( XAStreamInformationItf self,
162        XAuint32 streamIndex, /* [in] */
163        XAuint16 * pNameSize, /* [in/out] */
164        XAchar * pName)       /* [out] */
165{
166    XA_ENTER_INTERFACE
167
168    if (NULL == pNameSize || streamIndex == 0) {
169        result = XA_RESULT_PARAMETER_INVALID;
170    } else {
171#ifdef ANDROID
172        IStreamInformation *thiz = (IStreamInformation *) self;
173        interface_lock_shared(thiz);
174
175        XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
176        // streams in the container are numbered 1..nbStreams
177        if (streamIndex <= nbStreams) {
178            char streamName[16];        // large enough for the fixed format in next line
179            snprintf(streamName, sizeof(streamName), "stream%u", streamIndex);
180            size_t actualNameLength = strlen(streamName);
181            if (NULL == pName) {
182                // application is querying the name length in order to allocate a buffer
183                result = XA_RESULT_SUCCESS;
184            } else {
185                SLuint16 availableNameLength = *pNameSize;
186                if (actualNameLength > availableNameLength) {
187                    memcpy(pName, streamName, availableNameLength);
188                    result = XA_RESULT_BUFFER_INSUFFICIENT;
189                } else if (actualNameLength == availableNameLength) {
190                    memcpy(pName, streamName, availableNameLength);
191                    result = XA_RESULT_SUCCESS;
192                } else { // actualNameLength < availableNameLength
193                    memcpy(pName, streamName, actualNameLength + 1);
194                    result = XA_RESULT_SUCCESS;
195                }
196            }
197            *pNameSize = actualNameLength;
198        } else {
199            result = XA_RESULT_PARAMETER_INVALID;
200        }
201
202        interface_unlock_shared(thiz);
203#else
204        SL_LOGE("unsupported XAStreamInformationItf function");
205        result = XA_RESULT_FEATURE_UNSUPPORTED;
206#endif
207    }
208
209    XA_LEAVE_INTERFACE
210}
211
212
213static XAresult IStreamInformation_RegisterStreamChangeCallback( XAStreamInformationItf self,
214        xaStreamEventChangeCallback callback, /* [in] */
215        void * pContext)                      /* [in] */
216{
217    XA_ENTER_INTERFACE
218
219    IStreamInformation *thiz = (IStreamInformation *) self;
220
221    interface_lock_exclusive(thiz);
222
223    thiz->mCallback = callback;
224    thiz->mContext = pContext;
225    result = SL_RESULT_SUCCESS;
226
227    interface_unlock_exclusive(thiz);
228
229    XA_LEAVE_INTERFACE
230}
231
232
233static XAresult IStreamInformation_QueryActiveStreams( XAStreamInformationItf self,
234        XAuint32 *numStreams,      /* [in/out] */
235        XAboolean *activeStreams)  /* [out] */
236{
237    XA_ENTER_INTERFACE
238
239    if (NULL == numStreams) {
240        result = XA_RESULT_PARAMETER_INVALID;
241        XA_LEAVE_INTERFACE;
242    }
243
244#ifdef ANDROID
245    IStreamInformation *thiz = (IStreamInformation *) self;
246    interface_lock_shared(thiz);
247
248    result = XA_RESULT_SUCCESS;
249    *numStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
250    activeStreams = thiz->mActiveStreams;
251
252    interface_unlock_shared(thiz);
253#else
254    result = SL_RESULT_FEATURE_UNSUPPORTED;
255#endif
256
257    XA_LEAVE_INTERFACE
258}
259
260
261static XAresult IStreamInformation_SetActiveStream( XAStreamInformationItf self,
262        XAuint32   streamNum, /* [in] */
263        XAboolean  active,    /* [in] */
264        XAboolean  commitNow) /* [in] */
265{
266    XA_ENTER_INTERFACE
267
268    SL_LOGE("unsupported XAStreamInformationItf function");
269    result = XA_RESULT_FEATURE_UNSUPPORTED;
270
271    XA_LEAVE_INTERFACE
272}
273
274
275static const struct XAStreamInformationItf_ IStreamInformation_Itf = {
276    IStreamInformation_QueryMediaContainerInformation,
277    IStreamInformation_QueryStreamType,
278    IStreamInformation_QueryStreamInformation,
279    IStreamInformation_QueryStreamName,
280    IStreamInformation_RegisterStreamChangeCallback,
281    IStreamInformation_QueryActiveStreams,
282    IStreamInformation_SetActiveStream
283};
284
285
286void IStreamInformation_init(void *self)
287{
288    SL_LOGV("IStreamInformation_init\n");
289    IStreamInformation *thiz = (IStreamInformation *) self;
290    thiz->mItf = &IStreamInformation_Itf;
291
292    thiz->mCallback = NULL;
293    thiz->mContext = NULL;
294
295    for (int i=0 ; i < NB_SUPPORTED_STREAMS ; i++) {
296        thiz->mActiveStreams[i] = XA_BOOLEAN_FALSE;
297    }
298
299#ifdef ANDROID
300    // placement new constructor for C++ field within C struct
301    (void) new (&thiz->mStreamInfoTable) android::Vector<StreamInfo>();
302    // initialize container info
303    StreamInfo contInf;
304    contInf.domain = XA_DOMAINTYPE_CONTAINER;
305    contInf.containerInfo.containerType = XA_CONTAINERTYPE_UNSPECIFIED;
306    contInf.containerInfo.mediaDuration = XA_TIME_UNKNOWN;
307    // FIXME shouldn't this be 1 ?
308    contInf.containerInfo.numStreams = 0;
309    // always storing container info at index 0, as per spec: here, the table was still empty
310    thiz->mStreamInfoTable.add(contInf);
311#endif
312}
313
314
315void IStreamInformation_deinit(void *self) {
316#ifdef ANDROID
317    IStreamInformation *thiz = (IStreamInformation *) self;
318    // explicit destructor
319    thiz->mStreamInfoTable.~Vector<StreamInfo>();
320#endif
321}
322