/* vim: set sw=3 ts=3 sts=3 expandtab: */ #include "ecdb.h" typedef struct Burn_Data Burn_Data; struct Burn_Data { BurnDisc *disc; BurnSession *session; Eina_List *sources; Eina_List *tracks; Ecdb_Project *proj; Ecdb_Page *page; }; int ecdb_burn_finished(void *data, int type, void *event); int ecdb_erase_project_init(Ecdb_Erase_Project *proj); static void ecdb_burn_progress_handler(void *data, void *buffer, unsigned int nbyte); void ecdb_sources_list_free(Eina_List *list); void ecdb_tracks_list_free(Eina_List *list); int ecdb_burn_project(Ecdb_Burn_Project *proj, Ecdb_Page *page) { char reasons[BURN_REASONS_LEN]; int padding, i; Burn_Data *data; BurnTrack *track; BurnSource *source; BurnWriteOpts *opts; pthread_t progress_update; i = 0; data = calloc(1, sizeof(Burn_Data)); if (!data) { EINA_ERROR_PWARN("Error: Cannot create burn data structure!\n"); return FALSE; } data->proj = ECDB_PROJECT(proj); data->page = page; if (proj->burn_mode != BURN_AUDIO) padding = 300*1024; data->disc = burn_disc_create(); data->session = burn_session_create(); burn_disc_add_session(data->disc, data->session, BURN_POS_END); track = burn_track_create(); burn_track_define_data(track, 0, padding, 1, proj->burn_mode); source = ecdb_image_project(proj); if (!source) { EINA_ERROR_PWARN("Failed to add any files to burn disc!\n"); burn_session_free(data->session); burn_disc_free(data->disc); ecdb_sources_list_free(data->sources); ecdb_tracks_list_free(data->tracks); FREE(data); return ECDB_ERROR_IMAGE_CREATE; } if (burn_track_set_source(track, source) != BURN_SOURCE_OK) { EINA_ERROR_PWARN("Error: Cannot attach source object to track object!\n"); burn_session_free(data->session); burn_disc_free(data->disc); ecdb_sources_list_free(data->sources); ecdb_tracks_list_free(data->tracks); FREE(data); return ECDB_ERROR_SOURCE_ATTACH; } burn_session_add_track(data->session, track, BURN_POS_END); data->sources = eina_list_append(data->sources, source); data->tracks = eina_list_append(data->tracks, track); opts = burn_write_opts_new(ECDB_PROJECT(proj)->drive->tangible[0].drive); burn_write_opts_set_perform_opc(opts, proj->opc); burn_write_opts_set_multi(opts, proj->multi); if (proj->simulate) { EINA_ERROR_PINFO("Simulating Burn!\n"); } burn_write_opts_set_simulate(opts, proj->simulate); burn_drive_set_speed(ECDB_PROJECT(proj)->drive->tangible->drive, 0, proj->speed); burn_write_opts_set_underrun_proof(opts, proj->underrun_proof); EINA_ERROR_PDBG("Searching for burn mode\n"); if (burn_write_opts_auto_write_type(opts, data->disc, reasons, 0) == BURN_WRITE_NONE) { EINA_ERROR_PWARN("Error: Failed to find a suitable write mode" " for disc!\n"); burn_session_free(data->session); burn_disc_free(data->disc); burn_write_opts_free(opts); ecdb_sources_list_free(data->sources); ecdb_tracks_list_free(data->tracks); FREE(data); return ECDB_ERROR_WRITE_MODE; } burn_disc_write(opts, data->disc); burn_write_opts_free(opts); EINA_ERROR_PINFO("Disc now burning\n"); ECDB_PROJECT(proj)->pipe = ecore_pipe_add(ecdb_burn_progress_handler, data); pthread_create(&progress_update, NULL, ecdb_drive_progress_update, proj); pthread_detach(progress_update); ECDB_PROJECT(proj)->ev_handler = ecore_event_handler_add (ECDB_DRIVE_ACTION_FINISHED, ecdb_burn_finished, data); return ECDB_ERROR_NONE; } /* This function is pretty naive... Should probably update it at some time */ void * ecdb_drive_progress_update(void *data) { const Ecdb_Project *proj; BurnProgress p; struct burn_drive *drive; proj = data; if (!proj->drive->tangible) { EINA_ERROR_PWARN("No tangible drive!\n"); ecore_pipe_del(proj->pipe); pthread_exit(NULL); } drive = proj->drive->tangible[0].drive; EINA_ERROR_PDBG("Progress update active\n"); while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING) { usleep(100000); } while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) { if (p.sectors > 0) { ecore_pipe_write(proj->pipe, &p, sizeof(p)); } usleep(100000); } EINA_ERROR_PDBG("Closing pipe\n"); ecore_pipe_write(proj->pipe, proj->pipe, sizeof(Ecore_Pipe)); pthread_exit(NULL); } static void ecdb_burn_progress_handler(void *data, void *buffer, unsigned int nbyte) { BurnProgress *p; Evas_Object *swallow; Burn_Data *bdata; static int last_sector = 0; int percent; Edje_Message_Int_Set *progress_msg; Edje_Message_String finalize; if (nbyte != sizeof(BurnProgress)) { ecore_event_add(ECDB_DRIVE_ACTION_FINISHED, NULL, NULL, NULL); EINA_ERROR_PDBG("Adding event to queue.\n"); last_sector = 0; return; } else { p = buffer; } /* Libburn reports p->sector as being 0 right at the end of the job, * so store the last sector and use that to determine the proper * percentage/sector to set */ if (last_sector <= p->sector) { last_sector = p->sector; } else { last_sector = p->sectors; } bdata = data; if (!bdata) { EINA_ERROR_PWARN("ecdb_burn_progress_handler: NULL bdata!\n"); return; } if ((!bdata->page) || (!bdata->proj)) { EINA_ERROR_PWARN("ecdb_burn_progress_handler: NULL page or proj!\n"); return; } switch (bdata->proj->type) { case ECDB_AUDIO_PROJECT: swallow = bdata->page->audio; break; case ECDB_DATA_PROJECT: swallow = bdata->page->data; break; case ECDB_IMAGE_PROJECT: swallow = bdata->page->image; break; default: EINA_ERROR_PWARN("ecdb_burn_progress_handler: Unrecognized " "project type!\n"); return; } percent = (int)((double)(last_sector + 1) / (double)p->sectors * 100.0); if (percent >= 100) { finalize.str = "Finalizing disc..."; edje_object_message_send(swallow, EDJE_MESSAGE_STRING, 1, &finalize); } else { progress_msg = alloca(sizeof(Edje_Message_Int_Set) + (4 * sizeof(int))); progress_msg->count = 5; progress_msg->val[0] = percent; progress_msg->val[1] = last_sector; progress_msg->val[2] = p->sectors; progress_msg->val[3] = (int)p->buffer_available; progress_msg->val[4] = (int)p->buffer_capacity; edje_object_message_send(swallow, EDJE_MESSAGE_INT_SET, 0, progress_msg); } } int ecdb_burn_finished(void *data, int type, void *event) { Burn_Data *proj; proj = data; EINA_ERROR_PDBG("Freeing source and tracks\n"); ecdb_sources_list_free(proj->sources); ecdb_tracks_list_free(proj->tracks); EINA_ERROR_PDBG("Freeing session and disc\n"); burn_session_free(proj->session); burn_disc_free(proj->disc); EINA_ERROR_PDBG("Releasing drive\n"); burn_drive_release(proj->proj->drive->tangible[0].drive, 1); burn_drive_info_free(proj->proj->drive->tangible); EINA_ERROR_PINFO("Burn Complete\n"); ecore_event_handler_del(proj->proj->ev_handler); proj->proj->ev_handler = NULL; ecore_pipe_del(proj->proj->pipe); proj->proj->pipe = NULL; switch (proj->proj->type) { case ECDB_AUDIO_PROJECT: EINA_ERROR_PWARN("How in the world did you get here?\n"); //ecdb_burn_audio_cleanup(proj->page); break; case ECDB_DATA_PROJECT: ecdb_burn_data_cleanup(proj->page); break; case ECDB_IMAGE_PROJECT: ecdb_burn_image_cleanup(proj->page); break; default: EINA_ERROR_PWARN("ecdb_burn_finished: unknown project type!\n"); } FREE(proj); return TRUE; } void ecdb_sources_list_free(Eina_List *list) { void *data; EINA_LIST_FREE(list, data) burn_source_free(data); } void ecdb_tracks_list_free(Eina_List *list) { void *data; EINA_LIST_FREE(list, data) burn_track_free(data); }