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 ************************************************************************
18 * @file    M4PCM_PCMReader.c
19 * @brief   PCM reader implementation
20 * @note    This file implements functions of the PCM reader
21 ************************************************************************
22 */
23#include "M4OSA_CharStar.h"
24#include "M4PCMR_CoreReader.h"
25#include "M4OSA_Debug.h"
26#include "M4OSA_CharStar.h"
27/**
28 ******************************************************************************
29 * PCM reader version numbers
30 ******************************************************************************
31 */
32/* CHANGE_VERSION_HERE */
33#define M4PCMR_VERSION_MAJOR 1
34#define M4PCMR_VERSION_MINOR 0
35#define M4PCMR_VERSION_REVISION 0
36
37/**
38 ************************************************************************
39 * M4OSA_ERR M4PCMR_openRead(M4OSA_Context* pContext, M4OSA_Void* pUrl,
40 *                             M4OSA_FileReaderPointer* pFileFunction)
41 * @brief   This function opens a PCM file
42 * @note    This function :
43 *          - opens a PCM file
44 *          - initializes PCM context,
45 *          - verifies PCM file format
46 *          - Fill decoder config structure
47 *          - Changes state of the reader in 'Opening'
48 * @param   pContext: (OUT) Pointer on the PCM Reader context
49 * @param   pUrl: (IN) Name of the PCM file
50 * @param   pFileFunctions: (IN) Pointer on the file access functions
51 * @return  M4NO_ERROR                      there is no error during the opening
52 * @return  M4ERR_PARAMETER                 pContext and/or pUrl and/or pFileFunction is NULL
53 * @return  M4ERR_ALLOC                     there is no more memory available
54 * @return  M4ERR_FILE_NOT_FOUND            the file cannot be found
55 * @return  M4PCMC_ERR_PCM_NOT_COMPLIANT    the file does not seem to be compliant, no RIFF,
56 *                                             or lack of any mandatory chunk.
57 * @return  M4PCMC_ERR_PCM_NOT_SUPPORTED    the PCM format of this file is not supported by the
58 *                                           reader
59 * @return  Any M4OSA_FILE errors           see OSAL File specification for detailed errors
60 ************************************************************************
61 */
62M4OSA_ERR M4PCMR_openRead(M4OSA_Context* pContext, M4OSA_Void* pUrl,
63                             M4OSA_FileReadPointer* pFileFunction)
64{
65    M4OSA_ERR       err;
66    M4PCMR_Context *context;
67    M4OSA_Char*        pTempURL;
68    M4OSA_Char        value[6];
69
70    /* Check parameters */
71    if((M4OSA_NULL == pContext)|| (M4OSA_NULL == pUrl) ||(M4OSA_NULL == pFileFunction))
72    {
73        return M4ERR_PARAMETER;
74    }
75
76    /* Allocates the context */
77    context = M4OSA_NULL;
78    context = (M4PCMR_Context *)M4OSA_32bitAlignedMalloc(sizeof(M4PCMR_Context), M4WAV_READER,
79         (M4OSA_Char *)"M4PCMR_openRead");
80    if (M4OSA_NULL == context)
81    {
82        return M4ERR_ALLOC;
83    }
84    *pContext = (M4OSA_Context)context;
85
86    /* Initialize the context */
87    context->m_offset = 0;
88
89    context->m_state            = M4PCMR_kInit;
90    context->m_microState       = M4PCMR_kInit;
91    context->m_pFileReadFunc    = M4OSA_NULL;
92    context->m_fileContext      = M4OSA_NULL;
93    context->m_pAuBuffer        = M4OSA_NULL;
94    context->m_pDecoderSpecInfo = M4OSA_NULL;
95
96    /* Set sample frequency */
97    pTempURL = (M4OSA_Char*)pUrl + (strlen((const char *)pUrl)-11);
98    M4OSA_chrNCopy(value, pTempURL, 5);
99    M4OSA_chrGetUInt32(pTempURL, &(context->m_decoderConfig.SampleFrequency),
100         M4OSA_NULL, M4OSA_kchrDec);
101
102    /* Set number of channels */
103    pTempURL += 6;
104    M4OSA_chrNCopy(value, pTempURL, 1);
105    M4OSA_chrGetUInt16(pTempURL, &(context->m_decoderConfig.nbChannels),
106         M4OSA_NULL, M4OSA_kchrDec);
107
108    M4OSA_chrNCopy(pUrl,pUrl, (strlen((const char *)pUrl)-12));
109    /* Open the file */
110    context->m_fileContext = M4OSA_NULL;
111    err = pFileFunction->openRead(&(context->m_fileContext), pUrl, M4OSA_kFileRead);
112    if(M4NO_ERROR != err)
113    {
114        return err;
115    }
116    context->m_decoderConfig.BitsPerSample = 16;
117    context->m_decoderConfig.AvgBytesPerSec = context->m_decoderConfig.SampleFrequency * 2 \
118        * context->m_decoderConfig.nbChannels;
119    err = pFileFunction->getOption(context->m_fileContext, M4OSA_kFileReadGetFileSize,
120         (M4OSA_DataOption*)&(context->m_decoderConfig.DataLength));
121    if(M4NO_ERROR != err)
122    {
123        return err;
124    }
125    context->m_blockSize = 2048 * context->m_decoderConfig.nbChannels;  // Raw PCM.  Hence, get a
126                                                                        // chunk of data
127
128    if(context->m_decoderConfig.SampleFrequency == 8000)
129    {
130        /* AMR case, no pb */
131        context->m_blockSize = context->m_decoderConfig.nbChannels *\
132             (context->m_decoderConfig.SampleFrequency / 50) * \
133                (context->m_decoderConfig.BitsPerSample / 8);
134    }
135    if(context->m_decoderConfig.SampleFrequency == 16000)
136    {
137        /* AAC case, we can't read only 20 ms blocks */
138        context->m_blockSize = 2048 * context->m_decoderConfig.nbChannels;
139    }
140    context->m_dataStartOffset = 0;
141    context->m_pFileReadFunc = pFileFunction;
142
143    context->m_pAuBuffer = (M4OSA_MemAddr32)M4OSA_32bitAlignedMalloc(context->m_blockSize, M4WAV_READER,
144         (M4OSA_Char *)"Core PCM reader Access Unit");
145    if (M4OSA_NULL == context->m_pAuBuffer)
146    {
147        err = M4ERR_ALLOC;
148        goto cleanup;
149    }
150
151    /* Change state */
152    context->m_state = M4PCMR_kOpening;
153
154    return M4NO_ERROR;
155
156cleanup:
157
158    /* Close the file */
159    if(context->m_pFileReadFunc != M4OSA_NULL)
160        context->m_pFileReadFunc->closeRead(context->m_fileContext);
161
162    /* Free internal context */
163    free(context);
164    *pContext = M4OSA_NULL;
165
166    return err;
167}
168
169/**
170 ************************************************************************
171 * M4OSA_ERR M4PCMR_getNextStream(M4OSA_Context context, M4SYS_StreamDescription* pStreamDesc)
172 * @brief   This function get the (unique) stream of a PCM file
173 * @note    This function :
174 *          - Allocates and fills the decoder specific info structure
175 *          - Fills decoder specific infos structure
176 *          - Fills pStreamDesc structure allocated by the caller
177 * @param   context: (IN/OUT) PCM Reader context
178 * @param   pStreamDesc: (IN) Stream Description context
179 * @return  M4NO_ERROR          there is no error
180 * @return  M4ERR_PARAMETER     at least one parameter is NULL
181 * @return  M4ERR_ALLOC         there is no more memory available
182 * @return  M4ERR_STATE         this function cannot be called now
183 * @return  Any M4OSA_FILE      errors see OSAL File specification for detailed errors
184 ************************************************************************
185 */
186M4OSA_ERR M4PCMR_getNextStream(M4OSA_Context context, M4SYS_StreamDescription* pStreamDesc)
187{
188    M4PCMR_Context *c = (M4PCMR_Context *)context;
189
190    /* Check parameters */
191    if((M4OSA_NULL == context)|| (M4OSA_NULL == pStreamDesc))
192    {
193        return M4ERR_PARAMETER;
194    }
195
196    if (c->m_state == M4PCMR_kOpening_streamRetrieved)
197    {
198        return M4WAR_NO_MORE_STREAM;
199    }
200    /* Check Reader's m_state */
201    if(c->m_state != M4PCMR_kOpening)
202    {
203        return M4ERR_STATE;
204    }
205
206    /* Only one stream is contained in PCM file */
207    pStreamDesc->streamID = 1;
208    /* Not used */
209    pStreamDesc->profileLevel = 0;
210    pStreamDesc->decoderSpecificInfoSize = sizeof(M4PCMC_DecoderSpecificInfo);
211
212    /* Allocates decoder specific info structure */
213    pStreamDesc->decoderSpecificInfo = M4OSA_NULL;
214    pStreamDesc->decoderSpecificInfo =
215        (M4OSA_MemAddr32)M4OSA_32bitAlignedMalloc( sizeof(M4PCMC_DecoderSpecificInfo), M4WAV_READER,
216             (M4OSA_Char *)"M4PCMR_getNextStream");
217    if(pStreamDesc->decoderSpecificInfo == M4OSA_NULL)
218    {
219        return M4ERR_ALLOC;
220    }
221    /* Fill decoderSpecificInfo structure, with decoder config structure filled in 'openread'
222         function */
223    memcpy((void *)pStreamDesc->decoderSpecificInfo,
224         (void *)&c->m_decoderConfig, sizeof(M4PCMC_DecoderSpecificInfo));
225
226    /* Fill other fields of pStreamDesc structure */
227    pStreamDesc->timeScale = 1000;
228    pStreamDesc->duration = (M4OSA_Time)(((M4OSA_Double)(c->m_decoderConfig.DataLength)\
229         / (M4OSA_Double)(c->m_decoderConfig.AvgBytesPerSec))*pStreamDesc->timeScale);
230    pStreamDesc->averageBitrate = c->m_decoderConfig.AvgBytesPerSec * 8;/* in bits, multiply by 8*/
231    pStreamDesc->maxBitrate = pStreamDesc->averageBitrate; /* PCM stream has constant bitrate */
232
233    /* Determines Stream type */
234    switch(c->m_decoderConfig.BitsPerSample)
235    {
236        case 8:
237            switch(c->m_decoderConfig.nbChannels)
238            {
239                case 1:
240                    pStreamDesc->streamType = M4SYS_kPCM_8bitsU;
241                    break;
242//                case 2:
243//                    pStreamDesc->streamType = M4SYS_kPCM_8bitsS; /* ??? 8bits stereo not
244                                                                  //   defined ? */
245//                    break;
246                default:
247                    pStreamDesc->streamType = M4SYS_kAudioUnknown;
248            }
249            break;
250
251        case 16:
252            switch(c->m_decoderConfig.nbChannels)
253            {
254                case 1:
255                    pStreamDesc->streamType = M4SYS_kPCM_16bitsU;
256                    break;
257                case 2:
258                    pStreamDesc->streamType = M4SYS_kPCM_16bitsS;
259                    break;
260                default:
261                    pStreamDesc->streamType = M4SYS_kAudioUnknown;
262            }
263            break;
264
265        default:
266            pStreamDesc->streamType = M4SYS_kAudioUnknown;
267    }
268
269    c->m_pDecoderSpecInfo = pStreamDesc->decoderSpecificInfo;
270
271    c->m_state = M4PCMR_kOpening_streamRetrieved;
272
273    return M4NO_ERROR;
274}
275
276/**
277 ************************************************************************
278 * M4OSA_ERR M4PCMR_startReading(M4OSA_Context context, M4SYS_StreamID* pStreamIDs)
279 * @brief   This function starts reading the unique stream of a PCM file
280 * @note    This function :
281 *          - Verifies that the current reader's state allows to start reading a stream
282 *          - Check that provided StreamId is correct (always true, only one stream...)
283 *            In the player application, a StreamId table is initialized as follow:
284 *              M4SYS_StreamID pStreamID[2]={1,0};
285 *          - Change state of the reader in 'Reading'
286 * @param   context: (IN/OUT) PCM Reader context
287 * @param   streamID: (IN) Stream selection
288 * @return  M4NO_ERROR          there is no error
289 * @return  M4ERR_PARAMETER     at least one parameter is NULL
290 * @return  M4ERR_STATE         this function cannot be called now
291 * @return  M4ERR_BAD_STREAM_ID at least one of the streamID does not exist
292 *          (should never happen if table pStreamID is correctly initialized as above)
293 ************************************************************************
294 */
295M4OSA_ERR M4PCMR_startReading(M4OSA_Context context, M4SYS_StreamID* pStreamIDs)
296{
297    M4PCMR_Context *c = (M4PCMR_Context *)context;
298
299    /* Check parameters */
300    if((M4OSA_NULL == context) || (M4OSA_NULL == pStreamIDs))
301    {
302        return M4ERR_PARAMETER;
303    }
304
305    /* Check Reader's state */
306    if(c->m_state != M4PCMR_kOpening_streamRetrieved)
307    {
308        return M4ERR_STATE;
309    }
310
311    /* Check pStreamID and if they're OK, change reader's state */
312    if(pStreamIDs[0] == 1 || pStreamIDs[0] == 0)
313    /* First and unique stream contained in PCM file */
314    {
315        c->m_state = M4PCMR_kReading;
316        c->m_microState = M4PCMR_kReading;
317    }
318    else
319    {
320        return M4ERR_BAD_STREAM_ID;
321    }
322
323    return M4NO_ERROR;
324}
325
326/**
327 ************************************************************************
328 * M4OSA_ERR M4PCMR_nextAU(M4OSA_Context context, M4SYS_StreamID streamID, M4SYS_AccessUnit* pAU)
329 * @brief   This function reads the next AU contained in the PCM file
330 * @note    This function :
331 *          - Verifies that the current reader's state allows to read an AU
332 *          - Allocates memory to store read AU
333 *          - Read data from file and store them into previously allocated memory
334 *          - Fill AU structure fileds (CTS...)
335 *          - Change state of the reader in 'Reading' (not useful...)
336 *          - Change Micro state 'Reading' in M4PCMR_kReading_nextAU
337 *            (AU is read and can be deleted)
338 *          - Check if the last AU has been read or if we're about to read it
339 * @param   context: (IN/OUT) PCM Reader context
340 * @param   streamID: (IN) Stream selection
341 * @param   pAU: (IN/OUT) Acces Unit Structure
342 * @return  M4NO_ERROR          there is no error
343 * @return  M4ERR_PARAMETER     at least one parameter is NULL
344 * @return  M4ERR_ALLOC         there is no more memory available
345 * @return  M4ERR_STATE         this function cannot be called now
346 * @return  M4M4WAR_NO_DATA_YET there is no enough data in the file to provide a new access unit.
347 * @return  M4WAR_END_OF_STREAM There is no more access unit in the stream,
348 *                              or the sample number is bigger the maximum one.
349 ************************************************************************
350 */
351M4OSA_ERR M4PCMR_nextAU(M4OSA_Context context, M4SYS_StreamID streamID, M4SYS_AccessUnit* pAU)
352{
353    M4PCMR_Context *c = (M4PCMR_Context *)context;
354    M4OSA_ERR err = M4NO_ERROR;
355    M4OSA_UInt32 size_read;
356
357    /* Check parameters */
358    if((M4OSA_NULL == context) || (M4OSA_NULL == pAU))
359    {
360        return M4ERR_PARAMETER;
361    }
362
363    /* Check Reader's state */
364    if(c->m_state != M4PCMR_kReading && c->m_microState != M4PCMR_kReading)
365    {
366        return M4ERR_STATE;
367    }
368
369    /* Allocates AU dataAdress */
370    pAU->dataAddress = c->m_pAuBuffer;
371    size_read        = c->m_blockSize;
372
373    if((c->m_offset + size_read) >= c->m_decoderConfig.DataLength)
374    {
375        size_read = c->m_decoderConfig.DataLength - c->m_offset;
376    }
377
378    /* Read data in file, and copy it to AU Structure */
379    err = c->m_pFileReadFunc->readData(c->m_fileContext, (M4OSA_MemAddr8)pAU->dataAddress,
380         (M4OSA_UInt32 *)&size_read);
381    if(M4NO_ERROR != err)
382    {
383        return err;
384    }
385
386    /* Calculates the new m_offset, used to determine whether we're at end of reading or not */
387    c->m_offset = c->m_offset + size_read;
388
389    /* Fill others parameters of AU structure */
390    pAU->CTS =
391         (M4OSA_Time)(((M4OSA_Double)c->m_offset/(M4OSA_Double)c->m_decoderConfig.AvgBytesPerSec)\
392            *1000);
393    pAU->DTS = pAU->CTS;
394
395    pAU->attribute  = 0;
396    pAU->frag       = M4OSA_NULL;
397    pAU->nbFrag     = 0;
398    pAU->stream     = M4OSA_NULL;
399    pAU->size       = size_read;
400
401    /* Change states */
402    c->m_state = M4PCMR_kReading; /* Not changed ... */
403    c->m_microState = M4PCMR_kReading_nextAU; /* AU is read and can be deleted */
404
405    /* Check if there is another AU to read */
406    /* ie: if decoded nb of bytes = nb of bytes to decode,
407         it means there is no more AU to decode */
408    if(c->m_offset >= c->m_decoderConfig.DataLength)
409    {
410        return M4WAR_NO_MORE_AU;
411    }
412
413    return M4NO_ERROR;
414}
415
416/**
417 ************************************************************************
418 * M4OSA_ERR M4PCMR_freeAU(M4OSA_Context context, M4SYS_StreamID streamID, M4SYS_AccessUnit* pAU)
419 * @brief   This function frees the AU provided in parameter
420 * @note    This function :
421 *          - Verifies that the current reader's state allows to free an AU
422 *          - Free dataAddress field of AU structure
423 *          - Change state of the reader in 'Reading' (not useful...)
424 *          - Change Micro state 'Reading' in M4PCMR_kReading (another AU can be read)
425 * @param   context: (IN/OUT) PCM Reader context
426 * @param   streamID: (IN) Stream selection
427 * @param   pAU: (IN) Acces Unit Structure
428 * @return  M4NO_ERROR  there is no error
429 * @return  M4ERR_PARAMETER at least one parameter is NULL
430 * @return  M4ERR_STATE this function cannot be called now
431 ************************************************************************
432 */
433M4OSA_ERR M4PCMR_freeAU(M4OSA_Context context, M4SYS_StreamID streamID, M4SYS_AccessUnit* pAU)
434{
435    M4PCMR_Context *c = (M4PCMR_Context *)context;
436
437    /* Check parameters */
438    if((M4OSA_NULL == context ) || (M4OSA_NULL == pAU))
439    {
440        return M4ERR_PARAMETER;
441    }
442
443    /* Check Reader's state */
444    if(c->m_state != M4PCMR_kReading && c->m_microState != M4PCMR_kReading_nextAU)
445    {
446        return M4ERR_STATE;
447    }
448
449    pAU->dataAddress = M4OSA_NULL;
450
451    /* Change states */
452    c->m_state = M4PCMR_kReading; /* Not changed ... */
453    c->m_microState = M4PCMR_kReading; /* AU is deleted, another AU can be read */
454
455    return M4NO_ERROR;
456}
457
458/**
459 ************************************************************************
460 * M4OSA_ERR M4PCMR_seek(M4OSA_Context context, M4SYS_StreamID* pStreamID,
461                         M4OSA_Time time, M4SYS_seekAccessMode seekAccessMode,
462                         M4OSA_Time* pObtainCTS[])
463 * @brief   This function seeks into the PCM file at the provided time
464 * @note    This function :
465 *          - Verifies that the current reader's state allows to seek
466 *          - Determines from provided time m_offset to seek in file
467 *          - If m_offset is correct, seek in file
468 *          - Update new m_offset in PCM reader context
469 * @param   context: (IN/OUT) PCM Reader context
470 * @param   pStreamID: (IN) Stream selection (not used, only 1 stream)
471 * @param   time: (IN) Targeted time
472 * @param   seekMode: (IN) Selects the seek access mode
473 * @param   pObtainCTS[]: (OUT) Returned Time (not used)
474 * @return  M4NO_ERROR              there is no error
475 * @return  M4ERR_PARAMETER         at least one parameter is NULL
476 * @return  M4ERR_ALLOC             there is no more memory available
477 * @return  M4ERR_STATE             this function cannot be called now
478 * @return  M4WAR_INVALID_TIME      Specified time is not reachable
479 * @param   M4ERR_NOT_IMPLEMENTED   This seek mode is not implemented yet
480 ************************************************************************
481 */
482M4OSA_ERR M4PCMR_seek(M4OSA_Context context, M4SYS_StreamID* pStreamID, M4OSA_Time time,
483                      M4SYS_SeekAccessMode seekAccessMode, M4OSA_Time* pObtainCTS)
484{
485    M4PCMR_Context *c = (M4PCMR_Context *)context;
486    M4OSA_ERR err = M4NO_ERROR;
487    M4OSA_UInt32 offset;
488    M4OSA_UInt32 alignment;
489    M4OSA_UInt32 size_read;
490
491    /* Check parameters */
492    if((M4OSA_NULL == context) || (M4OSA_NULL == pStreamID))
493    {
494        return M4ERR_PARAMETER;
495    }
496
497    /* Check Reader's state */
498    if(c->m_state != M4PCMR_kOpening_streamRetrieved && c->m_state != M4PCMR_kReading)
499    {
500        return M4ERR_STATE;
501    }
502
503    switch(seekAccessMode)
504    {
505        case M4SYS_kBeginning:
506            /* Determine m_offset from time*/
507            offset =
508                (M4OSA_UInt32)(time * ((M4OSA_Double)(c->m_decoderConfig.AvgBytesPerSec) / 1000));
509            /** check the alignment on sample boundary */
510            alignment = c->m_decoderConfig.nbChannels*c->m_decoderConfig.BitsPerSample/8;
511            if (offset%alignment != 0)
512            {
513                offset -= offset%alignment;
514            }
515            /*add the header offset*/
516            offset += c->m_dataStartOffset;
517            /* If m_offset is over file size -> Invalid time */
518            if (offset > (c->m_dataStartOffset + c->m_decoderConfig.DataLength))
519            {
520                return M4WAR_INVALID_TIME;
521            }
522            else
523            {
524                /* Seek file */
525                size_read = offset;
526                err = c->m_pFileReadFunc->seek(c->m_fileContext, M4OSA_kFileSeekBeginning,
527                    (M4OSA_FilePosition *) &size_read);
528                if(M4NO_ERROR != err)
529                {
530                    return err;
531                }
532                /* Update m_offset in M4PCMR_context */
533                c->m_offset = offset - c->m_dataStartOffset;
534            }
535            break;
536
537        default:
538            return M4ERR_NOT_IMPLEMENTED;
539    }
540
541    return M4NO_ERROR;
542}
543
544/**
545 ************************************************************************
546 * M4OSA_ERR M4PCMR_closeRead(M4OSA_Context context)
547 * @brief   This function closes PCM file, and frees context
548 * @note    This function :
549 *          - Verifies that the current reader's state allows close the PCM file
550 *          - Closes the file
551 *          - Free structures
552 * @param   context: (IN/OUT) PCM Reader context
553 * @return  M4NO_ERROR              there is no error
554 * @return  M4ERR_PARAMETER         at least one parameter is NULL
555 * @return  M4ERR_STATE             this function cannot be called now
556 ************************************************************************
557 */
558M4OSA_ERR M4PCMR_closeRead(M4OSA_Context context)
559{
560    M4PCMR_Context *c = (M4PCMR_Context *)context;
561    M4OSA_ERR err = M4NO_ERROR;
562
563    /* Check parameters */
564    if(M4OSA_NULL == context)
565    {
566        return M4ERR_PARAMETER;
567    }
568
569    if(c->m_pDecoderSpecInfo != M4OSA_NULL)
570    {
571        free(c->m_pDecoderSpecInfo);
572    }
573
574    /* Check Reader's state */
575    if(c->m_state != M4PCMR_kReading)
576    {
577        return M4ERR_STATE;
578    }
579    else if(c->m_microState == M4PCMR_kReading_nextAU)
580    {
581        return M4ERR_STATE;
582    }
583
584    if (M4OSA_NULL != c->m_pAuBuffer)
585    {
586        free(c->m_pAuBuffer);
587    }
588
589    /* Close the file */
590    if (M4OSA_NULL != c->m_pFileReadFunc)
591    {
592        err = c->m_pFileReadFunc->closeRead(c->m_fileContext);
593    }
594
595    /* Free internal context */
596    if (M4OSA_NULL != c)
597    {
598        free(c);
599    }
600
601    return err;
602}
603
604/**
605 ************************************************************************
606 * M4OSA_ERR M4PCMR_getOption(M4OSA_Context context, M4PCMR_OptionID optionID,
607 *                                M4OSA_DataOption* pValue)
608 * @brief   This function get option of the PCM Reader
609 * @note    This function :
610 *          - Verifies that the current reader's state allows to get an option
611 *          - Return corresponding option value
612 * @param   context: (IN/OUT) PCM Reader context
613 * @param   optionID: (IN) ID of the option to get
614 * @param   pValue: (OUT) Variable where the option value is returned
615 * @return  M4NO_ERROR              there is no error.
616 * @return  M4ERR_PARAMETER         at least one parameter is NULL.
617 * @return  M4ERR_BAD_OPTION_ID     the optionID is not a valid one.
618 * @return  M4ERR_STATE             this option is not available now.
619 * @return  M4ERR_NOT_IMPLEMENTED   this option is not implemented
620 ************************************************************************
621 */
622M4OSA_ERR M4PCMR_getOption(M4OSA_Context context, M4PCMR_OptionID optionID,
623                             M4OSA_DataOption* pValue)
624{
625    M4PCMR_Context *c =(M4PCMR_Context *)context;
626
627    /* Check parameters */
628    if(M4OSA_NULL == context)
629    {
630        return M4ERR_PARAMETER;
631    }
632
633    /* Check reader's state */
634    if((c->m_state != M4PCMR_kOpening) && (c->m_state != M4PCMR_kOpening_streamRetrieved)\
635         && (c->m_state != M4PCMR_kReading))
636    {
637        return M4ERR_STATE;
638    }
639
640    /* Depend of the OptionID, the value to return is different */
641    switch(optionID)
642    {
643        case M4PCMR_kPCMblockSize:
644            *pValue = &c->m_blockSize;
645            break;
646
647        default:
648            return M4ERR_BAD_OPTION_ID;
649    }
650
651    return M4NO_ERROR;
652}
653
654/**
655 ************************************************************************
656 * M4OSA_ERR M4PCMR_setOption(M4OSA_Context context, M4PCMR_OptionID optionID,
657 *                                 M4OSA_DataOption Value)
658 * @brief   This function set option of the PCM Reader
659 * @note    This function :
660 *          - Verifies that the current reader's state allows to set an option
661 *          - Set corresponding option value
662 * @param   context: (IN/OUT) PCM Reader context
663 * @param   optionID: (IN) ID of the option to get
664 * @param   Value: (IN) Variable where the option value is stored
665 * @return  M4NO_ERROR              there is no error.
666 * @return  M4ERR_PARAMETER         at least one parameter is NULL.
667 * @return  M4ERR_BAD_OPTION_ID     the optionID is not a valid one.
668 * @return  M4ERR_STATE             this option is not available now.
669 * @return  M4ERR_NOT_IMPLEMENTED   this option is not implemented
670 ************************************************************************
671 */
672M4OSA_ERR M4PCMR_setOption(M4OSA_Context context, M4PCMR_OptionID optionID, M4OSA_DataOption Value)
673{
674    M4PCMR_Context *c =(M4PCMR_Context *)context;
675
676    /* Check parameters */
677    if(context == M4OSA_NULL)
678    {
679        return M4ERR_PARAMETER;
680    }
681
682    /* Check reader's state */
683    if((c->m_state != M4PCMR_kOpening) && (c->m_state != M4PCMR_kOpening_streamRetrieved)\
684         && (c->m_state != M4PCMR_kReading))
685    {
686        return M4ERR_STATE;
687    }
688
689    /* Depend of the OptionID, the value to set is different */
690    switch(optionID)
691    {
692        case M4PCMR_kPCMblockSize:
693            c->m_blockSize = (M4OSA_UInt32)Value;
694            break;
695
696        default:
697            return M4ERR_BAD_OPTION_ID;
698    }
699
700    return M4NO_ERROR;
701}
702
703/*********************************************************/
704M4OSA_ERR M4PCMR_getVersion (M4_VersionInfo *pVersion)
705/*********************************************************/
706{
707    M4OSA_TRACE1_1("M4PCMR_getVersion called with pVersion: 0x%x", pVersion);
708    M4OSA_DEBUG_IF1(((M4OSA_UInt32) pVersion == 0),M4ERR_PARAMETER,
709         "pVersion is NULL in M4PCMR_getVersion");
710
711    pVersion->m_major = M4PCMR_VERSION_MAJOR;
712    pVersion->m_minor = M4PCMR_VERSION_MINOR;
713    pVersion->m_revision = M4PCMR_VERSION_REVISION;
714
715    return M4NO_ERROR;
716}
717