1/*
2 * Copyright (C) 2010 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/* Record implementation */
18
19#include "sles_allinclusive.h"
20
21
22static SLresult IRecord_SetRecordState(SLRecordItf self, SLuint32 state)
23{
24    SL_ENTER_INTERFACE
25
26    switch (state) {
27    case SL_RECORDSTATE_STOPPED:
28    case SL_RECORDSTATE_PAUSED:
29    case SL_RECORDSTATE_RECORDING:
30        {
31        IRecord *thiz = (IRecord *) self;
32        interface_lock_exclusive(thiz);
33        thiz->mState = state;
34#ifdef ANDROID
35        android_audioRecorder_setRecordState(InterfaceToCAudioRecorder(thiz), state);
36#endif
37        interface_unlock_exclusive(thiz);
38        result = SL_RESULT_SUCCESS;
39        }
40        break;
41    default:
42        result = SL_RESULT_PARAMETER_INVALID;
43        break;
44    }
45
46    SL_LEAVE_INTERFACE
47}
48
49
50static SLresult IRecord_GetRecordState(SLRecordItf self, SLuint32 *pState)
51{
52    SL_ENTER_INTERFACE
53
54    IRecord *thiz = (IRecord *) self;
55    if (NULL == pState) {
56        result = SL_RESULT_PARAMETER_INVALID;
57    } else {
58        interface_lock_shared(thiz);
59        SLuint32 state = thiz->mState;
60        interface_unlock_shared(thiz);
61        *pState = state;
62        result = SL_RESULT_SUCCESS;
63    }
64
65    SL_LEAVE_INTERFACE
66}
67
68
69static SLresult IRecord_SetDurationLimit(SLRecordItf self, SLmillisecond msec)
70{
71    SL_ENTER_INTERFACE
72
73    IRecord *thiz = (IRecord *) self;
74    interface_lock_exclusive(thiz);
75    if (thiz->mDurationLimit != msec) {
76        thiz->mDurationLimit = msec;
77        interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
78    } else {
79        interface_unlock_exclusive(thiz);
80    }
81    result = SL_RESULT_SUCCESS;
82
83    SL_LEAVE_INTERFACE
84}
85
86
87static SLresult IRecord_GetPosition(SLRecordItf self, SLmillisecond *pMsec)
88{
89    SL_ENTER_INTERFACE
90
91    if (NULL == pMsec) {
92        result = SL_RESULT_PARAMETER_INVALID;
93    } else {
94        IRecord *thiz = (IRecord *) self;
95        SLmillisecond position;
96        interface_lock_shared(thiz);
97#ifdef ANDROID
98        // Android does not use the mPosition field for audio recorders
99        if (SL_OBJECTID_AUDIORECORDER == InterfaceToObjectID(thiz)) {
100            android_audioRecorder_getPosition(InterfaceToCAudioRecorder(thiz), &position);
101        } else {
102            position = thiz->mPosition;
103        }
104#else
105        position = thiz->mPosition;
106#endif
107        interface_unlock_shared(thiz);
108        *pMsec = position;
109        result = SL_RESULT_SUCCESS;
110    }
111
112    SL_LEAVE_INTERFACE
113}
114
115
116static SLresult IRecord_RegisterCallback(SLRecordItf self, slRecordCallback callback,
117    void *pContext)
118{
119    SL_ENTER_INTERFACE
120
121    IRecord *thiz = (IRecord *) self;
122    interface_lock_exclusive(thiz);
123    thiz->mCallback = callback;
124    thiz->mContext = pContext;
125    interface_unlock_exclusive(thiz);
126    result = SL_RESULT_SUCCESS;
127
128    SL_LEAVE_INTERFACE
129}
130
131
132static SLresult IRecord_SetCallbackEventsMask(SLRecordItf self, SLuint32 eventFlags)
133{
134    SL_ENTER_INTERFACE
135
136    if (eventFlags & ~(
137        SL_RECORDEVENT_HEADATLIMIT  |
138        SL_RECORDEVENT_HEADATMARKER |
139        SL_RECORDEVENT_HEADATNEWPOS |
140        SL_RECORDEVENT_HEADMOVING   |
141        SL_RECORDEVENT_HEADSTALLED  |
142        SL_RECORDEVENT_BUFFER_FULL)) {
143        result = SL_RESULT_PARAMETER_INVALID;
144    } else {
145        IRecord *thiz = (IRecord *) self;
146        interface_lock_exclusive(thiz);
147        if (thiz->mCallbackEventsMask != eventFlags) {
148            thiz->mCallbackEventsMask = eventFlags;
149            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
150        } else {
151            interface_unlock_exclusive(thiz);
152        }
153        result = SL_RESULT_SUCCESS;
154    }
155
156    SL_LEAVE_INTERFACE
157}
158
159
160static SLresult IRecord_GetCallbackEventsMask(SLRecordItf self, SLuint32 *pEventFlags)
161{
162    SL_ENTER_INTERFACE
163
164    if (NULL == pEventFlags) {
165        result = SL_RESULT_PARAMETER_INVALID;
166    } else {
167        IRecord *thiz = (IRecord *) self;
168        interface_lock_shared(thiz);
169        SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
170        interface_unlock_shared(thiz);
171        *pEventFlags = callbackEventsMask;
172        result = SL_RESULT_SUCCESS;
173    }
174
175    SL_LEAVE_INTERFACE
176}
177
178
179static SLresult IRecord_SetMarkerPosition(SLRecordItf self, SLmillisecond mSec)
180{
181    SL_ENTER_INTERFACE
182
183    if (SL_TIME_UNKNOWN == mSec) {
184        result = SL_RESULT_PARAMETER_INVALID;
185    } else {
186        IRecord *thiz = (IRecord *) self;
187        bool significant = false;
188        interface_lock_exclusive(thiz);
189        if (thiz->mMarkerPosition != mSec) {
190            thiz->mMarkerPosition = mSec;
191            if (thiz->mCallbackEventsMask & SL_PLAYEVENT_HEADATMARKER) {
192                significant = true;
193            }
194        }
195        if (significant) {
196            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
197        } else {
198            interface_unlock_exclusive(thiz);
199        }
200        result = SL_RESULT_SUCCESS;
201    }
202
203    SL_LEAVE_INTERFACE
204}
205
206
207static SLresult IRecord_ClearMarkerPosition(SLRecordItf self)
208{
209    SL_ENTER_INTERFACE
210
211    IRecord *thiz = (IRecord *) self;
212    bool significant = false;
213    interface_lock_exclusive(thiz);
214    // clearing the marker position is equivalent to setting the marker to SL_TIME_UNKNOWN
215    if (thiz->mMarkerPosition != SL_TIME_UNKNOWN) {
216        thiz->mMarkerPosition = SL_TIME_UNKNOWN;
217        if (thiz->mCallbackEventsMask & SL_PLAYEVENT_HEADATMARKER) {
218            significant = true;
219        }
220    }
221    if (significant) {
222        interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
223    } else {
224        interface_unlock_exclusive(thiz);
225    }
226    result = SL_RESULT_SUCCESS;
227
228    SL_LEAVE_INTERFACE
229}
230
231
232static SLresult IRecord_GetMarkerPosition(SLRecordItf self, SLmillisecond *pMsec)
233{
234    SL_ENTER_INTERFACE
235
236    if (NULL == pMsec) {
237        result = SL_RESULT_PARAMETER_INVALID;
238    } else {
239        IRecord *thiz = (IRecord *) self;
240        interface_lock_shared(thiz);
241        SLmillisecond markerPosition = thiz->mMarkerPosition;
242        interface_unlock_shared(thiz);
243        *pMsec = markerPosition;
244        if (SL_TIME_UNKNOWN == markerPosition) {
245            result = SL_RESULT_PRECONDITIONS_VIOLATED;
246        } else {
247            result = SL_RESULT_SUCCESS;
248        }
249    }
250
251    SL_LEAVE_INTERFACE
252}
253
254
255static SLresult IRecord_SetPositionUpdatePeriod(SLRecordItf self, SLmillisecond mSec)
256{
257    SL_ENTER_INTERFACE
258
259    if (0 == mSec) {
260        result = SL_RESULT_PARAMETER_INVALID;
261    } else {
262        IRecord *thiz = (IRecord *) self;
263        interface_lock_exclusive(thiz);
264        if (thiz->mPositionUpdatePeriod != mSec) {
265            thiz->mPositionUpdatePeriod = mSec;
266            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
267        } else {
268            interface_unlock_exclusive(thiz);
269        }
270        result = SL_RESULT_SUCCESS;
271    }
272
273    SL_LEAVE_INTERFACE
274}
275
276
277static SLresult IRecord_GetPositionUpdatePeriod(SLRecordItf self, SLmillisecond *pMsec)
278{
279    SL_ENTER_INTERFACE
280
281    if (NULL == pMsec) {
282        result = SL_RESULT_PARAMETER_INVALID;
283    } else {
284        IRecord *thiz = (IRecord *) self;
285        interface_lock_shared(thiz);
286        SLmillisecond positionUpdatePeriod = thiz->mPositionUpdatePeriod;
287        interface_unlock_shared(thiz);
288        *pMsec = positionUpdatePeriod;
289        result = SL_RESULT_SUCCESS;
290    }
291
292    SL_LEAVE_INTERFACE
293}
294
295
296static const struct SLRecordItf_ IRecord_Itf = {
297    IRecord_SetRecordState,
298    IRecord_GetRecordState,
299    IRecord_SetDurationLimit,
300    IRecord_GetPosition,
301    IRecord_RegisterCallback,
302    IRecord_SetCallbackEventsMask,
303    IRecord_GetCallbackEventsMask,
304    IRecord_SetMarkerPosition,
305    IRecord_ClearMarkerPosition,
306    IRecord_GetMarkerPosition,
307    IRecord_SetPositionUpdatePeriod,
308    IRecord_GetPositionUpdatePeriod
309};
310
311void IRecord_init(void *self)
312{
313    IRecord *thiz = (IRecord *) self;
314    thiz->mItf = &IRecord_Itf;
315    thiz->mState = SL_RECORDSTATE_STOPPED;
316    thiz->mDurationLimit = 0;
317    thiz->mPosition = (SLmillisecond) 0;
318    thiz->mCallback = NULL;
319    thiz->mContext = NULL;
320    thiz->mCallbackEventsMask = 0;
321    thiz->mMarkerPosition = SL_TIME_UNKNOWN;
322    thiz->mPositionUpdatePeriod = 1000; // per spec
323}
324