/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
/* rbplay source */
/* playback control & rockbox codec porting & codec thread */

#ifdef MBED
#include "mbed.h"
#include "rtos.h"
#endif
#include "SDFileSystem.h"
#include "app_audio.h"
#include "audioflinger.h"
#include "cqueue.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "hal_uart.h"
#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "audiohw.h"
#include "channel_mode.h"
#include "codec_platform.h"
#include "codeclib.h"
#include "codecs.h"
#include "compressor.h"
#include "dsp_core.h"
#include "eq.h"
#include "metadata.h"
#include "metadata_parsers.h"
#include "pga.h"

#include "app_key.h"
#include "app_overlay.h"
#include "app_thread.h"
#include "app_utils.h"
#include "hal_overlay.h"
#include "rbpcmbuf.h"
#include "rbplay.h"

#include "rb_ctl.h"
#include "rbplaysd.h"

/* Internals */

void rb_ctl_wait_lock_thread(bool lock);
void app_rbcodec_ctl_set_play_status(bool st);
extern bool app_rbcodec_check_hfp_active(void);

#include "SDFileSystem.h"

extern "C" void hal_sysfreq_print(void);

#define _LOG_TAG "[rb_ctl] "
#undef __attribute__(a)

#define RBPLAY_DEBUG 1
#if RBPLAY_DEBUG
#define _LOG_DBG(str, ...) TRACE(0, _LOG_TAG "" str, ##__VA_ARGS__)
#define _LOG_ERR(str, ...)                                                     \
  TRACE(0,                                                                     \
        _LOG_TAG "err:"                                                        \
                 "" str,                                                       \
        ##__VA_ARGS__)
#else
#define _LOG_DBG(str, ...)
#define _LOG_ERR(str, ...)                                                     \
  TRACE(0,                                                                     \
        _LOG_TAG "err:"                                                        \
                 "" str,                                                       \
        ##__VA_ARGS__)
#endif

#include "rb_ctl.h"
void rb_thread_send_resume(void);

typedef struct {
  uint32_t evt;
  uint32_t arg;
} RBCTL_MSG_BLOCK;

static osThreadId rb_ctl_tid;
static void rb_ctl_thread(void const *argument);
static int rb_ctl_default_priority;
osThreadDef(rb_ctl_thread, osPriorityHigh, 1, 1024 * 4, "rb_ctl");

#define RBCTL_MAILBOX_MAX (20)
osMailQDef(rb_ctl_mailbox, RBCTL_MAILBOX_MAX, RBCTL_MSG_BLOCK);
static osMailQId rb_ctl_mailbox = NULL;

int rb_ctl_mailbox_put(RBCTL_MSG_BLOCK *msg_src);

// playlist
extern playlist_struct sd_playlist;

rb_ctl_struct rb_ctl_context;

extern void rb_thread_set_decode_vars(int fd, int type, void *id3);
extern void rb_play_codec_run(void);
extern void rb_codec_set_halt(int halt);
extern void rb_player_sync_set_wait_thread(osThreadId tid);
extern void rb_player_sync_wait_close(void);
extern bool rb_pcmbuf_suspend_play_loop(void);
void app_rbplay_load_playlist(playlist_struct *list);
int rb_thread_post_msg(RB_MODULE_EVT evt, uint32_t arg);

static rb_ctl_status rb_ctl_get_status(void) { return rb_ctl_context.status; }

bool rb_ctl_parse_file(const char *file_path) {
  /* open file */

  _LOG_DBG(1, "open file  %s\n", file_path);
  rb_ctl_context.file_handle = open((const char *)file_path, O_RDWR);
  if (rb_ctl_context.file_handle <= 0) {
    _LOG_DBG(1, "open file %s failed\n", file_path);
    return false;
  }

  if (!get_metadata(&rb_ctl_context.song_id3, rb_ctl_context.file_handle,
                    rb_ctl_context.rb_fname)) {
    _LOG_DBG(0, "get_metadata failed\n");
    close(rb_ctl_context.file_handle);
    return false;
  }

  _LOG_DBG(4, "%s bitr:%d,saps %d, freq:%d\n", __func__,
           rb_ctl_context.song_id3.bitrate, rb_ctl_context.song_id3.samples,
           rb_ctl_context.song_id3.frequency);

  rb_thread_set_decode_vars(rb_ctl_context.file_handle,
                            rb_ctl_context.song_id3.codectype,
                            &rb_ctl_context.song_id3);

  return true;
}

void rb_ctl_vol_operation(bool inc) {
  uint32_t ret;
  struct AF_STREAM_CONFIG_T *stream_cfg = NULL;

  _LOG_DBG(2, "%s inc:%d , ", __func__, inc);

  if (inc) {
    if (rb_ctl_context.rb_player_vol < 16) {
      rb_ctl_context.rb_player_vol++;
    }
  } else {
    if (rb_ctl_context.rb_player_vol > 1) {
      rb_ctl_context.rb_player_vol--;
    }
  }
  if (rb_ctl_context.status != RB_CTL_PLAYING)
    return;

  ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg,
                          true);
  if (ret == 0) {
    stream_cfg->vol = rb_ctl_context.rb_player_vol;
    af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, stream_cfg);
  }
}

