示例#1
0
/* Handle Q_CODEC_LOAD */
static void load_codec(const struct codec_load_info *ev_data)
{
    int status = CODEC_ERROR;
    /* Save a local copy so we can let the audio thread go ASAP */
    struct codec_load_info data = *ev_data;
    bool const encoder = type_is_encoder(data.afmt);

    if (codec_type != AFMT_UNKNOWN)
    {
        /* Must have unloaded it first */
        logf("a codec is already loaded");
        if (data.hid >= 0)
            bufclose(data.hid);
        return;
    }

    trigger_cpu_boost();

    if (!encoder)
    {
        /* Do this now because codec may set some things up at load time */
        dsp_configure(ci.dsp, DSP_RESET, 0);
    }

    if (data.hid >= 0)
    {
        /* First try buffer load */
        status = codec_load_buf(data.hid, &ci);
        bufclose(data.hid);
    }

    if (status < 0)
    {
        /* Either not a valid handle or the buffer method failed */
        const char *codec_fn = get_codec_filename(data.afmt);
        if (codec_fn)
        {
#ifdef HAVE_IO_PRIORITY
            buf_back_off_storage(true);
#endif
            status = codec_load_file(codec_fn, &ci);
#ifdef HAVE_IO_PRIORITY
            buf_back_off_storage(false);
#endif
        }
    }

    if (status >= 0)
    {
        codec_type = data.afmt;
        codec_queue_ack(Q_CODEC_LOAD);
        return;
    }

    /* Failed - get rid of it */
    unload_codec();
}
示例#2
0
bool create_playlist(void)
{
    char filename[MAX_PATH];

    snprintf(filename, sizeof filename, "%s.m3u8",
             tc.currdir[1] ? tc.currdir : "/root");
    splashf(0, "%s %s", str(LANG_CREATING), filename);

    trigger_cpu_boost();
    catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, filename);
    cancel_cpu_boost();

    return true;
}
示例#3
0
static bool codec_load_next_track(void)
{
    intptr_t result = Q_CODEC_REQUEST_FAILED;

    audio_set_prev_elapsed(thistrack_id3->elapsed);

#ifdef AB_REPEAT_ENABLE
    ab_end_of_track_report();
#endif

    logf("Request new track");

    if (ci.new_track == 0)
    {
        ci.new_track++;
        automatic_skip = true;
    }

    if (!ci.stop_codec)
    {
        trigger_cpu_boost();
        LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
        result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
    }

    switch (result)
    {
        case Q_CODEC_REQUEST_COMPLETE:
            LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
            pcmbuf_start_track_change(automatic_skip);
            return true;

        case Q_CODEC_REQUEST_FAILED:
            LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
            ci.new_track = 0;
            ci.stop_codec = true;
            codec_requested_stop = true;
            return false;

        default:
            LOGFQUEUE("codec |< default");
            ci.stop_codec = true;
            codec_requested_stop = true;
            return false;
    }
}
示例#4
0
/* Handle Q_CODEC_RUN */
static void run_codec(void)
{
    bool const encoder = type_is_encoder(codec_type);
    int status;

    if (codec_type == AFMT_UNKNOWN)
    {
        logf("no codec to run");
        return;
    }

    codec_queue_ack(Q_CODEC_RUN);

    trigger_cpu_boost();

    if (!encoder)
    {
        /* This will be either the initial buffered offset or where it left off
           if it remained buffered and we're skipping back to it and it is best
           to have ci.curpos in sync with the handle's read position - it's the
           codec's responsibility to ensure it has the correct positions -
           playback is sorta dumb and only has a vague idea about what to
           buffer based upon what metadata has to say */
        ci.curpos = bufftell(ci.audio_hid);

        /* Pin the codec's audio data in place */
        buf_pin_handle(ci.audio_hid, true);
    }

    status = codec_run_proc();

    if (!encoder)
    {
        /* Codec is done with it - let it move */
        buf_pin_handle(ci.audio_hid, false);

        /* Notify audio that we're done for better or worse - advise of the
           status */
        LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
        audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
    }
}
示例#5
0
bool create_playlist(void)
{
    char filename[MAX_PATH];

    if (tc.currdir[1])
        snprintf(filename, sizeof filename, "%s.m3u8", tc.currdir);
    else
        snprintf(filename, sizeof filename, "%s/all.m3u8",
                catalog_get_directory());
        
    
    if (kbd_input(filename, MAX_PATH))
        return false;
    splashf(0, "%s %s", str(LANG_CREATING), filename);

    trigger_cpu_boost();
    catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, filename);
    cancel_cpu_boost();

    return true;
}
/* Handler STREAM_PLAY */
static void stream_on_play(void)
{
    int status = stream_mgr.status;

    stream_mgr_lock();

    if (status == STREAM_STOPPED)
    {
        uint32_t start;

        /* We just say we're playing now */
        stream_mgr.status = STREAM_PLAYING;

        /* Reply with previous state */
        stream_mgr_reply_msg(status);

        trigger_cpu_boost();

        /* Seek to initial position and set clock to that time */

        /* Save the resume time */
        stream_remember_resume_time();

        /* Prepare seek to start point */
        start = stream_seek_intl(stream_mgr.resume_time, SEEK_SET,
                                 STREAM_STOPPED, NULL);

        /* Sync and start - force buffer fill */
        stream_start_playback(start, true);
    }
    else
    {
        /* Reply with previous state */
        stream_mgr_reply_msg(status);
    }

    stream_mgr_unlock();
}
/* Handle STREAM_RESUME */
static void stream_on_resume(void)
{
    int status = stream_mgr.status;

    stream_mgr_lock();

    /* Reply with previous state */
    stream_mgr_reply_msg(status);

    if (status == STREAM_PAUSED)
    {
        /* Boost the CPU */
        trigger_cpu_boost();

        /* Sync and start - no force buffering */
        stream_start_playback(str_parser.last_seek_time, false);

        /* Officially playing */
        stream_mgr.status = STREAM_PLAYING;
    }

    stream_mgr_unlock();
}
示例#8
0
/* inline since branch is chosen at compile time */
static inline void usb_slave_mode(bool on)
{
#ifdef USE_ROCKBOX_USB
    int rc;

    if (on)
    {
        trigger_cpu_boost();
#ifdef HAVE_PRIORITY_SCHEDULING
        thread_set_priority(THREAD_ID_CURRENT, PRIORITY_REALTIME);
#endif
        usb_attach();
    }
    else /* usb_state == USB_INSERTED (only!) */
    {
#ifndef USB_DETECT_BY_DRV
        usb_enable(false);
#endif
#ifdef HAVE_PRIORITY_SCHEDULING
        thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM);
#endif
        /* Entered exclusive mode */
        rc = disk_mount_all();
        if (rc <= 0) /* no partition */
            panicf("mount: %d",rc);

        cancel_cpu_boost();
    }
