示例#1
0
static int playlist_view_catalog(void * param)
{
    /* kludge untill catalog_view_playlists() returns something useful */
    int old_playstatus = audio_status();
    (void)param;
    push_current_activity(ACTIVITY_PLAYLISTBROWSER);
    catalog_view_playlists();
    pop_current_activity();
    if (!old_playstatus && audio_status())
        return GO_TO_WPS;
    return GO_TO_PREVIOUS;
}
示例#2
0
static bool view_playlist(void)
{
    bool was_playing = audio_status() & AUDIO_STATUS_PLAY;
    bool result;

    result = playlist_viewer_ex(selected_file);

    if (!was_playing && (audio_status() & AUDIO_STATUS_PLAY) &&
        onplay_result == ONPLAY_OK)
        /* playlist was started from viewer */
        onplay_result = ONPLAY_START_PLAY;

    return result;
}
示例#3
0
static int treeplaylist_callback(int action,
                                 const struct menu_item_ex *this_item)
{
    switch (action)
    {
        case ACTION_REQUEST_MENUITEM:
            if (this_item == &tree_playlist_menu)
            {
                if (((selected_file_attr & FILE_ATTR_MASK) ==
                        FILE_ATTR_AUDIO) ||
                    ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)||
                     (selected_file_attr & ATTR_DIRECTORY))
                {
                    return action;
                }
            }
            else if (this_item == &view_playlist_item)
            {
                if ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U &&
                        context == CONTEXT_TREE)
                {
                    return action;
                }
            }
            else if (this_item == &i_shuf_pl_item)
            {
                if ((audio_status() & AUDIO_STATUS_PLAY) ||
                    (selected_file_attr & ATTR_DIRECTORY) ||
                    ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U))
                {
                    return action;
                }
            }
            else if (this_item == &i_last_shuf_pl_item ||
                     this_item == &q_last_shuf_pl_item)
            {
                if ((playlist_amount() > 0) &&
                    (audio_status() & AUDIO_STATUS_PLAY) &&
                    ((selected_file_attr & ATTR_DIRECTORY) ||
                    ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)))
                {
                    return action;
                }
            }
            return ACTION_EXIT_MENUITEM;
            break;
    }
    return action;
}
示例#4
0
static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
{
    size_t copy_n = reqsize;
    ssize_t ret;
    void *ptr;

    if (!(audio_status() & AUDIO_STATUS_PLAY))
    {
        *realsize = 0;
        return NULL;
    }

    ret = bufgetdata(get_audio_hid(), reqsize, &ptr);
    if (ret >= 0)
        copy_n = MIN((size_t)ret, reqsize);

    if (copy_n == 0)
    {
        *realsize = 0;
        return NULL;
    }

    *realsize = copy_n;

    return ptr;
} /* codec_request_buffer_callback */
示例#5
0
static bool codec_request_next_track_callback(void)
{
    int prev_codectype;

    if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY))
        return false;

    prev_codectype = get_codec_base_type(thistrack_id3->codectype);
    if (!codec_load_next_track())
        return false;

    /* Seek to the beginning of the new track because if the struct
       mp3entry was buffered, "elapsed" might not be zero (if the track has
       been played already but not unbuffered) */
    codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
    /* Check if the next codec is the same file. */
    if (prev_codectype == get_codec_base_type(thistrack_id3->codectype))
    {
        logf("New track loaded");
        codec_discard_codec_callback();
        return true;
    }
    else
    {
        logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype);
        return false;
    }
}
示例#6
0
static int bookmark_menu_callback(int action,
                                  const struct menu_item_ex *this_item)
{
    switch (action)
    {
        case ACTION_REQUEST_MENUITEM:
            if (this_item == &bookmark_load_menu_item)
            {
                if (!bookmark_exists())
                    return ACTION_EXIT_MENUITEM;
            }
            /* hide the bookmark menu if there is no playback */
            else if ((audio_status() & AUDIO_STATUS_PLAY) == 0)
                return ACTION_EXIT_MENUITEM;
            break;
#ifdef HAVE_LCD_CHARCELLS
        case ACTION_ENTER_MENUITEM:
            status_set_param(true);
            break;
#endif
        case ACTION_EXIT_MENUITEM:
#ifdef HAVE_LCD_CHARCELLS
            status_set_param(false);
#endif
            settings_save();
            break;
    }
    return action;
}
示例#7
0
文件: root_menu.c 项目: ntj/rockbox
static int wpsscrn(void* param)
{
    int ret_val = GO_TO_PREVIOUS;
    (void)param;
    if (audio_status())
    {
        talk_shutup();
        ret_val = gui_wps_show();
    }
    else if ( global_status.resume_index != -1 )
    {
        DEBUGF("Resume index %X offset %lX\n",
               global_status.resume_index,
               (unsigned long)global_status.resume_offset);
        if (playlist_resume() != -1)
        {
            playlist_start(global_status.resume_index,
                global_status.resume_offset);
            ret_val = gui_wps_show();
        }
    }
    else
    {
        splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
    }
    return ret_val;
}
示例#8
0
文件: root_menu.c 项目: ntj/rockbox
static char *get_wps_item_name(int selected_item, void * data, char *buffer)
{
    (void)selected_item; (void)data; (void)buffer;
    if (audio_status())
        return ID2P(LANG_NOW_PLAYING);
    return ID2P(LANG_RESUME_PLAYBACK);
}
示例#9
0
文件: root_menu.c 项目: ntj/rockbox
static int load_plugin_screen(char *plug_path)
{
    int ret_val;
    int old_previous = last_screen;    
    last_screen = next_screen;
    global_status.last_screen = (char)next_screen;
    status_save();
    
    switch (plugin_load(plug_path, NULL))
    {
    case PLUGIN_GOTO_WPS:
        ret_val = GO_TO_WPS;
        break;
    case PLUGIN_OK:
        ret_val = audio_status() ? GO_TO_PREVIOUS : GO_TO_ROOT;
        break;
    default:
        ret_val = GO_TO_PREVIOUS;
        break;
    }

    if (ret_val == GO_TO_PREVIOUS)
        last_screen = (old_previous == next_screen) ? GO_TO_ROOT : old_previous;
    return ret_val;
}
示例#10
0
static int ab_audio_event_handler(unsigned short event, unsigned long data)
{
    int rc = AUDIO_EVENT_RC_IGNORED;
    if ( ab_repeat_mode_enabled() )
    {
        switch(event)
        {
            case AUDIO_EVENT_POS_REPORT:
            {
                if ( ! (audio_status() & AUDIO_STATUS_PAUSE) &&
                        ab_reached_B_marker(data) )
                {
                    ab_jump_to_A_marker();
                    rc = AUDIO_EVENT_RC_HANDLED;
                }
                break;
            }
            case AUDIO_EVENT_END_OF_TRACK:
            {
                if ( ab_A_marker_set() && ! ab_B_marker_set() )
                {
                    ab_jump_to_A_marker();
                    rc = AUDIO_EVENT_RC_HANDLED;
                }
                break;
            }
        }
    }
    return rc;
}
示例#11
0
static int playback_callback(int action,const struct menu_item_ex *this_item)
{
    static bool old_shuffle = false;
    switch (action)
    {
        case ACTION_ENTER_MENUITEM:
            if (this_item == &shuffle_item)
                old_shuffle = global_settings.playlist_shuffle;
            break;
        case ACTION_EXIT_MENUITEM: /* on exit */
            if ((this_item == &shuffle_item) &&
                (old_shuffle != global_settings.playlist_shuffle)
                && (audio_status() & AUDIO_STATUS_PLAY))
            {
#if CONFIG_CODEC == SWCODEC
                dsp_set_replaygain();
#endif
                if (global_settings.playlist_shuffle)
                {
                    playlist_randomise(NULL, current_tick, true);
                }
                else
                {
                    playlist_sort(NULL, true);
                }
            }
            break;
    }
    return action;
}
示例#12
0
static int wpsscrn(void* param)
{
    int ret_val = GO_TO_PREVIOUS;
    (void)param;
    push_current_activity(ACTIVITY_WPS);
    if (audio_status())
    {
        talk_shutup();
        ret_val = gui_wps_show();
    }
    else if ( global_status.resume_index != -1 )
    {
        DEBUGF("Resume index %X crc32 %lX offset %lX\n",
               global_status.resume_index,
               (unsigned long)global_status.resume_crc32,
               (unsigned long)global_status.resume_offset);
        if (playlist_resume() != -1)
        {
            playlist_resume_track(global_status.resume_index,
                global_status.resume_crc32,
                global_status.resume_elapsed,
                global_status.resume_offset);
            ret_val = gui_wps_show();
        }
    }
    else
    {
        splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
    }
    pop_current_activity();
    return ret_val;
}
示例#13
0
void settings_apply_play_freq(int value, bool playback)
{
    static const unsigned long play_sampr[] = { SAMPR_44, SAMPR_48 };
    static int prev_setting = 0;

    if ((unsigned)value >= ARRAYLEN(play_sampr))
        value = 0;

    bool changed = value != prev_setting;
    prev_setting = value;

    unsigned long elapsed = 0;
    unsigned long offset = 0;
    bool playing = changed && !playback &&
                   audio_status() == AUDIO_STATUS_PLAY;

    if (playing)
    {
        struct mp3entry *id3 = audio_current_track();
        elapsed = id3->elapsed;
        offset = id3->offset;
    }

    if (changed && !playback)
        audio_hard_stop();

    /* Other sub-areas of playback pick it up from the mixer */
    mixer_set_frequency(play_sampr[value]);

    if (playing)
        audio_play(elapsed, offset);
}
示例#14
0
文件: onplay.c 项目: IlVerz/rockbox
static int cat_playlist_callback(int action,
                                 const struct menu_item_ex *this_item)
{
    (void)this_item;
    if (!selected_file ||
        (((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) &&
         ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) &&
         ((selected_file_attr & ATTR_DIRECTORY) == 0)))
    {
        return ACTION_EXIT_MENUITEM;
    }
#ifdef HAVE_TAGCACHE
    if (context == CONTEXT_ID3DB &&
        ((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO))
    {
        return ACTION_EXIT_MENUITEM;
    }
#endif

    switch (action)
    {
        case ACTION_REQUEST_MENUITEM:
            if ((audio_status() & AUDIO_STATUS_PLAY) || context != CONTEXT_WPS)
            {
                return action;
            }
            else
                return ACTION_EXIT_MENUITEM;
            break;
    }
    return action;
}
示例#15
0
/* Start playback of a playlist, checking for bookmark autoload, modified
 * playlists, etc., as required. Returns false if playback wasn't started,
 * or started via bookmark autoload, true otherwise.
 *
 * Pointers to both the full pathname and the separated parts needed to
 * avoid allocating yet another path buffer on the stack (and save some 
 * code; the caller typically needs to create the full pathname anyway)...
 */
bool ft_play_playlist(char* pathname, char* dirname, char* filename)
{
    if (global_settings.party_mode && audio_status()) 
    {
        splash(HZ, ID2P(LANG_PARTY_MODE));
        return false;
    }

    if (bookmark_autoload(pathname))
    {
        return false;
    }

    splash(0, ID2P(LANG_WAIT));

    /* about to create a new current playlist...
       allow user to cancel the operation */
    if (!warn_on_pl_erase())
        return false;

    if (playlist_create(dirname, filename) != -1)
    {
        if (global_settings.playlist_shuffle)
        {
            playlist_shuffle(current_tick, -1);
        }
        
        playlist_start(0, 0);
        return true;
    }
    
    return false;
}
示例#16
0
bool quick_screen_quick(int button_enter)
{
    struct gui_quickscreen qs;
    bool oldshuffle = global_settings.playlist_shuffle;
    int oldrepeat = global_settings.repeat_mode;
    bool usb = false;

    if (global_settings.shortcuts_replaces_qs)
        return do_shortcut_menu(NULL);

    qs.items[QUICKSCREEN_TOP] =
            get_setting(global_settings.qs_items[QUICKSCREEN_TOP], NULL);
    qs.items[QUICKSCREEN_LEFT] =
            get_setting(global_settings.qs_items[QUICKSCREEN_LEFT],
                        find_setting(&global_settings.playlist_shuffle, NULL));
    qs.items[QUICKSCREEN_RIGHT] =
            get_setting(global_settings.qs_items[QUICKSCREEN_RIGHT],
                        find_setting(&global_settings.repeat_mode, NULL));
    qs.items[QUICKSCREEN_BOTTOM] =
            get_setting(global_settings.qs_items[QUICKSCREEN_BOTTOM], NULL);

    qs.callback = NULL;
    if (gui_syncquickscreen_run(&qs, button_enter, &usb))
    {
        settings_save();
        settings_apply(false);
        /* make sure repeat/shuffle/any other nasty ones get updated */
        if ( oldrepeat != global_settings.repeat_mode &&
             (audio_status() & AUDIO_STATUS_PLAY) )
        {
            audio_flush_and_reload_tracks();
        }
        if (oldshuffle != global_settings.playlist_shuffle
            && audio_status() & AUDIO_STATUS_PLAY)
        {
            replaygain_update();
            if (global_settings.playlist_shuffle)
                playlist_randomise(NULL, current_tick, true);
            else
                playlist_sort(NULL, true);
        }
    }
    return usb;
}
示例#17
0
bool quick_screen_quick(int button_enter)
{
    struct gui_quickscreen qs;
    bool oldshuffle = global_settings.playlist_shuffle;
    int oldrepeat = global_settings.repeat_mode;

    qs.items[QUICKSCREEN_TOP] =
            get_setting(global_settings.qs_items[QUICKSCREEN_TOP],
                        find_setting(&global_settings.party_mode, NULL));
    qs.items[QUICKSCREEN_LEFT] =
            get_setting(global_settings.qs_items[QUICKSCREEN_LEFT],
                        find_setting(&global_settings.playlist_shuffle, NULL));
    qs.items[QUICKSCREEN_RIGHT] =
            get_setting(global_settings.qs_items[QUICKSCREEN_RIGHT],
                        find_setting(&global_settings.repeat_mode, NULL));
    qs.items[QUICKSCREEN_BOTTOM] =
            get_setting(global_settings.qs_items[QUICKSCREEN_BOTTOM],
                        find_setting(&global_settings.dirfilter, NULL));

    qs.callback = NULL;
    if (gui_syncquickscreen_run(&qs, button_enter))
    {
        settings_save();
        settings_apply(false);
        /* make sure repeat/shuffle/any other nasty ones get updated */
        if ( oldrepeat != global_settings.repeat_mode &&
             (audio_status() & AUDIO_STATUS_PLAY) )
        {
            audio_flush_and_reload_tracks();
        }
        if (oldshuffle != global_settings.playlist_shuffle
            && audio_status() & AUDIO_STATUS_PLAY)
        {
#if CONFIG_CODEC == SWCODEC
            dsp_set_replaygain();
#endif
            if (global_settings.playlist_shuffle)
                playlist_randomise(NULL, current_tick, true);
            else
                playlist_sort(NULL, true);
        }
    }
    return(0);
}
示例#18
0
static int playlist_insert_shuffled(void)
{
    if ((audio_status() & AUDIO_STATUS_PLAY) ||
        (selected_file_attr & ATTR_DIRECTORY) ||
        ((selected_file_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U))
    {
        playlist_insert_func((intptr_t*)PLAYLIST_INSERT_SHUFFLED);
        return ONPLAY_START_PLAY;
    }
    
    return ONPLAY_RELOAD_DIR;
}
示例#19
0
void ab_jump_to_A_marker(void)
{
#if (CONFIG_CODEC != SWCODEC)
    bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0;
    if ( ! paused )
        audio_pause();
#endif
    audio_ff_rewind(ab_A_marker);
#if (CONFIG_CODEC != SWCODEC)
    if ( ! paused )
        audio_resume();
#endif
}
示例#20
0
static int playback_callback(int action,const struct menu_item_ex *this_item)
{
    static bool old_shuffle = false;
    static int old_repeat = 0;
    switch (action)
    {
        case ACTION_ENTER_MENUITEM:
            if (this_item == &shuffle_item)
            {
                old_shuffle = global_settings.playlist_shuffle;
            }
            else if (this_item == &repeat_mode)
            {
                old_repeat = global_settings.repeat_mode;
            }
            break;

        case ACTION_EXIT_MENUITEM: /* on exit */
            if (!(audio_status() & AUDIO_STATUS_PLAY))
                break;

            if (this_item == &shuffle_item)
            {
                if (old_shuffle == global_settings.playlist_shuffle)
                    break;

#if CONFIG_CODEC == SWCODEC
                dsp_set_replaygain();
#endif
                if (global_settings.playlist_shuffle)
                {
                    playlist_randomise(NULL, current_tick, true);
                }
                else
                {
                    playlist_sort(NULL, true);
                }
            }
            else if (this_item == &repeat_mode)
            {
                if (old_repeat == global_settings.repeat_mode)
                    break;

                audio_flush_and_reload_tracks();
            }

            break;
    }
    return action;
}
示例#21
0
static int treeplaylist_wplayback_callback(int action,
                                        const struct menu_item_ex* this_item)
{
    (void)this_item;
    switch (action)
    {
        case ACTION_REQUEST_MENUITEM:
            if (audio_status() & AUDIO_STATUS_PLAY)
                return action;
            else
                return ACTION_EXIT_MENUITEM;
            break;
    }
    return action;
}
示例#22
0
static bool playback_settings_menu(void)
{
    int m;
    bool result;

    static const struct menu_item items[] = {
        { ID2P(LANG_SHUFFLE), shuffle },
        { ID2P(LANG_REPEAT), repeat_mode },
        { ID2P(LANG_PLAY_SELECTED), play_selected },
        { ID2P(LANG_RESUME), resume },
        { ID2P(LANG_WIND_MENU), ff_rewind_settings_menu },
        { ID2P(LANG_MP3BUFFER_MARGIN), buffer_margin },
        { ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
#if CONFIG_CODEC == SWCODEC
        { ID2P(LANG_CROSSFADE), crossfade },
        { ID2P(LANG_CROSSFADE_DURATION), crossfade_duration },
        { ID2P(LANG_REPLAYGAIN), replaygain_settings_menu },
        { ID2P(LANG_BEEP), beep },
#endif
#ifdef HAVE_SPDIF_POWER
        { ID2P(LANG_SPDIF_ENABLE), spdif },
#endif
        { ID2P(LANG_ID3_ORDER), id3_order },
        { ID2P(LANG_NEXT_FOLDER), next_folder },
        { ID2P(LANG_RUNTIMEDB_ACTIVE), runtimedb },
    };

    bool old_shuffle = global_settings.playlist_shuffle;

    m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
                 NULL, NULL, NULL);
    result = menu_run(m);
    menu_exit(m);

    if ((old_shuffle != global_settings.playlist_shuffle) 
        && (audio_status() & AUDIO_STATUS_PLAY))
    {
        if (global_settings.playlist_shuffle)
        {
            playlist_randomise(NULL, current_tick, true);
        }
        else
        {
            playlist_sort(NULL, true);
        }
    }
    return result;
}
示例#23
0
/* ----------------------------------------------------------------------- */
bool bookmark_is_bookmarkable_state(void)
{
    int resume_index = 0;

    if (!(audio_status() && audio_current_track()) ||
        /* no track playing */
       (playlist_get_resume_info(&resume_index) == -1) ||
        /* invalid queue info */
       (playlist_modified(NULL)))
        /* can't bookmark while in the queue */
    {
        return false;
    }

    return true;
}
示例#24
0
static int ft_play_dirname(char* name)
{
#if CONFIG_CODEC != SWCODEC
    if (audio_status() & AUDIO_STATUS_PLAY)
        return 0;
#endif

    if(talk_file(tc.currdir, name, dir_thumbnail_name, NULL,
                 NULL, false))
    {
        if(global_settings.talk_filetype)
            talk_id(VOICE_DIR, true);
        return 1;
    }
    else
        return -1;
}
/*
 * Estimate how much current we are drawing just to run.
 */
static int runcurrent(void)
{
    int current = CURRENT_NORMAL;

#ifndef BOOTLOADER
    if (usb_inserted()
#ifdef HAVE_USB_POWER
#if (CURRENT_USB < CURRENT_NORMAL)
            || usb_powered()
#else
            && !usb_powered()
#endif
#endif
       ) {
        current = CURRENT_USB;
    }

#if defined(HAVE_BACKLIGHT)
    if (backlight_get_current_timeout() == 0) /* LED always on */
        current += CURRENT_BACKLIGHT;
#endif

#if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
    if (audio_status() & AUDIO_STATUS_RECORD)
        current += CURRENT_RECORD;
#endif

#ifdef HAVE_SPDIF_POWER
    if (spdif_powered())
        current += CURRENT_SPDIF_OUT;
#endif

#ifdef HAVE_REMOTE_LCD
    if (remote_detect())
        current += CURRENT_REMOTE;
#endif

#if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
    if (ide_powered())
        current += CURRENT_ATA;
#endif

#endif /* BOOTLOADER */

    return current;
}
示例#26
0
static void ft_play_filename(char *dir, char *file)
{
#if CONFIG_CODEC != SWCODEC
    if (audio_status() & AUDIO_STATUS_PLAY)
        return;
#endif

    if (strlen(file) >= strlen(file_thumbnail_ext)
        && strcasecmp(&file[strlen(file) - strlen(file_thumbnail_ext)],
                      file_thumbnail_ext))
        /* file has no .talk extension */
        talk_file(dir, NULL, file, file_thumbnail_ext,
                  NULL, false);
    else
        /* it already is a .talk file, play this directly, but prefix it. */
        talk_file(dir, NULL, file, NULL,
                  TALK_IDARRAY(LANG_VOICE_DIR_HOVER), false);
}
示例#27
0
static void codec_seek_complete_callback(void)
{
    logf("seek_complete");
    /* If seeking-while-playing, pcm_is_paused() is true.
     * If seeking-while-paused, audio_status PAUSE is true.
     * A seamless seek skips this section. */
    bool audio_paused = audio_status() & AUDIO_STATUS_PAUSE;
    if (pcm_is_paused() || audio_paused)
    {
        /* Clear the buffer */
        pcmbuf_play_stop();
        dsp_configure(ci.dsp, DSP_FLUSH, 0);

        /* If seeking-while-playing, resume pcm playback */
        if (!audio_paused)
            pcmbuf_pause(false);
    }
    ci.seek_time = 0;
}
示例#28
0
文件: cuesheet.c 项目: Megaco/rockbox
/* takes care of seeking to a track in a playlist
 * returns false if audio  isn't playing */
static bool seek(unsigned long pos)
{
    if (!(audio_status() & AUDIO_STATUS_PLAY))
    {
        return false;
    }
    else
    {
#if (CONFIG_CODEC == SWCODEC)
        audio_pre_ff_rewind();
        audio_ff_rewind(pos);
#else
        audio_pause();
        audio_ff_rewind(pos);
        audio_resume();
#endif
        return true;
    }
}
示例#29
0
/* copy up-to size bytes into ptr and return the actual size copied */
static size_t codec_filebuf_callback(void *ptr, size_t size)
{
    ssize_t copy_n;

    if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY))
        return 0;

    copy_n = bufread(get_audio_hid(), size, ptr);

    /* Nothing requested OR nothing left */
    if (copy_n == 0)
        return 0;

    /* Update read and other position pointers */
    codec_advance_buffer_counters(copy_n);

    /* Return the actual amount of data copied to the buffer */
    return copy_n;
} /* codec_filebuf_callback */
示例#30
0
int current_playmode(void)
{
    int audio_stat = audio_status();

    /* ff_mode can be either STATUS_FASTFORWARD or STATUS_FASTBACKWARD
       and that supercedes the other modes */
    if(ff_mode)
        return ff_mode;
    
    if(audio_stat & AUDIO_STATUS_PLAY)
    {
        if(audio_stat & AUDIO_STATUS_PAUSE)
            return STATUS_PAUSE;
        else
            return STATUS_PLAY;
    }

#ifdef HAVE_RECORDING
    if(audio_stat & AUDIO_STATUS_RECORD)
    {
        if(audio_stat & AUDIO_STATUS_PAUSE)
            return STATUS_RECORD_PAUSE;
        else
            return STATUS_RECORD;
    }
#endif

#if CONFIG_TUNER
    audio_stat = get_radio_status();
    if(audio_stat & FMRADIO_PLAYING)
       return STATUS_RADIO;

    if(audio_stat & FMRADIO_PAUSED)
       return STATUS_RADIO_PAUSE;
#endif
    
    return STATUS_STOP;
}