The "GR-PEACH_Audio_Playback_7InchLCD_Sample" is a sample code that can provides high-resolution audio playback of FLAC format files. It also allows the user to audio-playback control functions such as play, pause, and stop by manipulating key switches.

Dependencies:   GR-PEACH_video R_BSP TLV320_RBSP USBHost_custom

Fork of GR-PEACH_Audio_Playback_Sample by Renesas

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                 (2u)
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 #define NC_BSS_SECT                 __attribute__((section("NC_BSS"),aligned(4)))
00091 
00092 /*--- User defined types of mbed-rtos mail ---*/
00093 typedef enum {
00094     DEC_MAILID_DUMMY = 0,
00095     DEC_MAILID_OPEN,            /* Requests the opening of the decoder. */
00096     DEC_MAILID_PLAY,            /* Requests the starting of the playback. */
00097     DEC_MAILID_PAUSE_ON,        /* Requests the starting of the pause. */
00098     DEC_MAILID_PAUSE_OFF,       /* Requests the stopping of the pause. */
00099     DEC_MAILID_STOP,            /* Requests the stopping of the playback. */
00100     DEC_MAILID_CLOSE,           /* Requests the closing of the decoder. */
00101     DEC_MAILID_CB_AUD_DATA_OUT, /* Finished the preparation for the audio output. */
00102     DEC_MAILID_SCUX_WRITE_FIN,  /* Finished the writing process of SCUX. */
00103     DEC_MAILID_SCUX_FLUSH_FIN,  /* Finished the flush process of SCUX. */
00104     DEC_MAILID_NUM
00105 } DEC_MAIL_ID;
00106 
00107 typedef struct {
00108     DEC_MAIL_ID     mail_id;
00109     uint32_t        param[MAIL_PARAM_NUM];
00110 } dec_mail_t;
00111 
00112 /*--- User defined types of decode thread ---*/
00113 /* The playback information of the playback file */
00114 typedef struct {
00115     SYS_PlayStat    play_stat;  /* Playback status */
00116     uint32_t        play_time;  /* Playback start time */
00117     uint32_t        total_time; /* Total playback time */
00118 } play_info_t;
00119 
00120 /* Control data of Decode thread */
00121 typedef struct {
00122     play_info_t     play_info;
00123     flac_ctrl_t     flac_ctrl;
00124 } dec_ctrl_t;
00125 
00126 /* Status of Decode thread */
00127 typedef enum {
00128     DEC_ST_IDLE = 0,            /* Idle */
00129     DEC_ST_META_FIN,            /* Finished the decoding until a metadata */
00130     DEC_ST_PLAY,                /* Decoder start */
00131     DEC_ST_PAUSE,               /* Decoder pause */
00132     DEC_ST_STOP_PREPARE,        /* Preparing of decoder stop */
00133     DEC_ST_STOP,                /* Decoder stop */
00134     DEC_ST_NUM
00135 } DEC_STATE;
00136 
00137 static Mail<dec_mail_t, MAIL_QUEUE_SIZE> mail_box;
00138 static R_BSP_Scux scux(SCUX_CH_0, SCUX_INT_LEVEL, SCUX_WRITE_NUM, SCUX_READ_NUM);
00139 
00140 static bool open_proc(flac_ctrl_t * const p_ctrl, 
00141         FILE * const p_handle, const DEC_CbOpen p_cb);
00142 static void close_proc(flac_ctrl_t * const p_ctrl, const DEC_CbClose p_cb);
00143 static bool play_proc(flac_ctrl_t * const p_ctrl, const uint32_t buf_id,
00144         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num);
00145 static bool pause_proc(const uint32_t buf_id,
00146         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num);
00147 static uint32_t get_audio_data(flac_ctrl_t * const p_ctrl, 
00148                                 int32_t * const p_buf, const uint32_t buf_num);
00149 static void data_out_callback(const bool result);
00150 static void write_callback(void * p_data, int32_t result, void * p_app_data);
00151 static void flush_callback(int32_t result);
00152 static bool send_mail(const DEC_MAIL_ID mail_id, 
00153                             const uint32_t param0, const uint32_t param1);
00154 static bool recv_mail(DEC_MAIL_ID * const p_mail_id, 
00155                         uint32_t * const p_param0, uint32_t * const p_param1);
00156 static void update_decode_stat(const SYS_PlayStat stat, play_info_t * const p_play_info);
00157 static void update_decode_playtime(const uint32_t play_time, play_info_t * const p_play_info);
00158 static void init_decode_playinfo(const uint32_t total_time, play_info_t * const p_play_info);
00159 static void notify_decode_stat(const play_info_t * const p_play_info);
00160 
00161 void dec_thread(void const *argument)
00162 {
00163     dec_ctrl_t                  dec_ctrl;   /* Control data of Decode thread */
00164     DEC_STATE                   dec_stat;   /* Status of Decode thread */
00165     DEC_MAIL_ID                 mail_type;
00166     uint32_t                    mail_param[MAIL_PARAM_NUM];
00167     uint32_t                    buf_id;
00168     uint32_t                    buf_num;
00169     uint32_t                    time_code;
00170     bool                        result;
00171     static int32_t NC_BSS_SECT  pcm_buf[PCM_BUF_NUM][TOTAL_SAMPLE_NUM];
00172 
00173     UNUSED_ARG(argument);
00174     dec_stat = DEC_ST_IDLE;
00175     while (1) {
00176         result = recv_mail(&mail_type, &mail_param[MAIL_PARAM0], &mail_param[MAIL_PARAM1]);
00177         if (result == true) {
00178             /* State transition processing */
00179             switch (dec_stat) {
00180                 case DEC_ST_META_FIN:       /* Finished the decoding until a metadata */
00181                     if (mail_type == DEC_MAILID_PLAY) {
00182                         time_code = flac_get_total_time(&dec_ctrl.flac_ctrl);
00183                         init_decode_playinfo(time_code, &dec_ctrl.play_info);
00184                         update_decode_stat(SYS_PLAYSTAT_PLAY, &dec_ctrl.play_info);
00185                         (void) aud_req_data_out(&data_out_callback);
00186                         dec_stat = DEC_ST_PLAY;
00187                     } else if (mail_type == DEC_MAILID_CLOSE) {
00188                         scux.ClearStop();
00189                         close_proc(&dec_ctrl.flac_ctrl, (DEC_CbClose)mail_param[MAIL_CLOSE_CB]);
00190                         dec_stat = DEC_ST_IDLE;
00191                     } else {
00192                         /* DO NOTHING */
00193                     }
00194                     break;
00195                 case DEC_ST_PLAY:           /* Decoder start */
00196                     if (mail_type == DEC_MAILID_PAUSE_ON) {
00197                         update_decode_stat(SYS_PLAYSTAT_PAUSE, &dec_ctrl.play_info);
00198                         dec_stat = DEC_ST_PAUSE;
00199                     } else if (mail_type == DEC_MAILID_STOP) {
00200                         scux.ClearStop();
00201                         (void) aud_req_zero_out();
00202                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00203                         dec_stat = DEC_ST_STOP;
00204                     } else if ((mail_type == DEC_MAILID_CB_AUD_DATA_OUT) || 
00205                                (mail_type == DEC_MAILID_SCUX_WRITE_FIN)) {
00206                         if (mail_type == DEC_MAILID_SCUX_WRITE_FIN) {
00207                             buf_id = mail_param[MAIL_SCUX_WRITE_BUF_INDEX];
00208                             buf_num = PCM_BUF_SINGLE;
00209                         } else {
00210                             buf_id = PCM_BUF_TOP_ID;
00211                             buf_num = PCM_BUF_NUM;
00212                         }
00213                         result = play_proc(&dec_ctrl.flac_ctrl, buf_id, &pcm_buf[buf_id], buf_num);
00214                         if (result == true) {
00215                             time_code = flac_get_play_time(&dec_ctrl.flac_ctrl);
00216                             update_decode_playtime(time_code, &dec_ctrl.play_info);
00217                             /* "dec_stat" variable does not change. */
00218                         } else {
00219                             result = scux.FlushStop(&flush_callback);
00220                             if (result == true) {
00221                                 dec_stat = DEC_ST_STOP_PREPARE;
00222                             } else {
00223                                 /* Error occurred by SCUX driver. */
00224                                 (void) aud_req_zero_out();
00225                                 update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00226                                 dec_stat = DEC_ST_STOP;
00227                             }
00228                         }
00229                     } else {
00230                         /* DO NOTHING */
00231                     }
00232                     break;
00233                 case DEC_ST_PAUSE:          /* Decoder pause */
00234                     if (mail_type == DEC_MAILID_PAUSE_OFF) {
00235                         update_decode_stat(SYS_PLAYSTAT_PLAY, &dec_ctrl.play_info);
00236                         dec_stat = DEC_ST_PLAY;
00237                     } else if (mail_type == DEC_MAILID_STOP) {
00238                         scux.ClearStop();
00239                         (void) aud_req_zero_out();
00240                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00241                         dec_stat = DEC_ST_STOP;
00242                     } else if ((mail_type == DEC_MAILID_CB_AUD_DATA_OUT) || 
00243                                (mail_type == DEC_MAILID_SCUX_WRITE_FIN)) {
00244                         if (mail_type == DEC_MAILID_SCUX_WRITE_FIN) {
00245                             buf_id = mail_param[MAIL_SCUX_WRITE_BUF_INDEX];
00246                             buf_num = PCM_BUF_SINGLE;
00247                         } else {
00248                             buf_id = PCM_BUF_TOP_ID;
00249                             buf_num = PCM_BUF_NUM;
00250                         }
00251                         result = pause_proc(buf_id, &pcm_buf[buf_id], buf_num);
00252                         if (result == true) {
00253                             /* "dec_stat" variable does not change. */
00254                         } else {
00255                             result = scux.FlushStop(&flush_callback);
00256                             if (result == true) {
00257                                 dec_stat = DEC_ST_STOP_PREPARE;
00258                             } else {
00259                                 /* Error occurred by SCUX driver. */
00260                                 (void) aud_req_zero_out();
00261                                 update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00262                                 dec_stat = DEC_ST_STOP;
00263                             }
00264                         }
00265                     } else {
00266                         /* DO NOTHING */
00267                     }
00268                     break;
00269                 case DEC_ST_STOP_PREPARE:   /* Preparing of decoder stop */
00270                     if (mail_type == DEC_MAILID_SCUX_FLUSH_FIN) {
00271                         (void) aud_req_zero_out();
00272                         update_decode_stat(SYS_PLAYSTAT_STOP, &dec_ctrl.play_info);
00273                         dec_stat = DEC_ST_STOP;
00274                     } else {
00275                         /* DO NOTHING */
00276                     }
00277                     break;
00278                 case DEC_ST_STOP:           /* Decoder stop */
00279                     if (mail_type == DEC_MAILID_CLOSE) {
00280                         close_proc(&dec_ctrl.flac_ctrl, (DEC_CbClose)mail_param[MAIL_CLOSE_CB]);
00281                         dec_stat = DEC_ST_IDLE;
00282                     } else {
00283                         /* DO NOTHING */
00284                     }
00285                     break;
00286                 case DEC_ST_IDLE:           /* Idle */
00287                 default:
00288                     if (mail_type == DEC_MAILID_OPEN) {
00289                         result = open_proc(&dec_ctrl.flac_ctrl, 
00290                                            (FILE*)mail_param[MAIL_OPEN_FILE], 
00291                                            (DEC_CbOpen)mail_param[MAIL_OPEN_CB]);
00292                         if (result == true) {
00293                             dec_stat = DEC_ST_META_FIN;
00294                         } else {
00295                             /* "dec_stat" variable does not change. */
00296                         }
00297                     } else {
00298                         dec_stat = DEC_ST_IDLE; /* This is fail-safe processing. */
00299                     }
00300                     break;
00301             }
00302         }
00303     }
00304 }
00305 
00306 bool dec_open(FILE * const p_handle, const DEC_CbOpen p_cb)
00307 {
00308     bool    ret = false;
00309 
00310     if ((p_handle != NULL) && (p_cb != NULL)) {
00311         ret = send_mail(DEC_MAILID_OPEN, (uint32_t)p_cb, (uint32_t)p_handle);
00312     }
00313     return ret;
00314 }
00315 
00316 bool dec_play(void)
00317 {
00318     bool    ret = false;
00319 
00320     ret = send_mail(DEC_MAILID_PLAY, MAIL_PARAM_NON, MAIL_PARAM_NON);
00321 
00322     return ret;
00323 }
00324 
00325 bool dec_pause_on(void)
00326 {
00327     bool    ret = false;
00328 
00329     ret = send_mail(DEC_MAILID_PAUSE_ON, MAIL_PARAM_NON, MAIL_PARAM_NON);
00330 
00331     return ret;
00332 }
00333 
00334 bool dec_pause_off(void)
00335 {
00336     bool    ret = false;
00337 
00338     ret = send_mail(DEC_MAILID_PAUSE_OFF, MAIL_PARAM_NON, MAIL_PARAM_NON);
00339 
00340     return ret;
00341 }
00342 
00343 bool dec_stop(void)
00344 {
00345     bool    ret;
00346 
00347     ret = send_mail(DEC_MAILID_STOP, MAIL_PARAM_NON, MAIL_PARAM_NON);
00348 
00349     return ret;
00350 }
00351 
00352 bool dec_close(const DEC_CbClose p_cb)
00353 {
00354     bool    ret = false;
00355 
00356     if (p_cb != NULL) {
00357         ret = send_mail(DEC_MAILID_CLOSE, (uint32_t)p_cb, MAIL_PARAM_NON);
00358     }
00359     return ret;
00360 }
00361 
00362 bool dec_scux_read(void * const p_data, const uint32_t data_size, 
00363                             const rbsp_data_conf_t * const p_data_conf)
00364 {
00365     bool            ret = false;
00366     int32_t         result;
00367 
00368     result = scux.read(p_data, data_size, p_data_conf);
00369     if (result == ESUCCESS) {
00370         ret = true;
00371     }
00372     return ret;
00373 }
00374 
00375 /** Executes the opening process of the decoder
00376  *
00377  *  @param p_ctrl Pointer to the control data of FLAC module.
00378  *  @param p_handle Pointer to the handle of FLAC file.
00379  *  @param p_cb Pointer to the callback for notification of the process result.
00380  *
00381  *  @returns 
00382  *    Results of process. true is success. false is failure.
00383  */
00384 static bool open_proc(flac_ctrl_t * const p_ctrl, FILE * const p_handle, const DEC_CbOpen p_cb)
00385 {
00386     bool                ret = false;
00387     bool                result;
00388     scux_src_usr_cfg_t  conf;
00389 
00390     if ((p_ctrl != NULL) && (p_handle != NULL) && (p_cb != NULL)) {
00391         result = flac_open(p_handle, p_ctrl);
00392         if (result == true) {
00393             /* Sets SCUX config */
00394             conf.src_enable           = true;
00395             conf.word_len             = SCUX_DATA_LEN_24;
00396             conf.mode_sync            = true;
00397             conf.input_rate           = p_ctrl->sample_rate;
00398             conf.output_rate          = DEC_OUTPUT_SAMPLE_RATE;
00399             conf.select_in_data_ch[0] = SELECT_IN_DATA_CH_0;
00400             conf.select_in_data_ch[1] = SELECT_IN_DATA_CH_1;
00401             result = scux.SetSrcCfg(&conf);
00402             if (result == true) {
00403                 ret = scux.TransStart();
00404             }
00405         }
00406         p_cb(ret, p_ctrl->sample_rate, p_ctrl->channel_num);
00407     }
00408     return ret;
00409 }
00410 
00411 /** Executes the closing process of the decoder
00412  *
00413  *  @param p_ctrl Pointer to the control data of FLAC module.
00414  *  @param p_cb Pointer to the callback for notification of the process result.
00415  *
00416  *  @returns 
00417  *    Results of process. true is success. false is failure.
00418  */
00419 static void close_proc(flac_ctrl_t * const p_ctrl, const DEC_CbClose p_cb)
00420 {
00421     if ((p_ctrl != NULL) && (p_cb != NULL)) {
00422         flac_close(p_ctrl);
00423         p_cb();
00424     }
00425 }
00426 
00427 /** Executes the starting process of the pause
00428  *
00429  *  @param p_ctrl Pointer to the control data of FLAC module.
00430  *  @param buf_id Index of PCM buffer array.
00431  *  @param p_buf Pointer to PCM buffer array to use in this process.
00432  *  @param element_num Elements number of PCM buffer array.
00433  *
00434  *  @returns 
00435  *    Results of process. true is success. false is failure.
00436  */
00437 static bool pause_proc(const uint32_t buf_id,
00438         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num)
00439 {
00440     bool                ret = false;
00441     uint32_t            i;
00442     int32_t             result;
00443     const uint32_t      pause_data_size = SAMPLE_NUM_PER_UNIT_MS * sizeof(*p_buf[0]);
00444     rbsp_data_conf_t    cb_conf = {
00445         &write_callback,
00446         NULL
00447     };
00448 
00449     if ((p_buf != NULL) && (element_num > 0u) && 
00450         (element_num <= PCM_BUF_NUM) && ((buf_id + element_num) <= PCM_BUF_NUM)) {
00451         /* Audio output process */
00452         result = ESUCCESS;
00453         for (i = 0; (i < element_num) && (result == ESUCCESS); i++) {
00454             (void) memset(&p_buf[i], 0, pause_data_size);
00455             cb_conf.p_app_data = (void *)(buf_id + i);
00456             result = scux.write(&p_buf[i], pause_data_size, &cb_conf);
00457         }
00458         if (result == ESUCCESS) {
00459             ret = true;
00460         }
00461     }
00462     return ret;
00463 }
00464 
00465 /** Executes the starting process of the playback
00466  *
00467  *  @param p_ctrl Pointer to the control data of FLAC module.
00468  *  @param buf_id Index of PCM buffer array.
00469  *  @param p_buf Pointer to PCM buffer array to use in this process.
00470  *  @param element_num Elements number of PCM buffer array.
00471  *
00472  *  @returns 
00473  *    Results of process. true is success. false is failure.
00474  */
00475 static bool play_proc(flac_ctrl_t * const p_ctrl, const uint32_t buf_id,
00476         int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t element_num)
00477 {
00478     bool                ret = false;
00479     int32_t             result;
00480     uint32_t            i;
00481     uint32_t            decoded_cnt;
00482     uint32_t            num;
00483     uint32_t            read_byte[PCM_BUF_NUM];
00484     rbsp_data_conf_t    cb_conf = {
00485         &write_callback,
00486         NULL
00487     };
00488 
00489     if ((p_ctrl != NULL) && (p_buf != NULL) && (element_num > 0u) && 
00490         (element_num <= PCM_BUF_NUM) && ((buf_id + element_num) <= PCM_BUF_NUM)) {
00491         /* FLAC decoder process */
00492         decoded_cnt = 0u;
00493         do {
00494             num = get_audio_data(p_ctrl, p_buf[decoded_cnt], sizeof(p_buf[0])/sizeof(*p_buf[0]));
00495             read_byte[decoded_cnt] = num * sizeof(num);
00496             if (num > 0u) {
00497                 decoded_cnt++;
00498             }
00499         } while ((decoded_cnt < element_num) &&  (num > 0u));
00500         /* Audio output process */
00501         if (decoded_cnt > 0u) {
00502             result = ESUCCESS;
00503             for (i = 0; (i < decoded_cnt) && (result == ESUCCESS); i++) {
00504                 cb_conf.p_app_data = (void *)(buf_id + i);
00505                 result = scux.write(&p_buf[i], read_byte[i], &cb_conf);
00506             }
00507             if (result == ESUCCESS) {
00508                 ret = true;
00509             }
00510         }
00511     }
00512     return ret;
00513 }
00514 
00515 /** Gets the decoded data from FLAC decoder library
00516  *
00517  *  @param p_ctrl Pointer to the control data of FLAC module.
00518  *  @param p_buf Pointer to PCM buffer array to store the decoded data.
00519  *  @param buf_num Elements number of PCM buffer array.
00520  *
00521  *  @returns 
00522  *    Elements number of decoded data.
00523  */
00524 static uint32_t get_audio_data(flac_ctrl_t * const p_ctrl, 
00525                             int32_t * const p_buf, const uint32_t buf_num)
00526 {
00527     uint32_t    read_cnt = 0u;
00528     bool        result;
00529 
00530     if ((p_ctrl != NULL) && (p_buf != NULL) && (buf_num > 0u)) {
00531         result = flac_set_pcm_buf(p_ctrl, p_buf, buf_num);
00532         while ((result == true) && ((read_cnt + MAX_SAMPLE_PER_1BLOCK) <= buf_num)) {
00533             result = flac_decode(p_ctrl);
00534             read_cnt = flac_get_pcm_cnt(p_ctrl);
00535         }
00536     }
00537     return read_cnt;
00538 }
00539 
00540 /** Callback function of Audio Out Thread
00541  *
00542  *  @param result Result of the process of Audio Out Thread
00543  */
00544 static void data_out_callback(const bool result)
00545 {
00546     (void) send_mail(DEC_MAILID_CB_AUD_DATA_OUT, (uint32_t)result, MAIL_PARAM_NON);
00547 }
00548 
00549 /** Callback function of SCUX driver
00550  *
00551  *  @param p_data Pointer to PCM byffer array.
00552  *  @param result Result of the process.
00553  *  @param p_app_data The control ID of PCM buffer.
00554  */
00555 static void write_callback(void * p_data, int32_t result, void * p_app_data)
00556 {
00557     const uint32_t  buf_id = (uint32_t)p_app_data;
00558     bool            flag_result;
00559 
00560     UNUSED_ARG(p_data);
00561     if (result > 0) {
00562         flag_result = true;
00563     } else {
00564         flag_result = false;
00565     }
00566     (void) send_mail(DEC_MAILID_SCUX_WRITE_FIN, (uint32_t)flag_result, buf_id);
00567 }
00568 
00569 /** Callback function of SCUX driver
00570  *
00571  *  @param result Result of the process.
00572  */
00573 static void flush_callback(int32_t result)
00574 {
00575     bool        flag_result;
00576 
00577     if (result > 0) {
00578         flag_result = true;
00579     } else {
00580         flag_result = false;
00581     }
00582     (void) send_mail(DEC_MAILID_SCUX_FLUSH_FIN, (uint32_t)flag_result, MAIL_PARAM_NON);
00583 }
00584 
00585 /** Sends the mail to Decode thread
00586  *
00587  *  @param mail_id Mail ID
00588  *  @param param0 Parameter 0 of this mail
00589  *  @param param1 Parameter 1 of this mail
00590  *
00591  *  @returns 
00592  *    Results of process. true is success. false is failure.
00593  */
00594 static bool send_mail(const DEC_MAIL_ID mail_id, 
00595                             const uint32_t param0, const uint32_t param1)
00596 {
00597     bool            ret = false;
00598     osStatus        stat;
00599     dec_mail_t      * const p_mail = mail_box.alloc();
00600 
00601     if (p_mail != NULL) {
00602         p_mail->mail_id = mail_id;
00603         p_mail->param[MAIL_PARAM0] = param0;
00604         p_mail->param[MAIL_PARAM1] = param1;
00605         stat = mail_box.put(p_mail);
00606         if (stat == osOK) {
00607             ret = true;
00608         } else {
00609             (void) mail_box.free(p_mail);
00610         }
00611     }
00612     return ret;
00613 }
00614 
00615 /** Receives the mail to Decode thread
00616  *
00617  *  @param p_mail_id Pointer to the variable to store the mail ID
00618  *  @param p_param0 Pointer to the variable to store the parameter 0 of this mail
00619  *  @param p_param1 Pointer to the variable to store the parameter 1 of this mail
00620  *
00621  *  @returns 
00622  *    Results of process. true is success. false is failure.
00623  */
00624 static bool recv_mail(DEC_MAIL_ID * const p_mail_id, 
00625                         uint32_t * const p_param0, uint32_t * const p_param1)
00626 {
00627     bool            ret = false;
00628     osEvent         evt;
00629     dec_mail_t      *p_mail;
00630     
00631     if ((p_mail_id != NULL) && (p_param0 != NULL) && (p_param1 != NULL)) {
00632         evt = mail_box.get();
00633         if (evt.status == osEventMail) {
00634             p_mail = (dec_mail_t *)evt.value.p;
00635             if (p_mail != NULL) {
00636                 *p_mail_id = p_mail->mail_id;
00637                 *p_param0 = p_mail->param[MAIL_PARAM0];
00638                 *p_param1 = p_mail->param[MAIL_PARAM1];
00639                 ret = true;
00640             }
00641             (void) mail_box.free(p_mail);
00642         }
00643     }
00644     return ret;
00645 }
00646 
00647 /** Updates the status of Decode thread
00648  *
00649  *  @param stat New status of Decode thread
00650  *  @param p_play_info Pointer to the playback information of the playback file
00651  */
00652 static void update_decode_stat(const SYS_PlayStat stat, play_info_t * const p_play_info)
00653 {
00654     if (p_play_info != NULL) {
00655         if (p_play_info->play_stat != stat) {
00656             p_play_info->play_stat = stat;
00657             notify_decode_stat(p_play_info);
00658         }
00659     }
00660 }
00661 
00662 /** Updates the playback time
00663  *
00664  *  @param play_time Current playback time
00665  *  @param p_play_info Pointer to the playback information of the playback file
00666  */
00667 static void update_decode_playtime(const uint32_t play_time, play_info_t * const p_play_info)
00668 {
00669     if (p_play_info != NULL) {
00670         if (p_play_info->play_time != play_time) {
00671             p_play_info->play_time = play_time;
00672             notify_decode_stat(p_play_info);
00673         }
00674     }
00675 }
00676 
00677 /** Initialises the playback information
00678  *
00679  *  @param total_time Total playback time
00680  *  @param p_play_info Pointer to the playback information of the playback file
00681  */
00682 static void init_decode_playinfo(const uint32_t total_time, play_info_t * const p_play_info)
00683 {
00684     if (p_play_info != NULL) {
00685         p_play_info->play_stat  = SYS_PLAYSTAT_STOP;
00686         p_play_info->play_time  = 0u;
00687         p_play_info->total_time = total_time;
00688     }
00689 }
00690 
00691 /** Notifies Main thread of the status of Decode thread
00692  *
00693  *  @param p_play_info Pointer to the playback information of the playback file
00694  */
00695 static void notify_decode_stat(const play_info_t * const p_play_info)
00696 {
00697     if (p_play_info != NULL) {
00698         (void) sys_notify_play_time(p_play_info->play_stat, 
00699                     p_play_info->play_time, p_play_info->total_time);
00700     }
00701 }