bool rb_ctl_is_playing(void) {
  return (rb_ctl_context.status == RB_CTL_PLAYING);
}

void rb_ctl_set_vol(uint32_t vol) {
  uint32_t ret;
  struct AF_STREAM_CONFIG_T *stream_cfg = NULL;

  _LOG_DBG(2, "%s set vol as :%d , ", __func__, vol);

  if (rb_ctl_context.status != RB_CTL_PLAYING)
    return;

  vol = (vol > 16) ? 16 : vol;
  rb_ctl_context.rb_player_vol = vol;

  ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg,
                          true);
  if (ret == 0) {
    stream_cfg->vol = rb_ctl_context.rb_player_vol;
    af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, stream_cfg);
  }
}

void rb_ctl_stop_play(void) {
  _LOG_DBG(1, "%s  \n", __func__);

  rb_codec_set_halt(1);
  // close file
  _LOG_DBG(0, " af  stream stop \n");
  af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
  _LOG_DBG(0, " af	stream close \n");
  af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
  _LOG_DBG(0, " close file \n");
  if (rb_ctl_context.file_handle != -1)
    close(rb_ctl_context.file_handle);
  rb_ctl_context.file_handle = -1;
  // release frequency
  _LOG_DBG(0, " release freq  \n");

  return;
}

void rb_ctl_sync_stop_play(void) {
  rb_player_sync_set_wait_thread(osThreadGetId());

  rb_ctl_stop_play();

  rb_player_sync_wait_close();
  // close file
  _LOG_DBG(0, " close file \n");
  if (rb_ctl_context.file_handle != -1)
    close(rb_ctl_context.file_handle);
  rb_ctl_context.file_handle = -1;
}

void rb_ctl_pause_playing(void) {
  af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
  _LOG_DBG(0, " af   stream close \n");
  af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
  // wait decoder suspend
  // osDelay(200);
  // while(!rb_pcmbuf_suspend_play_loop()) {
  // osThreadYield();
  //    osDelay(1);
  // }

  _LOG_DBG(1, "%s sucessed ", __func__);
}

void rb_ctl_resume_playing(void) {
#ifndef __TWS__
  rb_pcmbuf_init();
#endif
}

void rb_ctl_set_priority(int priority) {
  osThreadSetPriority(rb_ctl_tid, (osPriority)priority);
}

int rb_ctl_get_priority(void) { return (int)osThreadGetPriority(rb_ctl_tid); }

int rb_ctl_get_default_priority(void) { return rb_ctl_default_priority; }

void rb_ctl_reset_priority(void) {
  osThreadSetPriority(rb_ctl_tid, (osPriority)rb_ctl_default_priority);
}

