10b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/*
20b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
30b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
40b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
50b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * you may not use this file except in compliance with the License.
60b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * You may obtain a copy of the License at
70b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
80b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
90b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Unless required by applicable law or agreed to in writing, software
110b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
120b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * See the License for the specific language governing permissions and
140b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * limitations under the License.
150b167267bda99b68346045ccab14e810121d5de4Glenn Kasten */
160b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/* BufferQueue implementation */
180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#include "sles_allinclusive.h"
200b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
21ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten/** Determine the state of the audio player or audio recorder associated with a buffer queue.
234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten *  Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING).
244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten */
254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
26bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenstatic SLuint32 getAssociatedState(IBufferQueue *thiz)
274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten{
284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    SLuint32 state;
29bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    switch (InterfaceToObjectID(thiz)) {
304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    case SL_OBJECTID_AUDIOPLAYER:
31bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState;
324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        break;
334b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    case SL_OBJECTID_AUDIORECORDER:
34bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        state = ((CAudioRecorder *) thiz->mThis)->mRecord.mState;
354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        break;
364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    default:
374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // unreachable, but just in case we will assume it is stopped
384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        assert(SL_BOOLEAN_FALSE);
394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        state = SL_PLAYSTATE_STOPPED;
404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        break;
414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    }
424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    return state;
434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten}
444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
46e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn KastenSLresult IBufferQueue_Enqueue(SLBufferQueueItf self, const void *pBuffer, SLuint32 size)
470b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
48ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
49a8179ea15c4ff78db589d742b135649f0eda7ef2Glenn Kasten    //SL_LOGV("IBufferQueue_Enqueue(%p, %p, %u)", self, pBuffer, size);
50ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // Note that Enqueue while a Clear is pending is equivalent to Enqueue followed by Clear
524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
53ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pBuffer || 0 == size) {
54ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
550b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    } else {
56bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IBufferQueue *thiz = (IBufferQueue *) self;
57bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
58bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        BufferHeader *oldRear = thiz->mRear, *newRear;
59bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if ((newRear = oldRear + 1) == &thiz->mArray[thiz->mNumBuffers + 1]) {
60bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            newRear = thiz->mArray;
61a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        }
62bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (newRear == thiz->mFront) {
63ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_BUFFER_INSUFFICIENT;
64ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
65ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            oldRear->mBuffer = pBuffer;
66ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            oldRear->mSize = size;
67bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mRear = newRear;
68bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            ++thiz->mState.count;
69ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_SUCCESS;
70ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
72bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
73bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
74d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi            ATTR_BQ_ENQUEUE : ATTR_NONE);
750b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    }
76ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
770b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
780b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
79ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
80e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn KastenSLresult IBufferQueue_Clear(SLBufferQueueItf self)
810b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
82ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
83ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    result = SL_RESULT_SUCCESS;
85bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IBufferQueue *thiz = (IBufferQueue *) self;
86bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
88ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
89bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
90bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // flush associated audio player
920ac71cb5890738ea93c26a9f567be2b523235c64Jean-Michel Trivi        result = android_audioPlayer_bufferQueue_onClear(audioPlayer);
934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (SL_RESULT_SUCCESS == result) {
94bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mFront = &thiz->mArray[0];
95bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mRear = &thiz->mArray[0];
96bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mState.count = 0;
97bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mState.playIndex = 0;
98bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mSizeConsumed = 0;
994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
1004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    }
1014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef USE_OUTPUTMIXEXT
1044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // mixer might be reading from the front buffer, so tread carefully here
1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // NTH asynchronous cancel instead of blocking until mixer acknowledges
106bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mClearRequested = SL_BOOLEAN_TRUE;
107a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    do {
108bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_cond_wait(thiz);
109bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    } while (thiz->mClearRequested);
1106a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi#endif
1114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
112bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_unlock_exclusive(thiz);
113ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
114ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1150b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1160b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
118ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kastenstatic SLresult IBufferQueue_GetState(SLBufferQueueItf self, SLBufferQueueState *pState)
1190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
120ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
1234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
124ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pState) {
125ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
126ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
127bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IBufferQueue *thiz = (IBufferQueue *) self;
128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLBufferQueueState state;
129bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_shared(thiz);
1300b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#ifdef __cplusplus // FIXME Is this a compiler bug?
131bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        state.count = thiz->mState.count;
132bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        state.playIndex = thiz->mState.playIndex;
1330b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#else
134bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        state = thiz->mState;
1350b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#endif
136bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_shared(thiz);
137ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pState = state;
138ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
139ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
140ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1420b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1430b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
144ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
145e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn KastenSLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self,
1460b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    slBufferQueueCallback callback, void *pContext)
1470b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
148ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
149ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
150bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IBufferQueue *thiz = (IBufferQueue *) self;
151bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
1524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
153bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
154bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mCallback = callback;
155bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mContext = pContext;
1564b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        result = SL_RESULT_SUCCESS;
1574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    } else {
1584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        result = SL_RESULT_PRECONDITIONS_VIOLATED;
1594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    }
160bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_unlock_exclusive(thiz);
161ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
162ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1630b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1640b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
165ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1660b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic const struct SLBufferQueueItf_ IBufferQueue_Itf = {
1670b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_Enqueue,
1680b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_Clear,
1690b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_GetState,
1700b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_RegisterCallback
1710b167267bda99b68346045ccab14e810121d5de4Glenn Kasten};
1720b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
1730b167267bda99b68346045ccab14e810121d5de4Glenn Kastenvoid IBufferQueue_init(void *self)
1740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
175bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IBufferQueue *thiz = (IBufferQueue *) self;
176bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IBufferQueue_Itf;
177bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState.count = 0;
178bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState.playIndex = 0;
179bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = NULL;
180bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = NULL;
181bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mNumBuffers = 0;
182bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mClearRequested = SL_BOOLEAN_FALSE;
183bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mArray = NULL;
184bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFront = NULL;
185bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mRear = NULL;
1864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef ANDROID
187bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mSizeConsumed = 0;
1884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
189bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    BufferHeader *bufferHeader = thiz->mTypical;
1900b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    unsigned i;
1910b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    for (i = 0; i < BUFFER_HEADER_TYPICAL+1; ++i, ++bufferHeader) {
1920b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        bufferHeader->mBuffer = NULL;
1930b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        bufferHeader->mSize = 0;
1940b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    }
1950b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
196a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
197a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
198a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten/** \brief Interface deinitialization hook called by IObject::Destroy.
199a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten *  Free the buffer queue, if it was larger than typical.
200a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten */
201a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
202a9a70a4451545034c9263dd55b181f2912534c37Glenn Kastenvoid IBufferQueue_deinit(void *self)
203a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{
204bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IBufferQueue *thiz = (IBufferQueue *) self;
205bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if ((NULL != thiz->mArray) && (thiz->mArray != thiz->mTypical)) {
206bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        free(thiz->mArray);
207bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mArray = NULL;
208a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    }
209a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten}
210