pinebuds/apps/audioplayers/rbplay/rbplay.cpp

576 lines
14 KiB
C++

/***************************************************************************
*
* 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 */
#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef MBED
#include "mbed.h"
#include "rtos.h"
#endif
#include "app_overlay.h"
#include "apps.h"
#include "audioflinger.h"
#include "codecs.h"
#include "eq_export.h"
#include "hal_overlay.h"
#include "hal_trace.h"
#include "metadata.h"
#include "app_key.h"
#include "app_thread.h"
#include "app_utils.h"
#include "rbpcmbuf.h"
#include "rbplay.h"
#include "rbplaysd.h"
#include "utils.h"
#ifdef __TWS__
#include "app_tws.h"
#endif
// TODO: remove
#define BT_STREAM_RBCODEC 0x10 // from rockbox decoder
extern "C" {
void flac_codec_main(int r);
void flac_codec_run(void);
void wav_codec_main(int r);
void wav_codec_run(void);
void mpa_codec_main(int r);
void mpa_codec_run(void);
void ape_codec_main(int r);
void ape_codec_run(void);
void sbc_codec_main(int r);
void sbc_codec_run(void);
}
extern void rb_pcm_player_open(enum AUD_BITS_T bits,
enum AUD_SAMPRATE_T sample_rate,
enum AUD_CHANNEL_NUM_T channel_num, uint8_t vol);
#if defined(__TWS__)
typedef struct _rb_tws_codec_info {
uint8_t update_codec_info;
int32_t sample_freq;
uint8_t channel_num;
} rb_tws_codec_info;
rb_tws_codec_info codec_info = {1, 44100, 2};
#endif
static osThreadId rb_decode_tid = NULL;
static osThreadId rb_caller_tid = NULL;
typedef struct {
uint32_t evt;
uint32_t arg;
} RBTHREAD_MSG_BLOCK;
#define RBTHREAD_MAILBOX_MAX (10)
osMailQDef(rb_decode_mailbox, RBTHREAD_MAILBOX_MAX, RBTHREAD_MSG_BLOCK);
int rb_decode_mailbox_put(RBTHREAD_MSG_BLOCK *msg_src);
static osMailQId rb_decode_mailbox = NULL;
static void rb_decode_thread(void const *argument);
osThreadDef(rb_decode_thread, osPriorityAboveNormal, 1, 1024 * 2,
"rb_decorder");
// rbcodec info
static int song_fd;
static int song_format;
static struct mp3entry *current_id3;
static uint8_t rbplay_loop_on;
static volatile int rb_decode_halt_flag = 1;
struct codec_api ci_api;
struct codec_api *ci = &ci_api;
// TODO
volatile osThreadId thread_tid_waiter = NULL;
void init_dsp(void);
void codec_configure(int setting, intptr_t value);
uint16_t g_rbplayer_curr_song_idx = 0;
extern void app_rbplay_exit(void);
extern void bt_change_to_iic(APP_KEY_STATUS *status, void *param);
extern void rb_thread_send_switch(bool next);
extern void rb_thread_send_status_change(void);
enum APP_SYSFREQ_FREQ_T rb_player_get_work_freq(void);
static void rb_player_sync_close_done(void) { thread_tid_waiter = NULL; }
extern void rb_check_stream_reconfig(int32_t freq, uint8_t ch);
static void f_codec_pcmbuf_insert_callback(const void *ch1, const void *ch2,
int count) {
struct dsp_buffer src;
struct dsp_buffer dst;
src.remcount = count;
src.pin[0] = (const unsigned char *)ch1;
src.pin[1] = (const unsigned char *)ch2;
src.proc_mask = 0;
if (rb_codec_running() == 0)
return;
#ifndef __TWS__
while (src.remcount > 0) {
dst.remcount = 0;
dst.p16out = (short *)rb_pcmbuf_request_buffer(&dst.bufcount);
if (dst.p16out == NULL) {
warn("No pcm buffer");
osThreadYield();
} else {
dsp_process(ci->dsp, &src, &dst);
if (dst.remcount > 0) {
rb_pcmbuf_write(dst.remcount);
}
}
}
#else
if (codec_info.update_codec_info) {
rb_set_sbc_encoder_freq_ch(
codec_info.sample_freq,
codec_info.channel_num); // should call this to set trigger timer
rb_check_stream_reconfig(codec_info.sample_freq, codec_info.channel_num);
codec_info.update_codec_info = 0;
}
if (tws_local_player_need_tran_2_slave()) {
rb_tws_start_master_player(BT_STREAM_RBCODEC);
}
while (1) {
uint8_t *pcm_buff = NULL;
dst.remcount = 0;
dst.bufcount = MIN(src.remcount, 128); /* Arbitrary min request */
dst.p16out = (short *)rb_pcmbuf_request_buffer(&dst.bufcount);
pcm_buff = (uint8_t *)dst.p16out;
ASSERT(pcm_buff, "Should request buffer");
dsp_process(ci->dsp, &src, &dst);
if (dst.remcount > 0) {
while (rb_push_pcm_in_tws_buffer(pcm_buff, dst.remcount * 2 * 2) == 0) {
osDelay(2);
}
}
if (src.remcount <= 0) {
return; /* No input remains and DSP purged */
}
}
#endif
}
static void f_audio_codec_update_elapsed(unsigned long elapsed) {
// info("Update elapsed: %d", elapsed);
return;
}
static size_t f_codec_filebuf_callback(void *ptr, size_t size) {
ssize_t ret;
ret = read(song_fd, ptr, size);
if (ret < 0) {
error("File read error: %d", ret);
}
return ret;
}
static void *f_codec_request_buffer_callback(size_t *realsize, size_t reqsize) {
return NULL;
}
static void *f_codec_advance_buffer_callback(size_t amount) {
off_t ret = lseek(song_fd, (off_t)(ci->curpos + amount), SEEK_SET);
if (ret < 0) {
error("File seek fail");
return NULL;
}
ci->curpos += amount;
return (void *)ci;
}
static bool f_codec_seek_buffer_callback(size_t newpos) {
off_t ret = lseek(song_fd, (off_t)newpos, SEEK_SET);
if (ret < 0) {
error("File seek fail");
return false;
}
ci->curpos = newpos;
return true;
}
static void f_codec_seek_complete_callback(void) {
info("Seek complete");
dsp_configure(ci->dsp, DSP_FLUSH, 0);
}
static void f_audio_codec_update_offset(size_t offset) {}
static void f_codec_configure_callback(int setting, intptr_t value) {
dsp_configure(ci->dsp, setting, value);
#ifdef __TWS__
if (setting == DSP_SET_FREQUENCY) {
if (codec_info.sample_freq != value)
codec_info.update_codec_info = 1;
codec_info.sample_freq = value;
} else if (setting == DSP_SET_STEREO_MODE) {
if (codec_info.channel_num != (value == STEREO_MONO ? 1 : 2))
codec_info.update_codec_info = 1;
codec_info.channel_num = value == STEREO_MONO ? 1 : 2;
}
#endif
}
static enum codec_command_action f_codec_get_command_callback(intptr_t *param) {
if (rb_decode_halt_flag == 1)
return CODEC_ACTION_HALT;
return CODEC_ACTION_NULL;
}
static bool f_codec_loop_track_callback(void) { return false; }
static void init_ci_file(void) {
ci->codec_get_buffer = 0;
ci->pcmbuf_insert = f_codec_pcmbuf_insert_callback;
ci->set_elapsed = f_audio_codec_update_elapsed;
ci->read_filebuf = f_codec_filebuf_callback;
ci->request_buffer = f_codec_request_buffer_callback;
ci->advance_buffer = f_codec_advance_buffer_callback;
ci->seek_buffer = f_codec_seek_buffer_callback;
ci->seek_complete = f_codec_seek_complete_callback;
ci->set_offset = f_audio_codec_update_offset;
ci->configure = f_codec_configure_callback;
ci->get_command = f_codec_get_command_callback;
ci->loop_track = f_codec_loop_track_callback;
}
static void rb_play_init(void) {
init_dsp();
init_ci_file();
#ifndef __TWS__
rb_pcmbuf_init();
#endif
}
void rb_play_codec_init(void) {
RBTHREAD_MSG_BLOCK msg;
msg.evt = (uint32_t)RB_CTRL_CMD_CODEC_INIT;
msg.arg = (uint32_t)0;
rb_decode_mailbox_put(&msg);
}
void rb_play_codec_run(void) {
RBTHREAD_MSG_BLOCK msg;
msg.evt = (uint32_t)RB_CTRL_CMD_CODEC_RUN;
msg.arg = (uint32_t)0;
rb_decode_mailbox_put(&msg);
}
static int rb_codec_init_desc(void) {
info("Init decode format: %d", song_format);
switch (song_format) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
app_overlay_select(APP_OVERLAY_MPA);
mpa_codec_main(CODEC_LOAD);
break;
// TODO: add APP_OVERLAY_APE
#if 0
case AFMT_APE:
app_overlay_select(APP_OVERLAY_APE);
ape_codec_main(CODEC_LOAD);
break;
case AFMT_SBC:
app_overlay_select(APP_OVERLAY_A2DP);
sbc_codec_main(CODEC_LOAD);
break;
case AFMT_FLAC:
app_overlay_select(APP_OVERLAY_FLAC);
flac_codec_main(CODEC_LOAD);
break;
case AFMT_PCM_WAV:
app_overlay_select(APP_OVERLAY_WAV);
wav_codec_main(CODEC_LOAD);
break;
#endif
default:
error("unkown codec type init\n");
break;
}
return 0;
}
static int rb_codec_loop_on(void) {
#ifdef __TWS__
// set start transfer to slave
tws_local_player_set_tran_2_slave_flag(1);
#endif
switch (song_format) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
mpa_codec_run();
break;
#if 0
case AFMT_SBC:
sbc_codec_run();
break;
case AFMT_FLAC:
flac_codec_run();
break;
case AFMT_PCM_WAV:
wav_codec_run();
break;
case AFMT_APE:
ape_codec_run();
break;
#endif
default:
error("unkown codec type run\n");
break;
}
return 0;
}
static int rb_thread_process_evt(RB_CTRL_CMD_T evt) {
info("Decode event:%d", evt);
switch (evt) {
case RB_CTRL_CMD_CODEC_INIT:
rb_decode_halt_flag = 0;
rb_play_init();
/* get id3 */
/* init ci info */
ci->filesize = filesize(song_fd);
ci->id3 = current_id3;
ci->curpos = 0;
dsp_configure(ci->dsp, DSP_RESET, 0);
dsp_configure(ci->dsp, DSP_FLUSH, 0);
rb_codec_init_desc();
break;
case RB_CTRL_CMD_CODEC_RUN:
rbplay_loop_on = 1;
info("Play start");
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, rb_player_get_work_freq());
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
rb_codec_loop_on();
#if defined(__BTIF_AUTOPOWEROFF__)
app_start_10_second_timer(APP_POWEROFF_TIMER_ID);
#endif
song_fd = 0;
rb_decode_halt_flag = 1;
if (thread_tid_waiter) {
rb_player_sync_close_done();
} else {
rb_thread_send_status_change();
rb_thread_send_switch(true);
}
#ifdef __TWS__
// should update codec info after play one music
codec_info.update_codec_info = 1;
#endif
rbplay_loop_on = 0;
info("Play end");
break;
default:
error("Unkown rb cmd %d\n", evt);
break;
}
return 0;
}
int rb_decode_mailbox_put(RBTHREAD_MSG_BLOCK *msg_src) {
osStatus status;
RBTHREAD_MSG_BLOCK *msg_p = NULL;
msg_p = (RBTHREAD_MSG_BLOCK *)osMailAlloc(rb_decode_mailbox, 0);
if (!msg_p) {
TRACE(3, "%s fail, evt:%d,arg=%d \n", __func__, msg_src->evt, msg_src->arg);
return -1;
}
msg_p->evt = msg_src->evt;
msg_p->arg = msg_src->arg;
status = osMailPut(rb_decode_mailbox, msg_p);
return (int)status;
}
int rb_decode_mailbox_free(RBTHREAD_MSG_BLOCK *msg_p) {
osStatus status;
status = osMailFree(rb_decode_mailbox, msg_p);
return (int)status;
}
int rb_decode_mailbox_get(RBTHREAD_MSG_BLOCK **msg_p) {
osEvent evt;
evt = osMailGet(rb_decode_mailbox, osWaitForever);
if (evt.status == osEventMail) {
*msg_p = (RBTHREAD_MSG_BLOCK *)evt.value.p;
return 0;
}
return -1;
}
static void rb_decode_thread(void const *argument) {
RB_CTRL_CMD_T action;
RBTHREAD_MSG_BLOCK *msg_p;
while (1) {
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_32K);
// evt = osSignalWait(0, osWaitForever);
if (0 == rb_decode_mailbox_get(&msg_p)) {
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_104M);
action = (RB_CTRL_CMD_T)msg_p->evt;
rb_caller_tid = (osThreadId)msg_p->arg;
TRACE(3, "[%s] action:%d ,tid,0x%x", __func__, action, rb_caller_tid);
rb_thread_process_evt(action);
rb_decode_mailbox_free(msg_p);
if (rb_caller_tid)
osSignalSet(rb_decode_tid, 0x1203);
rb_caller_tid = NULL;
}
}
}
int app_rbplay_open(void) {
if (rb_decode_tid != NULL) {
warn("Decode thread reopen");
return -1;
}
rb_decode_mailbox = osMailCreate(osMailQ(rb_decode_mailbox), NULL);
if (rb_decode_mailbox == NULL) {
error("Failed to Create rb_decode_mailbox");
return -1;
}
rb_decode_tid = osThreadCreate(osThread(rb_decode_thread), NULL);
if (rb_decode_tid == NULL) {
error("Failed to Create rb_thread \n");
return -1;
}
return 0;
}
int rb_codec_running(void) { return ((rb_decode_halt_flag == 0) ? 1 : 0); }
void rb_codec_set_halt(int halt) { rb_decode_halt_flag = halt; }
void rb_thread_set_decode_vars(int fd, int type, void *id3) {
song_fd = fd;
song_format = type;
current_id3 = (struct mp3entry *)id3;
}
void rb_player_sync_set_wait_thread(osThreadId tid) {
if (rbplay_loop_on)
thread_tid_waiter = tid;
else
thread_tid_waiter = NULL;
}
void rb_player_sync_wait_close(void) {
while (NULL != thread_tid_waiter) {
osThreadYield();
}
}
enum APP_SYSFREQ_FREQ_T rb_player_get_work_freq(void) {
enum APP_SYSFREQ_FREQ_T freq;
hal_sysfreq_print();
info("bitrate:%d freq:%d\n", ci->id3->bitrate, ci->id3->frequency);
#ifndef __TWS__
enum AUD_SAMPRATE_T sample_rate = AUD_SAMPRATE_44100;
sample_rate = (enum AUD_SAMPRATE_T)ci->id3->frequency;
if (sample_rate > AUD_SAMPRATE_48000)
freq = APP_SYSFREQ_208M;
else if (sample_rate > AUD_SAMPRATE_44100)
freq = APP_SYSFREQ_104M;
else
freq = APP_SYSFREQ_52M;
if (ci->id3->bitrate > 192)
freq = APP_SYSFREQ_208M;
else if (ci->id3->bitrate > 128)
freq = APP_SYSFREQ_104M;
else
freq = APP_SYSFREQ_52M;
switch (song_format) {
case AFMT_APE:
freq = APP_SYSFREQ_208M;
break;
case AFMT_FLAC:
freq = APP_SYSFREQ_208M;
break;
case AFMT_PCM_WAV:
freq = APP_SYSFREQ_208M;
break;
default:
break;
}
#else
freq = APP_SYSFREQ_208M;
#endif
info("Decode thread run at: %d", freq);
return freq;
}