Renesas / Mbed OS GR-PEACH_Audio_Playback_Sample

Dependencies:   R_BSP TLV320_RBSP USBHost_custom

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers decode.cpp Source File

decode.cpp

00001 /*******************************************************************************
00002 * DISCLAIMER
00003 * This software is supplied by Renesas Electronics Corporation and is only
00004 * intended for use with Renesas products. No other uses are authorized. This
00005 * software is owned by Renesas Electronics Corporation and is protected under
00006 * all applicable laws, including copyright laws.
00007 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
00008 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
00009 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00010 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
00011 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
00012 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
00013 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
00014 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
00015 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00016 * Renesas reserves the right, without notice, to make changes to this software
00017 * and to discontinue the availability of this software. By using this software,
00018 * you agree to the additional terms and conditions found by accessing the
00019 * following link:
00020 * http://www.renesas.com/disclaimer*
00021 * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved.
00022 *******************************************************************************/
00023 
00024 #include "mbed.h"
00025 #include "rtos.h"
00026 #include "misratypes.h"
00027 #include "r_errno.h"
00028 #include "system.h"
00029 #include "decode.h"
00030 #include "audio_out.h"
00031 #include "dec_flac.h"
00032 
00033 /*--- Macro definition of mbed-rtos mail ---*/
00034 #define MAIL_QUEUE_SIZE     (12)    /* Queue size */
00035 #define MAIL_PARAM_NUM      (2)     /* Elements number of mail parameter array */
00036 
00037 /* dec_mail_t */
00038 #define MAIL_PARAM0         (0)     /* Index number of mail parameter array */
00039 #define MAIL_PARAM1         (1)     /* Index number of mail parameter array */
00040 
00041 #define MAIL_PARAM_NON      (0u)    /* Value of unused element of mail parameter array */
00042 
00043 /* mail_id = DEC_MAILID_OPEN */
00044 #define MAIL_OPEN_CB        (MAIL_PARAM0)   /* Callback function */
00045 #define MAIL_OPEN_FILE      (MAIL_PARAM1)   /* File handle */
00046 
00047 /* mail_id = DEC_MAILID_PLAY : No parameter */
00048 
00049 /* mail_id = DEC_MAILID_PAUSE_ON : No parameter */
00050 
00051 /* mail_id = DEC_MAILID_PAUSE_OFF : No parameter */
00052 
00053 /* mail_id = DEC_MAILID_STOP : No parameter */
00054 
00055 /* mail_id = DEC_MAILID_CLOSE */
00056 #define MAIL_CLOSE_CB               (MAIL_PARAM0)   /* Callback function */
00057 
00058 /* mail_id = DEC_MAILID_CB_AUD_DATA_OUT */
00059 #define MAIL_DATA_OUT_RESULT        (MAIL_PARAM0)   /* Result of the process */
00060 
00061 /* mail_id = DEC_MAILID_SCUX_WRITE_FIN */
00062 #define MAIL_SCUX_WRITE_RESULT      (MAIL_PARAM0)   /* Result of the process */
00063 #define MAIL_SCUX_WRITE_BUF_INDEX   (MAIL_PARAM1)   /* Index number of PCM buffer */
00064 
00065 /* mail_id = DEC_MAILID_SCUX_FLUSH_FIN */
00066 #define MAIL_SCUX_FLUSH_RESULT      (MAIL_PARAM0)   /* Result of the process */
00067 
00068 
00069 /*--- Macro definition of PCM buffer ---*/
00070 #define UNIT_TIME_MS                (50u)   /* Unit time of PCM data processing (ms) */
00071 #define SEC_TO_MSEC                 (1000u)
00072 
00073 /* Sample number per uint time (ms) */
00074 #define SAMPLE_NUM_PER_UNIT_MS      (((UNIT_TIME_MS * DEC_INPUT_MAX_SAMPLE_RATE) / SEC_TO_MSEC) * DEC_OUTPUT_CHANNEL_NUM)
00075 /* Max number of samples per 1 block */
00076 #define MAX_SAMPLE_PER_1BLOCK       (DEC_MAX_BLOCK_SIZE * DEC_OUTPUT_CHANNEL_NUM)
00077 
00078 #define PCM_BUF_NUM                 (3u)
00079 #define TOTAL_SAMPLE_NUM            (MAX_SAMPLE_PER_1BLOCK + SAMPLE_NUM_PER_UNIT_MS)
00080 
00081 #define PCM_BUF_SINGLE              (1)
00082 #define PCM_BUF_TOP_ID              (0)
00083 
00084 /*--- Macro definition of R_BSP_Scux ---*/
00085 #define SCUX_INT_LEVEL              (0x80)
00086 #define SCUX_READ_NUM               (DEC_SCUX_READ_NUM)
00087 #define SCUX_WRITE_NUM              (PCM_BUF_NUM)
00088 
00089 /* 4 bytes aligned. No cache memory. */
00090 #if defined(__ICCARM__)
00091 #define NC_BSS_SECT                 @ ".mirrorram"
00092 #else
00093 #define NC_BSS_SECT                 __attribute__((section("NC_BSS"),aligned(4)))
00094 #endif
00095 
00096 /*--- User defined types of mbed-rtos mail ---*/
00097 typedef enum {
00098     DEC_MAILID_DUMMY = 0,
00099     DEC_MAILID_OPEN,            /* Requests the opening of the decoder. */
00100     DEC_MAILID_PLAY,            /* Requests the starting of the playback. */
00101     DEC_MAILID_PAUSE_ON,        /* Requests the starting of the pause. */
00102     DEC_MAILID_PAUSE_OFF,       /* Requests the stopping of the pause. */
00103     DEC_MAILID_STOP,            /* Requests the stopping of the playback. */
00104     DEC_MAILID_CLOSE,           /* Requests the closing of the decoder. */
00105     DEC_MAILID_CB_AUD_DATA_OUT, /* Finished the preparation for the audio output. */
00106     DEC_MAILID_SCUX_WRITE_FIN,  /* Finished the writing process of SCUX. */
00107     DEC_MAILID_SCUX_FLUSH_FIN,  /* Finished the flush process of SCUX. */
00108     DEC_MAILID_NUM
00109 } DEC_MAIL_ID;
00110 
00111 typedef struct {
00112     DEC_MAIL_ID     mail_id;
00113     uint32_t        param[MAIL_PARAM_NUM];
00114 } dec_mail_t;
00115 
00116 /*--- User defined types of decode thread ---*/
00117 /* The playback information of the playback file */
00118 typedef struct {
00119     SYS_PlayStat    play_stat;  /* Playback status */
00120     uint32_t        play_time;  /* Playback start time */
00121     uint32_t        total_time; /* Total playback time */
00122 } play_info_t;
00123 
00124 /* Control data of Decode thread */
00125 typedef struct {
00126     play_info_t     play_info;
00127     flac_ctrl_t     flac_ctrl;
00128 } dec_ctrl_t;
00129 
00130 /* Status of Decode thread */
00131 typedef enum {
00132     DEC_ST_IDLE = 0,            /* Idle */
00133     DEC_ST_META_FIN,            /* Finished the decoding until a metadata */
00134     DEC_ST_PLAY,                /* Decoder start */
00135     DEC_ST_PAUSE,               /* Decoder pause */
00136     DEC_ST_STOP_PREPARE,        /* Preparing of decoder stop */
00137     DEC_ST_STOP,                /* Decoder stop */
00138     DEC_ST_NUM
00139 } DEC_STATE;
00140 
00141 static Mail<dec_mail_t, MAIL_QUEUE_SIZE> mail_box;
00142 static R_BSP_Scux scux(SCUX_CH_0, SCUX_INT_LEVEL, SCUX_WRITE_NUM, SCUX_READ_NUM);
00143 
00144 static bool open_proc(flac_ctrl_t * const p_ctrl, 
00145         FILE * const p_handle, const DEC_CbOpen p_cb);
00146 static void close_proc(flac_ctrl_t * const p_ctrl, const DEC_CbClose p_cb);
00147 static bool play_proc(flac_ctrl_t * const p_ctrl, const uint32_t buf_id,
00148         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num);
00149 static bool pause_proc(const uint32_t buf_id,
00150         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num);
00151 static uint32_t get_audio_data(flac_ctrl_t * const p_ctrl, 
00152                                 int32_t * const p_buf, const uint32_t buf_num);
00153 static void data_out_callback(const bool result);
00154 static void write_callback(void * p_data, int32_t result, void * p_app_data);
00155 static void flush_callback(int32_t result);
00156 static bool send_mail(const DEC_MAIL_ID mail_id, 
00157                             const uint32_t param0, const uint32_t param1);
00158 static bool recv_mail(DEC_MAIL_ID * const p_mail_id, 
00159                         uint32_t * const p_param0, uint32_t * const p_param1);
00160 static void update_decode_stat(const SYS_PlayStat stat, play_info_t * const p_play_info);
00161 static void update_decode_playtime(const uint32_t play_time, play_info_t * const p_play_info);
00162 static void init_decode_playinfo(const uint32_t total_time, play_info_t * const p_play_info);
00163 static void notify_decode_stat(const play_info_t * const p_play_info);
00164 
00165 void dec_thread(void const *argument)
00166 {
00167     dec_ctrl_t                  dec_ctrl;   /* Control data of Decode thread */
00168     DEC_STATE                   dec_stat;   /* Status of Decode thread */
00169     DEC_MAIL_ID                 mail_type;
00170     uint32_t                    mail_param[MAIL_PARAM_NUM];
00171     uint32_t                    buf_id;
00172     uint32_t                    buf_num;
00173     uint32_t                    time_code;
00174     bool                        result;
00175 #if defined(__ICCARM__)
00176     static int32_t pcm_buf[PCM_BUF_NUM][TOTAL_SAMPLE_NUM] NC_BSS_SECT;
00177 #else
00178     static int32_t NC_BSS_SECT  pcm_buf[PCM_BUF_NUM][TOTAL_SAMPLE_NUM];
00179 #endif
00180 
00181     UNUSED_ARG(argument);
00182     dec_stat = DEC_ST_IDLE;
00183     while (1) {
00184         result = recv_mail(&mail_type, &mail_param[MAIL_PARAM0], &mail_param[MAIL_PARAM1]);
00185         if (result == true) {
00186             /* State transition processing */
00187             switch (dec_stat) {
00188                 case DEC_ST_META_FIN:       /* Finished the decoding until a metadata */
00189                     if (mail_type == DEC_MAILID_PLAY) {
00190                         time_code = flac_get_total_time(&dec_ctrl.flac_ctrl);
00191                         init_decode_playinfo(time_code, &dec_ctrl.play_info);
00192                         update_decode_stat(SYS_PLAYSTAT_PLAY, &dec_ctrl.play_info);
00193                         (void) aud_req_data_out(&data_out_callback);
00194                         dec_stat = DEC_ST_PLAY;
00195                     } else if (mail_type == DEC_MAILID_CLOSE) {
00196                         scux.ClearStop();
00197                         close_proc(&dec_ctrl.flac_ctrl, (DEC_CbClose)mail_param[MAIL_CLOSE_CB]);
00198                         dec_stat = DEC_ST_IDLE;
00199                     } else {
00200                         /* DO NOTHING */
00201                     }
00202                     break;
00203                 case DEC_ST_PLAY:           /* Decoder start */
00204                     if (mail_type == DEC_MAILID_PAUSE_ON) {
00205                         update_decode_stat(SYS_PLAYSTAT_PAUSE, &dec_ctrl.play_info);
00206                         dec_stat = DEC_ST_PAUSE;
00207                     } else if (mail_type == DEC_MAILID_STOP) {
00208                         scux.ClearStop();
00209                         (void) aud_req_zero_out();
00210                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00211                         dec_stat = DEC_ST_STOP;
00212                     } else if ((mail_type == DEC_MAILID_CB_AUD_DATA_OUT) || 
00213                                (mail_type == DEC_MAILID_SCUX_WRITE_FIN)) {
00214                         if (mail_type == DEC_MAILID_SCUX_WRITE_FIN) {
00215                             buf_id = mail_param[MAIL_SCUX_WRITE_BUF_INDEX];
00216                             buf_num = PCM_BUF_SINGLE;
00217                         } else {
00218                             buf_id = PCM_BUF_TOP_ID;
00219                             buf_num = PCM_BUF_NUM;
00220                         }
00221                         result = play_proc(&dec_ctrl.flac_ctrl, buf_id, &pcm_buf[buf_id], buf_num);
00222                         if (result == true) {
00223                             time_code = flac_get_play_time(&dec_ctrl.flac_ctrl);
00224                             update_decode_playtime(time_code, &dec_ctrl.play_info);
00225                             /* "dec_stat" variable does not change. */
00226                         } else {
00227                             result = scux.FlushStop(&flush_callback);
00228                             if (result == true) {
00229                                 dec_stat = DEC_ST_STOP_PREPARE;
00230                             } else {
00231                                 /* Error occurred by SCUX driver. */
00232                                 (void) aud_req_zero_out();
00233                                 update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00234                                 dec_stat = DEC_ST_STOP;
00235                             }
00236                         }
00237                     } else {
00238                         /* DO NOTHING */
00239                     }
00240                     break;
00241                 case DEC_ST_PAUSE:          /* Decoder pause */
00242                     if (mail_type == DEC_MAILID_PAUSE_OFF) {
00243                         update_decode_stat(SYS_PLAYSTAT_PLAY, &dec_ctrl.play_info);
00244                         dec_stat = DEC_ST_PLAY;
00245                     } else if (mail_type == DEC_MAILID_STOP) {
00246                         scux.ClearStop();
00247                         (void) aud_req_zero_out();
00248                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00249                         dec_stat = DEC_ST_STOP;
00250                     } else if ((mail_type == DEC_MAILID_CB_AUD_DATA_OUT) || 
00251                                (mail_type == DEC_MAILID_SCUX_WRITE_FIN)) {
00252                         if (mail_type == DEC_MAILID_SCUX_WRITE_FIN) {
00253                             buf_id = mail_param[MAIL_SCUX_WRITE_BUF_INDEX];
00254                             buf_num = PCM_BUF_SINGLE;
00255                         } else {
00256                             buf_id = PCM_BUF_TOP_ID;
00257                             buf_num = PCM_BUF_NUM;
00258                         }
00259                         result = pause_proc(buf_id, &pcm_buf[buf_id], buf_num);
00260                         if (result == true) {
00261                             /* "dec_stat" variable does not change. */
00262                         } else {
00263                             result = scux.FlushStop(&flush_callback);
00264                             if (result == true) {
00265                                 dec_stat = DEC_ST_STOP_PREPARE;
00266                             } else {
00267                                 /* Error occurred by SCUX driver. */
00268                                 (void) aud_req_zero_out();
00269                                 update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00270                                 dec_stat = DEC_ST_STOP;
00271                             }
00272                         }
00273                     } else {
00274                         /* DO NOTHING */
00275                     }
00276                     break;
00277                 case DEC_ST_STOP_PREPARE:   /* Preparing of decoder stop */
00278                     if (mail_type == DEC_MAILID_SCUX_FLUSH_FIN) {
00279                         (void) aud_req_zero_out();
00280                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00281                         dec_stat = DEC_ST_STOP;
00282                     } else {
00283                         /* DO NOTHING */
00284                     }
00285                     break;
00286                 case DEC_ST_STOP:           /* Decoder stop */
00287                     if (mail_type == DEC_MAILID_CLOSE) {
00288                         close_proc(&dec_ctrl.flac_ctrl, (DEC_CbClose)mail_param[MAIL_CLOSE_CB]);
00289                         dec_stat = DEC_ST_IDLE;
00290                     } else {
00291                         /* DO NOTHING */
00292                     }
00293                     break;
00294                 case DEC_ST_IDLE:           /* Idle */
00295                 default:
00296                     if (mail_type == DEC_MAILID_OPEN) {
00297                         result = open_proc(&dec_ctrl.flac_ctrl, 
00298                                            (FILE*)mail_param[MAIL_OPEN_FILE], 
00299                                            (DEC_CbOpen)mail_param[MAIL_OPEN_CB]);
00300                         if (result == true) {
00301                             dec_stat = DEC_ST_META_FIN;
00302                         } else {
00303                             /* "dec_stat" variable does not change. */
00304                         }
00305                     } else {
00306                         dec_stat = DEC_ST_IDLE; /* This is fail-safe processing. */
00307                     }
00308                     break;
00309             }
00310         }
00311     }
00312 }
00313 
00314 bool dec_open(FILE * const p_handle, const DEC_CbOpen p_cb)
00315 {
00316     bool    ret = false;
00317 
00318     if ((p_handle != NULL) && (p_cb != NULL)) {
00319         ret = send_mail(DEC_MAILID_OPEN, (uint32_t)p_cb, (uint32_t)p_handle);
00320     }
00321     return ret;
00322 }
00323 
00324 bool dec_play(void)
00325 {
00326     bool    ret = false;
00327 
00328     ret = send_mail(DEC_MAILID_PLAY, MAIL_PARAM_NON, MAIL_PARAM_NON);
00329 
00330     return ret;
00331 }
00332 
00333 bool dec_pause_on(void)
00334 {
00335     bool    ret = false;
00336 
00337     ret = send_mail(DEC_MAILID_PAUSE_ON, MAIL_PARAM_NON, MAIL_PARAM_NON);
00338 
00339     return ret;
00340 }
00341 
00342 bool dec_pause_off(void)
00343 {
00344     bool    ret = false;
00345 
00346     ret = send_mail(DEC_MAILID_PAUSE_OFF, MAIL_PARAM_NON, MAIL_PARAM_NON);
00347 
00348     return ret;
00349 }
00350 
00351 bool dec_stop(void)
00352 {
00353     bool    ret;
00354 
00355     ret = send_mail(DEC_MAILID_STOP, MAIL_PARAM_NON, MAIL_PARAM_NON);
00356 
00357     return ret;
00358 }
00359 
00360 bool dec_close(const DEC_CbClose p_cb)
00361 {
00362     bool    ret = false;
00363 
00364     if (p_cb != NULL) {
00365         ret = send_mail(DEC_MAILID_CLOSE, (uint32_t)p_cb, MAIL_PARAM_NON);
00366     }
00367     return ret;
00368 }
00369 
00370 bool dec_scux_read(void * const p_data, const uint32_t data_size, 
00371                             const rbsp_data_conf_t * const p_data_conf)
00372 {
00373     bool            ret = false;
00374     int32_t         result;
00375 
00376     result = scux.read(p_data, data_size, p_data_conf);
00377     if (result == ESUCCESS) {
00378         ret = true;
00379     }
00380     return ret;
00381 }
00382 
00383 /** Executes the opening process of the decoder
00384  *
00385  *  @param p_ctrl Pointer to the control data of FLAC module.
00386  *  @param p_handle Pointer to the handle of FLAC file.
00387  *  @param p_cb Pointer to the callback for notification of the process result.
00388  *
00389  *  @returns 
00390  *    Results of process. true is success. false is failure.
00391  */
00392 static bool open_proc(flac_ctrl_t * const p_ctrl, FILE * const p_handle, const DEC_CbOpen p_cb)
00393 {
00394     bool                ret = false;
00395     bool                result;
00396     scux_src_usr_cfg_t  conf;
00397 
00398     if ((p_ctrl != NULL) && (p_handle != NULL) && (p_cb != NULL)) {
00399         result = flac_open(p_handle, p_ctrl);
00400         if (result == true) {
00401             /* Sets SCUX config */
00402             conf.src_enable           = true;
00403             conf.word_len             = SCUX_DATA_LEN_24;
00404             conf.mode_sync            = true;
00405             conf.input_rate           = p_ctrl->sample_rate;
00406             conf.output_rate          = DEC_OUTPUT_SAMPLE_RATE;
00407             conf.select_in_data_ch[0] = SELECT_IN_DATA_CH_0;
00408             conf.select_in_data_ch[1] = SELECT_IN_DATA_CH_1;
00409             result = scux.SetSrcCfg(&conf);
00410             if (result == true) {
00411                 ret = scux.TransStart();
00412             }
00413         }
00414         p_cb(ret, p_ctrl->sample_rate, p_ctrl->channel_num);
00415     }
00416     return ret;
00417 }
00418 
00419 /** Executes the closing process of the decoder
00420  *
00421  *  @param p_ctrl Pointer to the control data of FLAC module.
00422  *  @param p_cb Pointer to the callback for notification of the process result.
00423  *
00424  *  @returns 
00425  *    Results of process. true is success. false is failure.
00426  */
00427 static void close_proc(flac_ctrl_t * const p_ctrl, const DEC_CbClose p_cb)
00428 {
00429     if ((p_ctrl != NULL) && (p_cb != NULL)) {
00430         flac_close(p_ctrl);
00431         p_cb();
00432     }
00433 }
00434 
00435 /** Executes the starting process of the pause
00436  *
00437  *  @param p_ctrl Pointer to the control data of FLAC module.
00438  *  @param buf_id Index of PCM buffer array.
00439  *  @param p_buf Pointer to PCM buffer array to use in this process.
00440  *  @param element_num Elements number of PCM buffer array.
00441  *
00442  *  @returns 
00443  *    Results of process. true is success. false is failure.
00444  */
00445 static bool pause_proc(const uint32_t buf_id,
00446         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num)
00447 {
00448     bool                ret = false;
00449     uint32_t            i;
00450     int32_t             result;
00451     const uint32_t      pause_data_size = SAMPLE_NUM_PER_UNIT_MS * sizeof(*p_buf[0]);
00452     rbsp_data_conf_t    cb_conf = {
00453         &write_callback,
00454         NULL
00455     };
00456 
00457     if ((p_buf != NULL) && (element_num > 0u) && 
00458         (element_num <= PCM_BUF_NUM) && ((buf_id + element_num) <= PCM_BUF_NUM)) {
00459         /* Audio output process */
00460         result = ESUCCESS;
00461         for (i = 0; (i < element_num) && (result == ESUCCESS); i++) {
00462             (void) memset(&p_buf[i], 0, pause_data_size);
00463             cb_conf.p_app_data = (void *)(buf_id + i);
00464             result = scux.write(&p_buf[i], pause_data_size, &cb_conf);
00465         }
00466         if (result == ESUCCESS) {
00467             ret = true;
00468         }
00469     }
00470     return ret;
00471 }
00472 
00473 /** Executes the starting process of the playback
00474  *
00475  *  @param p_ctrl Pointer to the control data of FLAC module.
00476  *  @param buf_id Index of PCM buffer array.
00477  *  @param p_buf Pointer to PCM buffer array to use in this process.
00478  *  @param element_num Elements number of PCM buffer array.
00479  *
00480  *  @returns 
00481  *    Results of process. true is success. false is failure.
00482  */
00483 static bool play_proc(flac_ctrl_t * const p_ctrl, const uint32_t buf_id,
00484         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num)
00485 {
00486     bool                ret = false;
00487     int32_t             result;
00488     uint32_t            i;
00489     uint32_t            decoded_cnt;
00490     uint32_t            num;
00491     uint32_t            read_byte[PCM_BUF_NUM];
00492     rbsp_data_conf_t    cb_conf = {
00493         &write_callback,
00494         NULL
00495     };
00496 
00497     if ((p_ctrl != NULL) && (p_buf != NULL) && (element_num > 0u) && 
00498         (element_num <= PCM_BUF_NUM) && ((buf_id + element_num) <= PCM_BUF_NUM)) {
00499         /* FLAC decoder process */
00500         decoded_cnt = 0u;
00501         do {
00502             num = get_audio_data(p_ctrl, p_buf[decoded_cnt], sizeof(p_buf[0])/sizeof(*p_buf[0]));
00503             read_byte[decoded_cnt] = num * sizeof(num);
00504             if (num > 0u) {
00505                 decoded_cnt++;
00506             }
00507         } while ((decoded_cnt < element_num) &&  (num > 0u));
00508         /* Audio output process */
00509         if (decoded_cnt > 0u) {
00510             result = ESUCCESS;
00511             for (i = 0; (i < decoded_cnt) && (result == ESUCCESS); i++) {
00512                 cb_conf.p_app_data = (void *)(buf_id + i);
00513                 result = scux.write(&p_buf[i], read_byte[i], &cb_conf);
00514             }
00515             if (result == ESUCCESS) {
00516                 ret = true;
00517             }
00518         }
00519     }
00520     return ret;
00521 }
00522 
00523 /** Gets the decoded data from FLAC decoder library
00524  *
00525  *  @param p_ctrl Pointer to the control data of FLAC module.
00526  *  @param p_buf Pointer to PCM buffer array to store the decoded data.
00527  *  @param buf_num Elements number of PCM buffer array.
00528  *
00529  *  @returns 
00530  *    Elements number of decoded data.
00531  */
00532 static uint32_t get_audio_data(flac_ctrl_t * const p_ctrl, 
00533                             int32_t * const p_buf, const uint32_t buf_num)
00534 {
00535     uint32_t    read_cnt = 0u;
00536     bool        result;
00537 
00538     if ((p_ctrl != NULL) && (p_buf != NULL) && (buf_num > 0u)) {
00539         result = flac_set_pcm_buf(p_ctrl, p_buf, buf_num);
00540         while ((result == true) && ((read_cnt + MAX_SAMPLE_PER_1BLOCK) <= buf_num)) {
00541             result = flac_decode(p_ctrl);
00542             read_cnt = flac_get_pcm_cnt(p_ctrl);
00543         }
00544     }
00545     return read_cnt;
00546 }
00547 
00548 /** Callback function of Audio Out Thread
00549  *
00550  *  @param result Result of the process of Audio Out Thread
00551  */
00552 static void data_out_callback(const bool result)
00553 {
00554     (void) send_mail(DEC_MAILID_CB_AUD_DATA_OUT, (uint32_t)result, MAIL_PARAM_NON);
00555 }
00556 
00557 /** Callback function of SCUX driver
00558  *
00559  *  @param p_data Pointer to PCM byffer array.
00560  *  @param result Result of the process.
00561  *  @param p_app_data The control ID of PCM buffer.
00562  */
00563 static void write_callback(void * p_data, int32_t result, void * p_app_data)
00564 {
00565     const uint32_t  buf_id = (uint32_t)p_app_data;
00566     bool            flag_result;
00567 
00568     UNUSED_ARG(p_data);
00569     if (result > 0) {
00570         flag_result = true;
00571     } else {
00572         flag_result = false;
00573     }
00574     (void) send_mail(DEC_MAILID_SCUX_WRITE_FIN, (uint32_t)flag_result, buf_id);
00575 }
00576 
00577 /** Callback function of SCUX driver
00578  *
00579  *  @param result Result of the process.
00580  */
00581 static void flush_callback(int32_t result)
00582 {
00583     bool        flag_result;
00584 
00585     if (result > 0) {
00586         flag_result = true;
00587     } else {
00588         flag_result = false;
00589     }
00590     (void) send_mail(DEC_MAILID_SCUX_FLUSH_FIN, (uint32_t)flag_result, MAIL_PARAM_NON);
00591 }
00592 
00593 /** Sends the mail to Decode thread
00594  *
00595  *  @param mail_id Mail ID
00596  *  @param param0 Parameter 0 of this mail
00597  *  @param param1 Parameter 1 of this mail
00598  *
00599  *  @returns 
00600  *    Results of process. true is success. false is failure.
00601  */
00602 static bool send_mail(const DEC_MAIL_ID mail_id, 
00603                             const uint32_t param0, const uint32_t param1)
00604 {
00605     bool            ret = false;
00606     osStatus        stat;
00607     dec_mail_t      * const p_mail = mail_box.alloc();
00608 
00609     if (p_mail != NULL) {
00610         p_mail->mail_id = mail_id;
00611         p_mail->param[MAIL_PARAM0] = param0;
00612         p_mail->param[MAIL_PARAM1] = param1;
00613         stat = mail_box.put(p_mail);
00614         if (stat == osOK) {
00615             ret = true;
00616         } else {
00617             (void) mail_box.free(p_mail);
00618         }
00619     }
00620     return ret;
00621 }
00622 
00623 /** Receives the mail to Decode thread
00624  *
00625  *  @param p_mail_id Pointer to the variable to store the mail ID
00626  *  @param p_param0 Pointer to the variable to store the parameter 0 of this mail
00627  *  @param p_param1 Pointer to the variable to store the parameter 1 of this mail
00628  *
00629  *  @returns 
00630  *    Results of process. true is success. false is failure.
00631  */
00632 static bool recv_mail(DEC_MAIL_ID * const p_mail_id, 
00633                         uint32_t * const p_param0, uint32_t * const p_param1)
00634 {
00635     bool            ret = false;
00636     osEvent         evt;
00637     dec_mail_t      *p_mail;
00638     
00639     if ((p_mail_id != NULL) && (p_param0 != NULL) && (p_param1 != NULL)) {
00640         evt = mail_box.get();
00641         if (evt.status == osEventMail) {
00642             p_mail = (dec_mail_t *)evt.value.p;
00643             if (p_mail != NULL) {
00644                 *p_mail_id = p_mail->mail_id;
00645                 *p_param0 = p_mail->param[MAIL_PARAM0];
00646                 *p_param1 = p_mail->param[MAIL_PARAM1];
00647                 ret = true;
00648             }
00649             (void) mail_box.free(p_mail);
00650         }
00651     }
00652     return ret;
00653 }
00654 
00655 /** Updates the status of Decode thread
00656  *
00657  *  @param stat New status of Decode thread
00658  *  @param p_play_info Pointer to the playback information of the playback file
00659  */
00660 static void update_decode_stat(const SYS_PlayStat stat, play_info_t * const p_play_info)
00661 {
00662     if (p_play_info != NULL) {
00663         if (p_play_info->play_stat != stat) {
00664             p_play_info->play_stat = stat;
00665             notify_decode_stat(p_play_info);
00666         }
00667     }
00668 }
00669 
00670 /** Updates the playback time
00671  *
00672  *  @param play_time Current playback time
00673  *  @param p_play_info Pointer to the playback information of the playback file
00674  */
00675 static void update_decode_playtime(const uint32_t play_time, play_info_t * const p_play_info)
00676 {
00677     if (p_play_info != NULL) {
00678         if (p_play_info->play_time != play_time) {
00679             p_play_info->play_time = play_time;
00680             notify_decode_stat(p_play_info);
00681         }
00682     }
00683 }
00684 
00685 /** Initialises the playback information
00686  *
00687  *  @param total_time Total playback time
00688  *  @param p_play_info Pointer to the playback information of the playback file
00689  */
00690 static void init_decode_playinfo(const uint32_t total_time, play_info_t * const p_play_info)
00691 {
00692     if (p_play_info != NULL) {
00693         p_play_info->play_stat  = SYS_PLAYSTAT_STOP;
00694         p_play_info->play_time  = 0u;
00695         p_play_info->total_time = total_time;
00696     }
00697 }
00698 
00699 /** Notifies Main thread of the status of Decode thread
00700  *
00701  *  @param p_play_info Pointer to the playback information of the playback file
00702  */
00703 static void notify_decode_stat(const play_info_t * const p_play_info)
00704 {
00705     if (p_play_info != NULL) {
00706         (void) sys_notify_play_time(p_play_info->play_stat, 
00707                     p_play_info->play_time, p_play_info->total_time);
00708     }
00709 }