#else /* !USE_ROCKBOX_USB */
    if (on)
    {
        /* until we have native mass-storage mode, we want to reboot on
           usb host connect */
        try_reboot();
    }
#endif /* USE_ROCKBOX_USB */
}
示例#9
0
void radio_screen(void)
{
    bool done = false;
    int button;
    bool stereo = false, last_stereo = false;
    int update_type = 0;
    bool screen_freeze = false;
    bool keep_playing = false;
    bool talk = false;
#ifdef FM_RECORD_DBLPRE
    int lastbutton = BUTTON_NONE;
    unsigned long rec_lastclick = 0;
#endif
#if CONFIG_CODEC != SWCODEC
    int timeout = current_tick + HZ/10;
#if !defined(SIMULATOR)
    unsigned int last_seconds = 0;
    unsigned int seconds = 0;
    struct audio_recording_options rec_options;
#endif /* SIMULATOR */
#endif /* CONFIG_CODEC != SWCODEC */
#ifndef HAVE_NOISY_IDLE_MODE
    int button_timeout = current_tick + (2*HZ);
#endif

    /* change status to "in screen" */
    push_current_activity(ACTIVITY_FM);
    in_screen = true;

    if(radio_preset_count() <= 0)
    {
        radio_load_presets(global_settings.fmr_file);
    }
    skin_get_global_state()->id3 = NULL;
#ifdef HAVE_ALBUMART
    radioart_init(true);
#endif    

    if(radio_status == FMRADIO_OFF)
        audio_stop();

    fms_fix_displays(FMS_ENTER);

#ifndef SIMULATOR

#if CONFIG_CODEC != SWCODEC
    rec_create_directory();
    audio_init_recording();

    sound_settings_apply();
    /* Yes, we use the D/A for monitoring */
    peak_meter_playback(true);

    peak_meter_enable(true);

    rec_init_recording_options(&rec_options);
    rec_options.rec_source = AUDIO_SRC_LINEIN;
    rec_set_recording_options(&rec_options);

    audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
            sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);