#ifdef __IAG_BLE_INCLUDE__
extern "C" void app_ble_inform_music_switch(uint16_t index);
#endif
static int rb_ctl_handle_event(RBCTL_MSG_BLOCK *msg_body) {
  RB_MODULE_EVT evt = (RB_MODULE_EVT)msg_body->evt;
  uint32_t arg = msg_body->arg;
  //    hal_sysfreq_print();

  switch (evt) {
  case RB_MODULE_EVT_PLAY:
    if (rb_ctl_context.status != RB_CTL_IDLE) {
      if (rb_ctl_context.status == RB_CTL_SUSPEND)
        rb_thread_send_resume();
      else
        _LOG_DBG(2, "%s  st  %d not in idle \n", __func__,
                 rb_ctl_context.status);
      break;
    }
    _LOG_DBG(3, " %s start %d/%d ", __func__, rb_ctl_context.curr_song_idx,
             sd_playlist.total_songs);
    if (sd_playlist.total_songs > 0) {
      playlist_item *it;

      it = app_rbplay_get_playitem(rb_ctl_context.curr_song_idx);

      if (it == NULL) {
        _LOG_DBG(2, " %s get item fail idx %d", __func__,
                 rb_ctl_context.curr_song_idx);
      }

      _LOG_DBG(2, "%s  start songidx %d \n", __func__,
               rb_ctl_context.curr_song_idx);

      memcpy(rb_ctl_context.rb_audio_file, it->file_path,
             sizeof(uint16_t) * FILE_PATH_LEN - 4);
      memcpy(rb_ctl_context.rb_fname, it->file_name,
             sizeof(rb_ctl_context.rb_fname));

      if (rb_ctl_parse_file((const char *)rb_ctl_context.rb_audio_file)) {
        _LOG_DBG(2, "%s  start init, the tid 0x%x\n", __func__,
                 osThreadGetId());
        rb_play_codec_init();
        _LOG_DBG(1, "%s  start run\n", __func__);
        rb_play_codec_run();
        rb_ctl_context.status = RB_CTL_PLAYING;
        app_rbcodec_ctl_set_play_status(true);
        break;
      } else {
        _LOG_DBG(2, "%s  evt  %d parse fail,find next\n", __func__,
                 msg_body->evt);
        rb_thread_post_msg(RB_MODULE_EVT_PLAY_NEXT, true);
      }

    } else {
      _LOG_DBG(2, "%s  evt  %d no songs\n", __func__, msg_body->evt);
    }
    break;
  case RB_MODULE_EVT_STOP:
    if (rb_ctl_context.status == RB_CTL_IDLE) {
      _LOG_DBG(2, "%s  st  %d in idle \n", __func__, rb_ctl_context.status);
      break;
    }
    if (rb_ctl_context.status == RB_CTL_SUSPEND) {
      // osDelay(100);
      rb_ctl_resume_playing();
      rb_ctl_context.status = RB_CTL_PLAYING;
    }
    rb_ctl_sync_stop_play();
    rb_ctl_context.status = RB_CTL_IDLE;
    app_rbcodec_ctl_set_play_status(false);
    break;
  case RB_MODULE_EVT_SUSPEND:
    if (rb_ctl_context.status != RB_CTL_PLAYING) {
      _LOG_DBG(2, "%s  st  %d not running \n", __func__, rb_ctl_context.status);
      break;
    }
    rb_ctl_pause_playing();
    rb_ctl_context.status = RB_CTL_SUSPEND;
    break;
  case RB_MODULE_EVT_RESUME:
    if (rb_ctl_context.status != RB_CTL_SUSPEND) {
      _LOG_DBG(2, "%s  st  %d not suspend \n", __func__, rb_ctl_context.status);
      break;
    }
    rb_ctl_resume_playing();
    rb_ctl_context.status = RB_CTL_PLAYING;
    break;
  case RB_MODULE_EVT_PLAY_NEXT:
    if (rb_ctl_context.status == RB_CTL_PLAYING) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
    } else if (rb_ctl_context.status == RB_CTL_SUSPEND) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
    } else {
    }
    if (arg == 0) {
      rb_ctl_context.curr_song_idx--;

      if (rb_ctl_context.curr_song_idx == 0xffff)
        rb_ctl_context.curr_song_idx = sd_playlist.total_songs - 1;

    } else {

      rb_ctl_context.curr_song_idx++;

      if (rb_ctl_context.curr_song_idx >= sd_playlist.total_songs)
        rb_ctl_context.curr_song_idx = 0;
    }

