Home | History | Annotate | Download | only in src
      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  */
     62 M4OSA_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 
    156 cleanup:
    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  */
    186 M4OSA_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  */
    295 M4OSA_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  */
    351 M4OSA_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  */
    433 M4OSA_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  */
    482 M4OSA_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  */
    558 M4OSA_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  */
    622 M4OSA_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  */
    672 M4OSA_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 /*********************************************************/
    704 M4OSA_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