#endif /* CONFIG_CODEC != SWCODEC */
#endif /* ndef SIMULATOR */
    /* turn on radio */
#if CONFIG_CODEC == SWCODEC
    /* This should be done before touching audio settings */
    while (!pcm_is_initialized())
       sleep(0);

    audio_set_input_source(AUDIO_SRC_FMRADIO,
                           (radio_status == FMRADIO_PAUSED) ?
                               SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
#else
    if (radio_status == FMRADIO_OFF)
        radio_start();
#endif

    if(radio_preset_count() < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
        presets_scan(NULL);

    preset_set_current(preset_find(curr_freq));
    if(radio_current_preset() != -1)
         radio_mode = RADIO_PRESET_MODE;

    /* Load/update the skin at last, when fully initialzed, so that it can
     * display the right content from the beginning */
    FOR_NB_SCREENS(i)
        skin_update(FM_SCREEN, i, SKIN_REFRESH_ALL);

#ifndef HAVE_NOISY_IDLE_MODE
    cpu_idle_mode(true);
#endif

    while(!done)
    {
        if(search_dir != 0)
        {
            curr_freq = step_freq(curr_freq, search_dir);
            update_type = SKIN_REFRESH_ALL;

            if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
            {
                preset_set_current(preset_find(curr_freq));
                remember_frequency();
                end_search();
                talk = true;
            }
            trigger_cpu_boost();
        }

        if (!update_type)
        {
            cancel_cpu_boost();
        }

        button = fms_do_button_loop(update_type>0);

#ifndef HAVE_NOISY_IDLE_MODE
        if (button != ACTION_NONE)
        {
            cpu_idle_mode(false);
            button_timeout = current_tick + (2*HZ);
        }
#endif
        switch(button)
        {
             case ACTION_FM_STOP:
#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
                if(audio_status() == AUDIO_STATUS_RECORD)
                {
                    audio_stop();
                }
                else
#endif
                {
                    done = true;
                    if(presets_have_changed())
                    {
                        if(yesno_pop(ID2P(LANG_SAVE_CHANGES)))
                        {
                            presets_save();
                        }
                    }
                }
                update_type = SKIN_REFRESH_NON_STATIC;
                break;

#ifdef FM_RECORD
            case ACTION_FM_RECORD:
#ifdef FM_RECORD_DBLPRE
                if (lastbutton != ACTION_FM_RECORD_DBLPRE)
                {
                    rec_lastclick = 0;
                    break;
                }
                if (current_tick - rec_lastclick > HZ/2)
                {
                    rec_lastclick = current_tick;
                    break;
                }
#endif /* FM_RECORD_DBLPRE */
#ifndef SIMULATOR
                if(audio_status() == AUDIO_STATUS_RECORD)
                {
                    rec_command(RECORDING_CMD_START_NEWFILE);
                    update_type = SKIN_REFRESH_ALL;
                }
                else
                {
                    rec_command(RECORDING_CMD_START);
                    update_type = SKIN_REFRESH_ALL;
                }
#if CONFIG_CODEC != SWCODEC
                last_seconds = 0;
#endif
#endif /* SIMULATOR */
                break;
#endif /* #ifdef FM_RECORD */

            case ACTION_FM_EXIT:
#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
                if(audio_status() == AUDIO_STATUS_RECORD)
                    audio_stop();
#endif
                keep_playing = true;
                done = true;
                if(presets_have_changed())
                {
                    if(yesno_pop(ID2P(LANG_SAVE_CHANGES)))
                    {
                        presets_save();
                    }
                }

                break;

            case ACTION_STD_PREV:
            case ACTION_STD_NEXT:
                next_station(button == ACTION_STD_PREV ? -1 : 1);
                end_search();
                update_type = SKIN_REFRESH_ALL;
                talk = true;
                break;

            case ACTION_STD_PREVREPEAT:
            case ACTION_STD_NEXTREPEAT:
            {
                int dir = search_dir;
                search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
                if (radio_mode != RADIO_SCAN_MODE)
                {
                    preset_next(search_dir);
                    end_search();
                    talk = true;
                }
                else if (dir == 0)
                {
                    /* Starting auto scan */
                    tuner_set(RADIO_MUTE, 1);
                }
                update_type = SKIN_REFRESH_ALL;
                break;
            }

            case ACTION_SETTINGS_INC:
            case ACTION_SETTINGS_INCREPEAT:
                global_settings.volume++;
                setvol();
                update_type = SKIN_REFRESH_NON_STATIC;
                break;

            case ACTION_SETTINGS_DEC:
            case ACTION_SETTINGS_DECREPEAT:
                global_settings.volume--;
                setvol();
                update_type = SKIN_REFRESH_NON_STATIC;
                break;

            case ACTION_FM_PLAY:
                if (radio_status == FMRADIO_PLAYING)
                    radio_pause();
                else
                    radio_start();

                update_type = SKIN_REFRESH_NON_STATIC;
                talk = false;
                talk_shutup();
                break;

            case ACTION_FM_MENU:
                fms_fix_displays(FMS_EXIT);
                do_menu(&radio_settings_menu, NULL, NULL, false);
                preset_set_current(preset_find(curr_freq));
                fms_fix_displays(FMS_ENTER);
                update_type = SKIN_REFRESH_ALL;
                break;

#ifdef FM_PRESET
            case ACTION_FM_PRESET:
                if(radio_preset_count() < 1)
                {
                    splash(HZ, ID2P(LANG_FM_NO_PRESETS));
                    update_type = SKIN_REFRESH_ALL;
                    break;
                }
                fms_fix_displays(FMS_EXIT);
                handle_radio_presets();
                fms_fix_displays(FMS_ENTER);
                update_type = SKIN_REFRESH_ALL;
                break;
#endif /* FM_PRESET */

#ifdef FM_FREEZE
            case ACTION_FM_FREEZE:
                if(!screen_freeze)
                {
                    splash(HZ, str(LANG_FM_FREEZE));
                    screen_freeze = true;
                }
                else
                {
                    update_type = SKIN_REFRESH_ALL;
                    screen_freeze = false;
                }
                break;
#endif /* FM_FREEZE */

            case SYS_USB_CONNECTED:
#if CONFIG_CODEC != SWCODEC
                /* Only accept USB connection when not recording */
                if(audio_status() != AUDIO_STATUS_RECORD)
#endif
                {
                    default_event_handler(SYS_USB_CONNECTED);
                    screen_freeze = true; /* Cosmetic: makes sure the
                                             radio screen doesn't redraw */
                    done = true;
                }
                break;

#ifdef FM_MODE
           case ACTION_FM_MODE:
                if(radio_mode == RADIO_SCAN_MODE)
                {
                    /* Force scan mode if there are no presets. */
                    if(radio_preset_count() > 0)
                        radio_mode = RADIO_PRESET_MODE;
                }
                else
                    radio_mode = RADIO_SCAN_MODE;
                update_type = SKIN_REFRESH_ALL;
                cond_talk_ids_fq(radio_mode ?
                                 LANG_PRESET : LANG_RADIO_SCAN_MODE);
                talk = true;
                break;
#endif /* FM_MODE */

#ifdef FM_NEXT_PRESET
            case ACTION_FM_NEXT_PRESET:
                preset_next(1);
                end_search();
                update_type = SKIN_REFRESH_ALL;
                talk = true;
                break;
#endif

#ifdef FM_PREV_PRESET
            case ACTION_FM_PREV_PRESET:
                preset_next(-1);
                end_search();
                update_type = SKIN_REFRESH_ALL;
                talk = true;
                break;
#endif
            case ACTION_NONE:
                update_type = SKIN_REFRESH_NON_STATIC;
                break;
             /* this case is used by the softlock feature
              * it requests a full update here */
            case ACTION_REDRAW:
                skin_request_full_update(FM_SCREEN);
                break;

            default:
                default_event_handler(button);
#ifdef HAVE_RDS_CAP
                if (tuner_get(RADIO_EVENT))
                    update_type = SKIN_REFRESH_ALL;
#endif
                if (!tuner_get(RADIO_PRESENT))
                {
#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
                    if(audio_status() == AUDIO_STATUS_RECORD)
                        audio_stop();
#endif
                    keep_playing = false;
                    done = true;
                    if(presets_have_changed())
                    {
                        if(yesno_pop(ID2P(LANG_SAVE_CHANGES)))
                        {
                            radio_save_presets();
                        }
                    }

                    /* Clear the preset list on exit. */
                    preset_list_clear();
                }
                break;
        } /*switch(button)*/

#ifdef FM_RECORD_DBLPRE
        if (button != ACTION_NONE)
            lastbutton = button;
#endif

#if CONFIG_CODEC != SWCODEC
        peak_meter_peek();
#endif

        if(!screen_freeze)
        {
            /* Only display the peak meter when not recording */
#if CONFIG_CODEC != SWCODEC
            if(TIME_AFTER(current_tick, timeout))
            {
                timeout = current_tick + HZ;
#else  /* SWCODEC */
            {
#endif /* CONFIG_CODEC == SWCODEC */

                /* keep "mono" from always being displayed when paused */
                if (radio_status != FMRADIO_PAUSED)
                {
                    stereo = tuner_get(RADIO_STEREO) &&
                        !global_settings.fm_force_mono;

                    if(stereo != last_stereo)
                    {
                        update_type = SKIN_REFRESH_ALL;
                        last_stereo = stereo;
                    }
                }
            }

#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
            seconds = audio_recorded_time() / HZ;
            if (update_type || seconds > last_seconds)
            {
                last_seconds = seconds;
#else
            if (update_type)
            {
#endif
                FOR_NB_SCREENS(i)
                    skin_update(FM_SCREEN, i, update_type);
                if (update_type == (int)SKIN_REFRESH_ALL)
                    skin_request_full_update(CUSTOM_STATUSBAR);
            }
        }
        update_type = 0;

        if (global_settings.talk_file && talk
            && radio_status == FMRADIO_PAUSED)
        {
            talk = false;
            bool enqueue = false;
            if (radio_mode == RADIO_SCAN_MODE)
            {
                talk_value_decimal(curr_freq, UNIT_INT, 6, enqueue);
                enqueue = true;
            }
            if (radio_current_preset() >= 0)
                preset_talk(radio_current_preset(), radio_mode == RADIO_PRESET_MODE,
                            enqueue);
        }

#if CONFIG_CODEC != SWCODEC
        if(audio_status() & AUDIO_STATUS_ERROR)
        {
            done = true;
        }
#endif

#ifndef HAVE_NOISY_IDLE_MODE
        if (TIME_AFTER(current_tick, button_timeout))
        {
            cpu_idle_mode(true);
        }
#endif
    } /*while(!done)*/

#ifndef SIMULATOR
#if CONFIG_CODEC != SWCODEC
    if(audio_status() & AUDIO_STATUS_ERROR)
    {
        splash(0, str(LANG_DISK_FULL));
        audio_error_clear();

        while(1)
        {
            button = get_action(CONTEXT_FM|ALLOW_SOFTLOCK, TIMEOUT_BLOCK);
            if(button == ACTION_FM_STOP)
                break;
        }
    }

    audio_init_playback();
#endif /* CONFIG_CODEC != SWCODEC */

    sound_settings_apply();
#endif /* SIMULATOR */

    if(keep_playing)
    {
/* Catch FMRADIO_PLAYING status for the sim. */
#ifndef SIMULATOR
#if CONFIG_CODEC != SWCODEC
        /* Enable the Left and right A/D Converter */
        audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
                                 sound_default(SOUND_RIGHT_GAIN),
                                 AUDIO_GAIN_LINEIN);
        mas_codec_writereg(6, 0x4000);
#endif
        end_search();
#endif /* SIMULATOR */
    }
    else
    {
#if CONFIG_CODEC == SWCODEC
        audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
#else
        radio_stop();
#endif
    }

#ifndef HAVE_NOISY_IDLE_MODE
    cpu_idle_mode(false);
#endif
    fms_fix_displays(FMS_EXIT);
    pop_current_activity();
    in_screen = false;
} /* radio_screen */

void toggle_mono_mode(bool mono)
{
    tuner_set(RADIO_FORCE_MONO, mono);
}

void set_radio_region(int region)
{
#ifdef HAVE_RADIO_REGION
    tuner_set(RADIO_REGION, region);
#endif
    next_station(0);
    remember_frequency();
    (void)region;
}
/* Voice thread message processing */
static enum voice_state voice_message(struct voice_thread_data *td)
{
    if (quiet_counter > 0)
        queue_wait_w_tmo(&voice_queue, &td->ev, HZ/10);
    else
        queue_wait(&voice_queue, &td->ev);

    switch (td->ev.id)
    {
    case Q_VOICE_PLAY:
        LOGFQUEUE("voice < Q_VOICE_PLAY");
        if (quiet_counter == 0)
        {
            /* Boost CPU now */
            trigger_cpu_boost();
        }
        else
        {
            /* Stop any clip still playing */
            voice_stop_playback();
        }

        quiet_counter = QUIET_COUNT;

        /* Copy the clip info */
        td->vi = *(struct voice_info *)td->ev.data;

        /* Be sure audio buffer is initialized */
        audio_restore_playback(AUDIO_WANT_VOICE);

        /* We need nothing more from the sending thread - let it run */
        queue_reply(&voice_queue, 1);

        /* Make audio play more softly and set delay to return to normal
           playback level */
        pcmbuf_soft_mode(true);

        /* Clean-start the decoder */
        td->st = speex_decoder_init(&speex_wb_mode);

        /* Make bit buffer use our own buffer */
        speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size);
        speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead);

        return VOICE_STATE_DECODE;

    case SYS_TIMEOUT:
        if (voice_unplayed_frames())
        {
            /* Waiting for PCM to finish */
            break;
        }

        /* Drop through and stop the first time after clip runs out */
        if (quiet_counter-- != QUIET_COUNT)
        {
            if (quiet_counter <= 0)
                pcmbuf_soft_mode(false);

            break;
        }

        /* Fall-through */
    case Q_VOICE_STOP:
        LOGFQUEUE("voice < Q_VOICE_STOP");
        cancel_cpu_boost();
        voice_stop_playback();
        break;

    /* No default: no other message ids are sent */
    }

    return VOICE_STATE_MESSAGE;
}
示例#11
0
/* Buffer data for the given handle.
   Return whether or not the buffering should continue explicitly.  */