#ifdef __IAG_BLE_INCLUDE__
    app_ble_inform_music_switch(rb_ctl_context.curr_song_idx);
#endif

    rb_thread_post_msg(RB_MODULE_EVT_PLAY, 0);
    break;
  case RB_MODULE_EVT_CHANGE_VOL:
    rb_ctl_vol_operation(arg);
    break;
  case RB_MODULE_EVT_SET_VOL:
    rb_ctl_set_vol(arg);
    break;
  case RB_MODULE_EVT_CHANGE_IDLE:
    rb_ctl_stop_play();
    rb_ctl_context.status = RB_CTL_IDLE;
    break;
  case RB_MODULE_EVT_PLAY_IDX:
    if (arg > sd_playlist.total_songs - 1) {
      break;
    }
    if (rb_ctl_context.status == RB_CTL_PLAYING) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
    } else if (rb_ctl_context.status == RB_CTL_SUSPEND) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
    } else {
    }

    rb_ctl_context.curr_song_idx = (uint16_t)arg;

    rb_thread_post_msg(RB_MODULE_EVT_PLAY, 0);
    break;
// for voice cocah
#if 0
        case SBCREADER_ACTION_INIT:
            //prepare fs
            voiceCocah_prepare_fs();
            //init the data buff
            voiceCocah_read_sbc_data();
            break;
        case SBCREADER_ACTION_RUN:
            //fill sbc queue
            voiceCocah_read_sbc_data();
            break;
        case SBCREADER_ACTION_STOP:
            //release the res
            voiceCocah_stop_clean();
            rb_ctl_reset_priority();
            break;
#endif

#ifdef __TWS__
  case RB_MODULE_EVT_RESTORE_DUAL_PLAY:
    extern void rb_restore_dual_play(uint8_t stream_type);
    rb_restore_dual_play(arg);
    break;
#endif
  case RB_MODULE_EVT_DEL_FILE:
    static rb_ctl_status prev_status = rb_ctl_context.status;
    if (rb_ctl_context.status == RB_CTL_PLAYING) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
      rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE, arg);
    } else if (rb_ctl_context.status == RB_CTL_SUSPEND) {
      rb_thread_post_msg(RB_MODULE_EVT_STOP, 0);
      rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE, arg);
    } else {
      app_ctl_remove_file(arg);
      if (prev_status == RB_CTL_PLAYING) {
        rb_thread_post_msg(RB_MODULE_EVT_PLAY, 0);
      }
    }

    break;
#if defined(TWS_LINEIN_PLAYER)
  case RB_MODULE_EVT_LINEIN_START:
    extern int app_linein_codec_start(void);
    app_linein_codec_start();
    break;

  case RB_MODULE_EVT_RECONFIG_STREAM:
    extern void rb_tws_reconfig_stream(uint32_t arg);
    rb_tws_reconfig_stream(arg);
    break;

  case RB_MODULE_EVT_SET_TWS_MODE:
    break;
#endif
#ifdef SBC_RECORD_TEST

  case SBC_RECORD_ACTION_START: {
    rb_ctl_context.sbc_record_on = true;
    app_rbplay_set_store_flag(true);
    app_rbplay_open_sbc_file();

  } break;

  case SBC_RECORD_ACTION_DATA_IND: {
    if (rb_ctl_context.sbc_record_on) {
      app_rbplay_process_sbc_data();
    }
  } break;

  case SBC_RECORD_ACTION_STOP: {
    rb_ctl_context.sbc_record_on = false;
    app_rbplay_set_store_flag(false);
    app_rbplay_close_sbc_file();
  } break;
