0%

movian-backend

Movian 中使用了大量的 backend 服务,本文来分析 backend 实现流程

Register

Search 为例

static inr
search_canhandle(const char *url)
{
  return !strncmp(url, "search:", strlen("search:"));
}

static int
search_open(prop_t *page, const char *url0, int sync)
{

}

static backend_t be_search = {
  .be_canhandle = search_canhandle,
  .be_open = search_open,
};

BE_REGISTER(search);

BE_REGISTER 宏定义

#define BE_REGISTER(name)
  INITIALIZER(backend_init_ ## name) {                                 \
    backend_register(&be_ ## name);                                    \
  }

INITIALIZER 宏定义在 src/compiler.h

#elif defined(__GNUC__)

#define INITIALIZER(f) \
   static void f(void) __attribute__((constructor)); \
   static void f(void)

#endif

其中 __attribute__ constructor 被修饰的函数作为构造函数执行

其中 backend_registerbe_search 插入到链表 backends

void
backend_register(backend_t *be)
{
  LIST_INSERT_HEAD(&backends, be, be_global_link);
}

因此在执行到 main 之前已经调用 backend_register,完成 backend 注册

Init

src/arch/linux/linux_main.c

main ->
main_init ->
backend_init

void
backend_init(void)
{
  backend_t *be;
  hts_lwmutex_init(&dyanamic_backends_mutex);
  hts_mutex_init(&imageloader_mutex);
  hts_cond_init(&imageloader_cond, &imageloader_mutex);

  TAILQ_INIT(&cached_images);

  LIST_FOREACH(be, &backends, be_global_link)
    if(be->be_init != NULL)
      be->be_init();
}

play video

UI ->
glw_create ->
class->gc_ctor ->
glw_video_ctor ->
video_playback_create ->
video_player_idle ->
play_video ->
backend_play_video

play audio

video 流程不一样

be_playqueue 注册

static backend_t be_playqueue = {
  .be_init = playqueue_init,
  .be_canhandle = be_playqueue_canhandle,
  .be_open = be_playqueue_open,
};

BE_REGISTER(playqueue);

playqueue_init ->
player_thread ->
backend_play_audio

page open

backend_page_open 注册为 backend,除此之外只给 upgrade 调用

static int
upgrade_open_url(prop_t *page, const char *url, int sync)
{
  if(!strcmp(url, "showtime:upgrade")) {
    usage_page_open(sync, "Upgrade");
    backend_page_open(page, "page:upgrade", sync);
    upgrade_refresh();
    prop_set(page, "directClose", PROP_SET_INT, 1);
  } else {
    nav_open_error(page, "Invalid URI");
  }
  return 0;
}
static backend_t be_page = {
  .be_canhandle = be_page_canhandle,
  .be_open = backend_page_open,
};

BE_REGISTER(page);

backend probe

main_init ->
service_int ->
service_probe_loop ->
backend_probe

backend_probe_result_t
backend_probe(const char *url, char *errbuf, size_t errlen, int timeout_ms)
{
  if(timeout_ms <= 0)
    timeout_ms = 5000;

  // 匹配 URL
  backend_t *be = backend_canhandle(url);
  if(be == NULL) {
    snprintf(errbuf, errlen, "No handler for URL");
    return BACKEND_PROBE_NO_HANDLER;
  }

  if(be->be_probe == NULL)
    return BACKEND_PROBE_OK;

  // Example: .be_probe = fa_check_url
  return be->be_probe(url, errbuf, errlen, timeout_ms);
}

backend open

search_open ->
backend_open -> backend_search

可以匹配到 .be_search = plugin_search .be_search = ecmascript_search

通用 src/arch/linux/linux_main.c

main ->
linux_global_eventsink ->
switch_ui

ui_current 设置为 ui_glw,然后

main_loop ->
ui_glw->start ->
glw_x11_start ->
nav_spawn ->
nav_create ->
nav_open0 ->
nav_open_backend ->
nav_open_thread ->
back_open