static bool buffer_handle(int handle_id)
{
    logf("buffer_handle(%d)", handle_id);
    struct memory_handle *h = find_handle(handle_id);
    bool stop = false;

    if (!h)
        return true;

    if (h->filerem == 0) {
        /* nothing left to buffer */
        return true;
    }

    if (h->fd < 0)  /* file closed, reopen */
    {
        if (*h->path)
            h->fd = open(h->path, O_RDONLY);

        if (h->fd < 0)
        {
            /* could not open the file, truncate it where it is */
            h->filesize -= h->filerem;
            h->filerem = 0;
            return true;
        }

        if (h->offset)
            lseek(h->fd, h->offset, SEEK_SET);
    }

    trigger_cpu_boost();

    if (h->type == TYPE_ID3)
    {
        if (!get_metadata((struct mp3entry *)(buffer + h->data), h->fd, h->path))
        {
            /* metadata parsing failed: clear the buffer. */
            memset(buffer + h->data, 0, sizeof(struct mp3entry));
        }
        close(h->fd);
        h->fd = -1;
        h->filerem = 0;
        h->available = sizeof(struct mp3entry);
        h->widx += sizeof(struct mp3entry);
        send_event(BUFFER_EVENT_FINISHED, &h->id);
        return true;
    }

    while (h->filerem > 0 && !stop)
    {
        /* max amount to copy */
        size_t copy_n = MIN( MIN(h->filerem, BUFFERING_DEFAULT_FILECHUNK),
                             buffer_len - h->widx);

        ssize_t overlap;
        uintptr_t next_handle = ringbuf_offset(h->next);

        /* stop copying if it would overwrite the reading position */
        if (ringbuf_add_cross(h->widx, copy_n, buf_ridx) >= 0)
            return false;

        /* FIXME: This would overwrite the next handle
         * If this is true, then there's a handle even though we have still
         * data to buffer. This should NEVER EVER happen! (but it does :( ) */
        if (h->next && (overlap
                = ringbuf_add_cross(h->widx, copy_n, next_handle)) > 0)
        {
            /* stop buffering data for now and post-pone buffering the rest */
            stop = true;
            DEBUGF( "%s(): Preventing handle corruption: h1.id:%d h2.id:%d"
                    " copy_n:%lu overlap:%ld h1.filerem:%lu\n", __func__,
                    h->id, h->next->id, (unsigned long)copy_n, overlap,
                    (unsigned long)h->filerem);
            copy_n -= overlap;
        }

        /* rc is the actual amount read */
        int rc = read(h->fd, &buffer[h->widx], copy_n);

        if (rc < 0)
        {
            /* Some kind of filesystem error, maybe recoverable if not codec */
            if (h->type == TYPE_CODEC) {
                logf("Partial codec");
                break;
            }

            DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
            h->filesize -= h->filerem;
            h->filerem = 0;
            break;
        }

        /* Advance buffer */
        h->widx = ringbuf_add(h->widx, rc);
        if (h == cur_handle)
            buf_widx = h->widx;
        h->available += rc;
        h->filerem -= rc;

        /* If this is a large file, see if we need to break or give the codec
         * more time */
        if (h->type == TYPE_PACKET_AUDIO &&
            pcmbuf_is_lowdata() && !buffer_is_low())
        {
            sleep(1);
        }
        else
        {
            yield();
        }

        if (!queue_empty(&buffering_queue))
            break;
    }

    if (h->filerem == 0) {
        /* finished buffering the file */
        close(h->fd);
        h->fd = -1;
        send_event(BUFFER_EVENT_FINISHED, &h->id);
    }

    return !stop;
}
示例#12
0
/* Voice thread message processing */
static void voice_message(struct voice_thread_data *td)
{
    while (1)
    {
        switch (td->ev.id)
        {
        case Q_VOICE_PLAY:
            LOGFQUEUE("voice < Q_VOICE_PLAY");
            /* Put up a block for completion signal */
            voice_done = false;

            /* Copy the clip info */
            td->vi = *(struct voice_info *)td->ev.data;

            /* Be sure audio buffer is initialized */
            audio_restore_playback(AUDIO_WANT_VOICE);

            /* We need nothing more from the sending thread - let it run */
            queue_reply(&voice_queue, 1);

            if (td->state == TSTATE_STOPPED)
            {
                /* Boost CPU now */
                trigger_cpu_boost();
            }
            else if (!playback_is_playing())
            {
                /* Just voice, stop any clip still playing */
                pcmbuf_play_stop();
            }

            /* Clean-start the decoder */
            td->st = speex_decoder_init(&speex_wb_mode);

            /* Make bit buffer use our own buffer */
            speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size);
            speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead);

            td->state = TSTATE_DECODE;
            return;

        case Q_VOICE_STOP:
            LOGFQUEUE("voice < Q_VOICE_STOP: %ld", td->ev.data);

            if (td->ev.data != 0 && !playback_is_playing())
            {
                /* If not playing, it's just voice so stop pcm playback */
                pcmbuf_play_stop();
            }

            /* Cancel boost */
            cancel_cpu_boost();

            td->state = TSTATE_STOPPED;
            voice_done = true;
            break;

        case Q_VOICE_STATE:
            LOGFQUEUE("voice < Q_VOICE_STATE");
            queue_reply(&voice_queue, td->state);

            if (td->state == TSTATE_STOPPED)
                break; /* Not in a playback state */

            return;

        default:
            /* Default messages get a reply and thread continues with no
             * state transition */
            LOGFQUEUE("voice < default");

            if (td->state == TSTATE_STOPPED)
                break;  /* Not in playback state */

            queue_reply(&voice_queue, 0);
            return;
        }

        queue_wait(&voice_queue, &td->ev);
    }
}