#endif
  default:
    break;
  }
  if (SBC_RECORD_ACTION_DATA_IND != msg_body->evt)
    _LOG_DBG(3, "%s  rbcodec evt  %d  ,st %d ended\n", __func__, msg_body->evt,
             rb_ctl_context.status);
  return 0;
}

int rb_thread_post_msg(RB_MODULE_EVT evt, uint32_t arg) {
  int ret;
  RBCTL_MSG_BLOCK msg;

  if (!rb_ctl_tid)
    return 0;
  /* APIs */
  msg.evt = (uint32_t)evt;
  msg.arg = (uint32_t)arg;
  ret = rb_ctl_mailbox_put(&msg);

  _LOG_DBG(3, "%s   ret %d evt:%d\n", __func__, ret, evt);
  return 0;
}

void app_wait_player_stoped(void) {
  while (rb_ctl_context.status != RB_CTL_IDLE)
    osThreadYield();
}

void app_wait_player_suspend(void) {
  if (rb_ctl_context.status == RB_CTL_IDLE)
    return;

  while (rb_ctl_context.status != RB_CTL_SUSPEND)
    osThreadYield();
}

void app_wait_player_resumed(void) {
  if (rb_ctl_context.status == RB_CTL_IDLE)
    return;

  while (rb_ctl_context.status != RB_CTL_PLAYING)
    osThreadYield();
}

void rb_thread_send_play(void) {
  _LOG_DBG(1, " %s ", __FUNCTION__);
  rb_thread_post_msg(RB_MODULE_EVT_PLAY, (uint32_t)osThreadGetId());
}

void rb_thread_send_stop(void) {
  _LOG_DBG(1, " %s ", __FUNCTION__);
  rb_thread_post_msg(RB_MODULE_EVT_STOP, (uint32_t)osThreadGetId());

  osDelay(200);
  app_wait_player_stoped();
}

void rb_thread_send_pause(void) {
  _LOG_DBG(1, " %s ", __FUNCTION__);

  rb_thread_post_msg(RB_MODULE_EVT_SUSPEND, (uint32_t)osThreadGetId());
  app_wait_player_suspend();

  _LOG_DBG(1, " %s end", __FUNCTION__);
}

void rb_thread_send_resume(void) {
  _LOG_DBG(1, " %s ", __FUNCTION__);

  rb_thread_post_msg(RB_MODULE_EVT_RESUME, (uint32_t)osThreadGetId());

  _LOG_DBG(1, " %s end", __FUNCTION__);
}

void rb_play_dual_play_restore(uint8_t stream_type) {
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);

  rb_thread_post_msg(RB_MODULE_EVT_RESTORE_DUAL_PLAY, stream_type);
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);
}

void rb_thread_send_switch(bool next) {
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);

  rb_thread_post_msg(RB_MODULE_EVT_PLAY_NEXT, next);

  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);
}

void rb_play_linein_start(void) {
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);

  rb_thread_post_msg(RB_MODULE_EVT_LINEIN_START, 0);
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);
}

void rb_play_reconfig_stream(uint32_t arg) {
  _LOG_DBG(3, "%s %d arg:0x%x\n", __func__, __LINE__, arg);

  rb_thread_post_msg(RB_MODULE_EVT_RECONFIG_STREAM, arg);
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);
}

void rb_play_set_tws_mode(uint32_t arg) {
  _LOG_DBG(3, "%s %d arg:0x%x\n", __func__, __LINE__, arg);

  rb_thread_post_msg(RB_MODULE_EVT_SET_TWS_MODE, arg);
  _LOG_DBG(2, "%s %d \n", __func__, __LINE__);
}

