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