static void *dae_play_loop(void *arg) { char *buffer = g_malloc(CD_FRAMESIZE_RAW * CDDA_DAE_FRAMES); int pos = LBA(cdda_playing.cd_toc.track[cdda_playing.track]); int end, frames; if (cdda_playing.track == cdda_playing.cd_toc.last_track) end = LBA(cdda_playing.cd_toc.leadout); else end = LBA(cdda_playing.cd_toc.track[cdda_playing.track + 1]); while (cdda_playing.playing) { int left; char *data; if (dae_data.seek != -1) { cdda_ip.output->flush(dae_data.seek * 1000); pos = LBA(cdda_playing.cd_toc.track[cdda_playing.track]) + dae_data.seek * 75; dae_data.seek = -1; dae_data.eof = FALSE; } frames = MIN(CDDA_DAE_FRAMES, end - pos); if (frames == 0) dae_data.eof = TRUE; if (dae_data.eof) { xmms_usleep(30000); continue; } frames = read_audio_data(cdda_playing.fd, pos, frames, buffer); if (frames <= 0) { int err = -frames; if (err == EOPNOTSUPP) dae_data.eof = TRUE; else { /* * If the read failed, skip ahead to * avoid getting stuck on scratches * and such. */ g_message("read_audio_data() failed: %s (%d)", strerror(err), err); pos += MIN(CDDA_DAE_FRAMES, end - pos); } continue; } left = frames * CD_FRAMESIZE_RAW; data = buffer; while (cdda_playing.playing && left > 0 && dae_data.seek == -1) { int cur = MIN(512 * 2 * 2, left); cdda_ip.add_vis_pcm(cdda_ip.output->written_time(), FMT_S16_LE, 2, cur, data); while (cdda_ip.output->buffer_free() < cur && cdda_playing.playing && dae_data.seek == -1) xmms_usleep(30000); if (cdda_playing.playing && dae_data.seek == -1) cdda_ip.output->write_audio(data, cur); left -= cur; data += cur; } pos += frames; } cdda_ip.output->buffer_free(); cdda_ip.output->buffer_free(); g_free(buffer); return NULL; }
static void *playlist_get_info_func(void *arg) { GList *node; gboolean update_playlistwin = FALSE, update_mainwin = FALSE; PlaylistEntry *entry; while (playlist_get_info_going) { if (cfg.get_info_on_load && playlist_get_info_scan_active) { PL_LOCK(); for (node = get_playlist(); node; node = g_list_next(node)) { entry = node->data; if (entry->title || entry->length != -1) continue; if (!playlist_get_info_entry(entry)) { if (g_list_index(get_playlist(), entry) == -1) /* Entry disapeared while we looked it up. Restart. */ node = get_playlist(); } else if (entry->title || entry->length != -1) { update_playlistwin = TRUE; if (entry == playlist_position) update_mainwin = TRUE; break; } } PL_UNLOCK(); if (!node) playlist_get_info_scan_active = FALSE; } else if (!cfg.get_info_on_load && cfg.get_info_on_demand && cfg.playlist_visible && !cfg.playlist_shaded) { gboolean found = FALSE; PL_LOCK(); if (!get_playlist()) { PL_UNLOCK(); xmms_usleep(1000000); continue; } for (node = g_list_nth(get_playlist(), playlistwin_get_toprow()); node && playlistwin_item_visible(g_list_position(get_playlist(), node)); node = g_list_next(node)) { entry = node->data; if (entry->title || entry->length != -1) continue; if (!playlist_get_info_entry(entry)) { if (g_list_index(get_playlist(), entry) == -1) /* Entry disapeared while we looked it up. Restart. */ node = g_list_nth(get_playlist(), playlistwin_get_toprow()); } else if (entry->title || entry->length != -1) { update_playlistwin = TRUE; if (entry == playlist_position) update_mainwin = TRUE; found = TRUE; break; } } PL_UNLOCK(); if (!found) { xmms_usleep(500000); continue; } } else xmms_usleep(500000); if (update_playlistwin) { playlistwin_update_list(); update_playlistwin = FALSE; } if (update_mainwin) { mainwin_set_info_text(); update_mainwin = FALSE; } } pthread_exit(NULL); }
static void *play_loop(void *arg) { enum uade_control_state controlstate = UADE_S_STATE; int ret; int left = 0; uint8_t space[UADE_MAX_MESSAGE_SIZE]; struct uade_msg *um = (struct uade_msg *) space; int subsong_end = 0; uint16_t *sm; int i; unsigned int play_bytes, tailbytes = 0; uint64_t subsong_bytes = 0; char *reason; uint32_t *u32ptr; int writeoffs; int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE; int song_end_trigger = 0; int64_t skip_bytes = 0; uade_lock(); record_playtime = 1; uade_unlock(); while (1) { if (controlstate == UADE_S_STATE) { assert(left == 0); if (abort_playing) { uade_lock(); record_playtime = 0; uade_unlock(); break; } uade_lock(); if (uade_seek_forward) { skip_bytes += uade_seek_forward * UADE_BYTES_PER_FRAME * state.config.frequency; uade_ip.output->flush(uade_ip.output->written_time() + uade_seek_forward * 1000); uade_seek_forward = 0; } if (uade_select_sub != -1) { state.song->cur_subsong = uade_select_sub; uade_change_subsong(&state); uade_ip.output->flush(0); uade_select_sub = -1; subsong_end = 0; subsong_bytes = 0; /* we do this to avoid timeout, and to not record playtime */ state.song->out_bytes = 0; record_playtime = 0; uade_info_string(); } if (subsong_end && song_end_trigger == 0) { if (state.song->cur_subsong == -1 || state.song->max_subsong == -1) { song_end_trigger = 1; } else { state.song->cur_subsong++; if (state.song->cur_subsong > state.song->max_subsong) { song_end_trigger = 1; } else { int x = 0; uade_change_subsong(&state); while (uade_ip.output->buffer_playing()) { /* Sleep at most 5 secs */ if (x >= 500) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "UADE: blocking work-around activated.\n"); break; } x++; xmms_usleep(10000); } uade_ip.output->flush(0); subsong_end = 0; subsong_bytes = 0; uade_gui_subsong_changed(state.song->cur_subsong); uade_info_string(); } } } uade_unlock(); if (song_end_trigger) { /* We must drain the audio fast if abort_playing happens (e.g. the user changes song when we are here waiting the sound device) */ while (uade_ip.output->buffer_playing() && abort_playing == 0) xmms_usleep(10000); break; } left = uade_read_request(&state.ipc); if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n"); return NULL; } controlstate = UADE_R_STATE; } else { if (uade_receive_message(um, sizeof(space), &state.ipc) <= 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade\n"); exit(1); } switch (um->msgtype) { case UADE_COMMAND_TOKEN: controlstate = UADE_S_STATE; break; case UADE_REPLY_DATA: sm = (uint16_t *) um->data; for (i = 0; i < um->size; i += 2) { *sm = ntohs(*sm); sm++; } if (subsong_end) { play_bytes = tailbytes; tailbytes = 0; } else { play_bytes = um->size; } if (subsong_end == 0 && song_end_trigger == 0 && uade_test_silence(um->data, play_bytes, &state)) { subsong_end = 1; } subsong_bytes += play_bytes; uade_lock(); state.song->out_bytes += play_bytes; uade_unlock(); if (skip_bytes > 0) { if (play_bytes <= skip_bytes) { skip_bytes -= play_bytes; play_bytes = 0; } else { play_bytes -= skip_bytes; skip_bytes = 0; } } uade_effect_run(&state.effects, (int16_t *) um->data, play_bytes / framesize); uade_ip.add_vis_pcm(uade_ip.output->written_time(), sample_format, UADE_CHANNELS, play_bytes, um->data); writeoffs = 0; while (writeoffs < play_bytes) { int writable; while ((writable = uade_ip.output->buffer_free()) <= 0) { if (abort_playing) goto nowrite; xmms_usleep(10000); } if (writable > (play_bytes - writeoffs)) writable = play_bytes - writeoffs; uade_ip.output->write_audio(&um->data[writeoffs], writable); writeoffs += writable; } nowrite: if (state.config.timeout != -1 && state.config.use_timeouts) { if (song_end_trigger == 0) { uade_lock(); if (state.song->out_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.timeout) { song_end_trigger = 1; record_playtime = 0; } uade_unlock(); } } if (state.config.subsong_timeout != -1 && state.config.use_timeouts) { if (subsong_end == 0 && song_end_trigger == 0) { if (subsong_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.subsong_timeout) { subsong_end = 1; record_playtime = 0; } } } assert (left >= um->size); left -= um->size; break; case UADE_REPLY_FORMATNAME: uade_check_fix_string(um, 128); strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname); strlcpy(state.song->formatname, (char *) um->data, sizeof state.song->formatname); break; case UADE_REPLY_MODULENAME: uade_check_fix_string(um, 128); strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename); strlcpy(state.song->modulename, (char *) um->data, sizeof state.song->modulename); break; case UADE_REPLY_MSG: uade_check_fix_string(um, 128); plugindebug("Message: %s\n", (char *) um->data); break; case UADE_REPLY_PLAYERNAME: uade_check_fix_string(um, 128); strlcpy(gui_playername, (char *) um->data, sizeof gui_playername); strlcpy(state.song->playername, (char *) um->data, sizeof state.song->playername); break; case UADE_REPLY_SONG_END: if (um->size < 9) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Invalid song end reply\n"); exit(1); } tailbytes = ntohl(((uint32_t *) um->data)[0]); /* next ntohl() is only there for a principle. it is not useful */ if (ntohl(((uint32_t *) um->data)[1]) == 0) { /* normal happy song end. go to next subsong if any */ subsong_end = 1; } else { /* unhappy song end (error in the 68k side). skip to next song ignoring possible subsongs */ song_end_trigger = 1; } i = 0; reason = (char *) &um->data[8]; while (reason[i] && i < (um->size - 8)) i++; if (reason[i] != 0 || (i != (um->size - 9))) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Broken reason string with song end notice\n"); exit(1); } break; case UADE_REPLY_SUBSONG_INFO: if (um->size != 12) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong info: too short a message\n"); exit(1); } u32ptr = (uint32_t *) um->data; uade_lock(); state.song->min_subsong = ntohl(u32ptr[0]); state.song->max_subsong = ntohl(u32ptr[1]); state.song->cur_subsong = ntohl(u32ptr[2]); if (!(-1 <= state.song->min_subsong && state.song->min_subsong <= state.song->cur_subsong && state.song->cur_subsong <= state.song->max_subsong)) { int tempmin = state.song->min_subsong, tempmax = state.song->max_subsong; __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename); state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax; state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin; if (state.song->cur_subsong > state.song->max_subsong) state.song->max_subsong = state.song->cur_subsong; else if (state.song->cur_subsong < state.song->min_subsong) state.song->min_subsong = state.song->cur_subsong; } uade_unlock(); break; default: __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Expected sound data. got %d.\n", um->msgtype); plugin_disabled = 1; return NULL; } } } last_beat_played = 1; if (uade_send_short_message(UADE_COMMAND_REBOOT, &state.ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send reboot.\n"); return NULL; } if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n"); return NULL; } do { ret = uade_receive_message(um, sizeof(space), &state.ipc); if (ret < 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade.\n"); return NULL; } if (ret == 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "End of input after reboot.\n"); return NULL; } } while (um->msgtype != UADE_COMMAND_TOKEN); return NULL; }
void *play_loop_(void *arg) { unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; (void)arg; while(stream_data_.is_playing) { if(!stream_data_.eof) { while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { unsigned s; s = sample_buffer_last_ - sample_buffer_first_; if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) { stream_data_.eof = true; break; } else if(!FLAC__stream_decoder_process_single(decoder_)) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); stream_data_.eof = true; break; } blocksize = sample_buffer_last_ - sample_buffer_first_ - s; decode_position_frame_last = decode_position_frame; if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; } if(sample_buffer_last_ - sample_buffer_first_ > 0) { const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; unsigned written_time, bh_index_w; FLAC__uint64 decode_position; sample_buffer_first_ += n; flac_ip.add_vis_pcm(flac_ip.output->written_time(), stream_data_.sample_format, stream_data_.channels, bytes, sample_buffer_start); while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) xmms_usleep(10000); if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) flac_ip.output->write_audio(sample_buffer_start, bytes); /* compute current bitrate */ written_time = flac_ip.output->written_time(); bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_w != bh_index_last_w) { bh_index_last_w = bh_index_w; decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = decode_position > decode_position_last && written_time > written_time_last ? 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample; decode_position_last = decode_position; written_time_last = written_time; } } else { stream_data_.eof = true; xmms_usleep(10000); } } else xmms_usleep(10000); if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) { const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec; FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples); if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples) target_sample = stream_data_.total_samples - 1; if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) { flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000); bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: SEEK ERROR\n"); FLAC__stream_decoder_flush(decoder_); stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } stream_data_.seek_to_in_sec = -1; } else { /* display the right bitrate from history */ unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { bh_index_last_o = bh_index_o; flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels); } } } safe_decoder_finish_(decoder_); /* are these two calls necessary? */ flac_ip.output->buffer_free(); flac_ip.output->buffer_free(); g_free(stream_data_.title); pthread_exit(NULL); return 0; /* to silence the compiler warning about not returning a value */ }
void *oss_loop(void *arg) { gint length, cnt; fd_set set; struct timeval tv; while (going) { if (oss_used() > prebuffer_size) prebuffer = FALSE; if (oss_used() > 0 && !paused && !prebuffer) { tv.tv_sec = 0; tv.tv_usec = 10000; FD_ZERO(&set); FD_SET(fd, &set); if(!select_works || (select(fd + 1, NULL, &set, NULL, &tv) > 0)) { length = MIN(blk_size, oss_used()); while (length > 0) { cnt = MIN(length,buffer_size-rd_index); oss_write_audio(buffer + rd_index, cnt); rd_index=(rd_index+cnt)%buffer_size; length-=cnt; } if (!oss_used()) ioctl(fd, SNDCTL_DSP_POST, 0); } } else xmms_usleep(10000); oss_calc_device_buffer_used(); if (do_pause && !paused) { do_pause = FALSE; paused = TRUE; /* * We lose some data here that is sent to the * soundcard, but not yet played. I don't * think this is worth fixing. */ ioctl(fd, SNDCTL_DSP_RESET, 0); } else if (unpause && paused) { unpause = FALSE; close(fd); fd = open(device_name, O_WRONLY); oss_set_audio_params(); paused = FALSE; } if (flush != -1) { /* * This close and open is a work around of a * bug that exists in some drivers which cause * the driver to get f****d up by a reset */ ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); fd = open(device_name, O_WRONLY); oss_set_audio_params(); output_time_offset = flush; written = ((guint64)flush * input.bps) / 1000; rd_index = wr_index = output_bytes = 0; flush = -1; prebuffer = TRUE; } } ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); g_free(buffer); pthread_exit(NULL); }