void rb_thread_send_play_idx(uint32_t array_subidx) {
  _LOG_DBG(2, " %s array_subidx %d, ", __FUNCTION__, array_subidx);

  rb_thread_post_msg(RB_MODULE_EVT_PLAY_IDX, array_subidx);
}

void rb_thread_send_vol(bool inc) {
  _LOG_DBG(2, " %s inc %d, ", __FUNCTION__, inc);

  rb_thread_post_msg(RB_MODULE_EVT_CHANGE_VOL, inc);
}

void rb_thread_send_status_change(void) {
  _LOG_DBG(1, " %s , ", __FUNCTION__);

  rb_thread_post_msg(RB_MODULE_EVT_CHANGE_IDLE, 0);
}

void rb_thread_set_vol(uint32_t vol) {
  _LOG_DBG(1, " %s , ", __FUNCTION__);

  rb_thread_post_msg(RB_MODULE_EVT_SET_VOL, vol);
}

void rb_thread_send_del_file(uint16_t idx) {
  _LOG_DBG(1, " %s , ", __FUNCTION__);

  rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE, idx);
}

void rb_thread_send_sbc_record_start(void) {
  _LOG_DBG(1, " %s , ", __FUNCTION__);

  rb_thread_post_msg(SBC_RECORD_ACTION_START, (uint32_t)osThreadGetId());
}

void rb_thread_send_sbc_record_data_ind(void) {
  if (!rb_ctl_context.sbc_record_on)
    return;
  //  _LOG_DBG(1," %s , ",__FUNCTION__);
  rb_thread_post_msg(SBC_RECORD_ACTION_DATA_IND, (uint32_t)osThreadGetId());
}

void rb_thread_send_sbc_record_stop(void) {
  _LOG_DBG(1, " %s , ", __FUNCTION__);

  rb_thread_post_msg(SBC_RECORD_ACTION_STOP, (uint32_t)osThreadGetId());
}

// interface for audio module
static bool user_key_pause_stream = false;
void app_rbplay_audio_reset_pause_status(void) {
  user_key_pause_stream = false;
}

int app_rbplay_audio_onoff(bool onoff, uint16_t aud_id) {
  _LOG_DBG(3, " %s onoff %d, get status:%d", __FUNCTION__, onoff,
           rb_ctl_get_status());

  if (app_rbcodec_check_hfp_active() && !onoff) {
    if (RB_CTL_PLAYING == rb_ctl_get_status()) {
      rb_thread_send_pause();
    }
  } else if (!onoff) {
    // rb_thread_send_stop();
    rb_thread_send_pause();
  } else {
    if (!user_key_pause_stream) {
      if (RB_CTL_SUSPEND == rb_ctl_get_status()) {
        rb_thread_send_resume();
        app_wait_player_resumed();
      } else {
        rb_thread_send_play();
      }
    }
  }

  return 0;
}

void app_rbplay_pause_resume(void) {
  _LOG_DBG(2, " %s get status:%d", __func__, rb_ctl_get_status());

  user_key_pause_stream = true;
  if (RB_CTL_SUSPEND == rb_ctl_get_status()) {
    user_key_pause_stream = false;
    rb_thread_send_resume();
  }
  if (RB_CTL_PLAYING == rb_ctl_get_status()) {
    user_key_pause_stream = true;
    rb_thread_send_pause();
  }
}
// sbc reader run within thread

static int rb_ctl_mailbox_init(void) {
  rb_ctl_mailbox = osMailCreate(osMailQ(rb_ctl_mailbox), NULL);
  if (rb_ctl_mailbox == NULL) {
    TRACE(0, "Failed to Create rb_ctl_mailbox\n");
    return -1;
  }
  return 0;
}

int rb_ctl_mailbox_put(RBCTL_MSG_BLOCK *msg_src) {
  osStatus status;

  RBCTL_MSG_BLOCK *msg_p = NULL;

  msg_p = (RBCTL_MSG_BLOCK *)osMailAlloc(rb_ctl_mailbox, 0);
  if (!msg_p) {
    TRACE(3, "%s fail, evt:%d,arg=%d \n", __func__, msg_src->evt, msg_src->arg);
    return -1;
  }

  ASSERT(msg_p, "osMailAlloc error");

  msg_p->evt = msg_src->evt;
  msg_p->arg = msg_src->arg;

  status = osMailPut(rb_ctl_mailbox, msg_p);

  return (int)status;
}

int rb_ctl_mailbox_free(RBCTL_MSG_BLOCK *msg_p) {
  osStatus status;

  status = osMailFree(rb_ctl_mailbox, msg_p);

  return (int)status;
}

int rb_ctl_mailbox_get(RBCTL_MSG_BLOCK **msg_p) {
  osEvent evt;
  evt = osMailGet(rb_ctl_mailbox, osWaitForever);
  if (evt.status == osEventMail) {
    *msg_p = (RBCTL_MSG_BLOCK *)evt.value.p;
    return 0;
  }
  return -1;
}

#if 0
void rb_ctl_action_init(void)
{

    bool ind = voiceCocah_get_indication();
    TRACE(2," %s Cocah %d",__func__,ind);

    if( !ind) return ;

    //  rb_ctl_set_priority(osPriorityHigh);

    rb_thread_post_msg(SBCREADER_ACTION_INIT,(uint32_t)osThreadGetId());
}

void rb_ctl_action_run(void)
{
    bool ind = voiceCocah_get_indication();
    TRACE(2," %s Cocah %d",__func__,ind);

    if( !ind) return ;

    rb_thread_post_msg(SBCREADER_ACTION_RUN,(uint32_t)osThreadGetId());
}

void rb_ctl_action_stop(void)
{
    bool ind = voiceCocah_get_indication();
    TRACE(2," %s Cocah %d",__func__,ind);

    if( !ind) return ;

    rb_thread_post_msg(SBCREADER_ACTION_STOP,(uint32_t)osThreadGetId());

}
#endif
static void rb_ctl_thread(void const *argument) {
  osEvent evt;
#if 1
  app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_208M);

  app_rbplay_load_playlist(&sd_playlist);
#endif
  memset(&rb_ctl_context, 0x0, sizeof(rb_ctl_struct));
  rb_ctl_context.rb_player_vol = 6;
  rb_ctl_context.status = RB_CTL_IDLE;

  rb_ctl_context.curr_song_idx = 0;
  // load playlist here

  // voiceCocah_init();

  rb_ctl_context.init_done = true;

  while (1) {
    RBCTL_MSG_BLOCK *msg_p = NULL;

    app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_32K);

    if (!rb_ctl_mailbox_get(&msg_p)) {
      app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_104M);

      rb_ctl_handle_event(msg_p);

      rb_ctl_mailbox_free(msg_p);
    }
  }
}

int rb_ctl_init(void) {
  _LOG_DBG(1, "%s \n", __func__);

  rb_ctl_context.init_done = false;
  rb_ctl_context.sbc_record_on = false;

  app_rbplay_open();

  rb_ctl_mailbox_init();

  rb_ctl_tid = osThreadCreate(osThread(rb_ctl_thread), NULL);
  rb_ctl_default_priority = osPriorityAboveNormal;

  if (rb_ctl_tid == NULL) {
    TRACE(0, "Failed to Create rb_ctl_thread\n");
    return 0;
  }
  _LOG_DBG(1, "Leave %s \n", __func__);
  return 0;
}

uint8_t rb_ctl_get_vol(void) { return rb_ctl_context.rb_player_vol; }

bool rb_ctl_is_init_done(void) { return rb_ctl_context.init_done; }

bool rb_ctl_is_paused(void) { return (RB_CTL_SUSPEND == rb_ctl_get_status()); }

uint16_t rb_ctl_songs_count(void) { return sd_playlist.total_songs; }
