/** Play an audio track. */ static bool play_track(track_t i_start_track, track_t i_end_track) { bool b_ok = true; char line[80]; if (!b_cd) { read_toc(p_cdio); } read_subchannel(p_cdio); if (!b_cd || i_first_track == CDIO_CDROM_LEADOUT_TRACK) return false; if (debug) fprintf(stderr,"play tracks: %d-%d => ", i_start_track, i_end_track-1); if (i_start_track < i_first_track) i_start_track = i_first_track; if (i_start_track > i_last_audio_track) i_start_track = i_last_audio_track; if (i_end_track < i_first_track) i_end_track = i_first_track; if (i_end_track > i_last_audio_track) i_end_track = i_last_audio_track; i_end_track++; if (debug) fprintf(stderr,"%d-%d\n",i_start_track, i_end_track-1); cd_pause(p_cdio); snprintf(line, sizeof(line), "play track %d to track %d.", i_start_track, i_end_track-1); action(line); b_ok = (DRIVER_OP_SUCCESS == cdio_audio_play_msf(p_cdio, &(toc[i_start_track]), &(toc[i_end_track])) ); if (!b_ok) xperror("play"); return b_ok; }
/*! Play an audio track. */ static bool play_track(track_t i_start_track, track_t i_end_track) { bool b_ok = true; if (!b_cd) { cd_close(psz_device); read_toc(p_cdio); } read_subchannel(p_cdio); if (!b_cd || i_first_track == CDIO_CDROM_LEADOUT_TRACK) return false; if (debug) fprintf(stderr,"play tracks: %d-%d => ", i_start_track, i_end_track); if (i_start_track < i_first_track) i_start_track = i_first_track; if (i_start_track > i_last_audio_track) i_start_track = i_last_audio_track; if (i_end_track < i_first_track) i_end_track = i_first_track; if (i_end_track > i_last_audio_track) i_end_track = i_last_audio_track; if (debug) fprintf(stderr,"%d-%d\n",i_start_track, i_end_track); cd_pause(p_cdio); b_ok = (DRIVER_OP_SUCCESS == cdio_audio_play_msf(p_cdio, &(toc[i_start_track]), &(toc[i_end_track])) ); if (!b_ok) xperror("play"); return b_ok; }
/* * Description: Pause or Resume the Current Track. */ static void open_close() { if ( cd_is_paused ()) { cd_resume (); } else if ( cd_current_track ()) { cd_pause (); } }
void list_tracks() { refresh_screen(); int cur_print_line = MESSAGE_LINE; mvprintw(cur_print_line, OUTPUT_COL, "CD Track Listing:"); cur_print_line += 2; FILE *fp = fopen(tracks_file, "r"); if (NULL == fp) { mvprintw(ERROR_LINE, OUTPUT_COL, "%s\n", "save_record(): fopen error"); refresh(); return; } char buf[1024]; memset(buf, 0, sizeof(buf)); int len = strlen(cur_cd_cat); while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, cur_cd_cat, len) == 0) { char *track_ptr = buf; int separator_count = 0; while (*track_ptr != '\0') { if (*track_ptr == ',') ++ separator_count; if (separator_count >= 2) { ++ track_ptr; break; } ++ track_ptr; } mvprintw(cur_print_line ++, OUTPUT_COL, "%s", track_ptr); } } refresh(); fclose(fp); cd_pause(cur_print_line + 1); }
void play_release() { struct disc_status status; if(!disc_present) return; cd_poll(cd_fd, &status); switch(status.status_mode) { case CDAUDIO_PLAYING: cd_pause(cd_fd); return; case CDAUDIO_PAUSED: cd_resume(cd_fd); return; default: cd_play(cd_fd, play_track); } }
static void skip(int diff) { msf_t start_msf; int sec; read_subchannel(p_cdio); if (!b_cd || i_first_track == CDIO_CDROM_LEADOUT_TRACK) return; sec = cdio_audio_get_msf_seconds(&sub.abs_addr); sec += diff; if (sec < 0) sec = 0; start_msf.m = cdio_to_bcd8(sec / CDIO_CD_SECS_PER_MIN); start_msf.s = cdio_to_bcd8(sec % CDIO_CD_SECS_PER_MIN); start_msf.f = 0; cd_pause(p_cdio); if ( DRIVER_OP_SUCCESS != cdio_audio_play_msf(p_cdio, &start_msf, &(toc[i_last_audio_track])) ) xperror("play"); }
/* * Perform special action on behalf of the user. * Knows about the internals of this device */ int cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct cd_softc *cd; struct disklabel *lp; int part = DISKPART(dev); int error = 0; cd = cdlookup(DISKUNIT(dev)); if (cd == NULL) return ENXIO; SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx\n", cmd)); /* * If the device is not valid.. abandon ship */ if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { switch (cmd) { case DIOCWLABEL: case DIOCLOCK: case DIOCEJECT: case SCIOCIDENTIFY: case SCIOCCOMMAND: case SCIOCDEBUG: case CDIOCLOADUNLOAD: case SCIOCRESET: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTEREO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: case CDIOCCLOSE: case CDIOCEJECT: case CDIOCALLOW: case CDIOCPREVENT: case CDIOCSETDEBUG: case CDIOCCLRDEBUG: case CDIOCRESET: case DVD_AUTH: case DVD_READ_STRUCT: case MTIOCTOP: if (part == RAW_PART) break; /* FALLTHROUGH */ default: if ((cd->sc_link->flags & SDEV_OPEN) == 0) error = ENODEV; else error = EIO; goto exit; } } switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); cdgetdisklabel(dev, cd, lp, 0); bcopy(lp, cd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); break; case DIOCGDINFO: case DIOCGPDINFO: *(struct disklabel *)addr = *(cd->sc_dk.dk_label); break; case DIOCGPART: ((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &cd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; break; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; break; } if ((error = cdlock(cd)) != 0) break; cd->flags |= CDF_LABELLING; error = setdisklabel(cd->sc_dk.dk_label, (struct disklabel *)addr, /*cd->sc_dk.dk_openmask : */0); if (error == 0) { } cd->flags &= ~CDF_LABELLING; cdunlock(cd); break; case DIOCWLABEL: error = EBADF; break; case CDIOCPLAYTRACKS: { struct ioc_play_track *args = (struct ioc_play_track *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play_tracks(cd, args->start_track, args->start_index, args->end_track, args->end_index); break; } case CDIOCPLAYMSF: { struct ioc_play_msf *args = (struct ioc_play_msf *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play_msf(cd, args->start_m, args->start_s, args->start_f, args->end_m, args->end_s, args->end_f); break; } case CDIOCPLAYBLOCKS: { struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr; if ((error = cd_set_pa_immed(cd, 0)) != 0) break; error = cd_play(cd, args->blk, args->len); break; } case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args = (struct ioc_read_subchannel *)addr; struct cd_sub_channel_info data; int len = args->data_len; if (len > sizeof(data) || len < sizeof(struct cd_sub_channel_header)) { error = EINVAL; break; } error = cd_read_subchannel(cd, args->address_format, args->data_format, args->track, &data, len); if (error) break; len = min(len, _2btol(data.header.data_len) + sizeof(struct cd_sub_channel_header)); error = copyout(&data, args->data, len); break; } case CDIOREADTOCHEADER: { struct ioc_toc_header th; if ((error = cd_read_toc(cd, 0, 0, &th, sizeof(th), 0)) != 0) break; if (cd->sc_link->quirks & ADEV_LITTLETOC) th.len = letoh16(th.len); else th.len = betoh16(th.len); bcopy(&th, addr, sizeof(th)); break; } case CDIOREADTOCENTRYS: { struct cd_toc *toc; struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr; struct ioc_toc_header *th; struct cd_toc_entry *cte; int len = te->data_len; int ntracks; toc = malloc(sizeof(*toc), M_TEMP, M_WAITOK | M_ZERO); th = &toc->header; if (len > sizeof(toc->entries) || len < sizeof(struct cd_toc_entry)) { free(toc, M_TEMP); error = EINVAL; break; } error = cd_read_toc(cd, te->address_format, te->starting_track, toc, len + sizeof(struct ioc_toc_header), 0); if (error) { free(toc, M_TEMP); break; } if (te->address_format == CD_LBA_FORMAT) for (ntracks = th->ending_track - th->starting_track + 1; ntracks >= 0; ntracks--) { cte = &toc->entries[ntracks]; cte->addr_type = CD_LBA_FORMAT; if (cd->sc_link->quirks & ADEV_LITTLETOC) { #if BYTE_ORDER == BIG_ENDIAN swap16_multi((u_int16_t *)&cte->addr, sizeof(cte->addr) / 2); #endif } else cte->addr.lba = betoh32(cte->addr.lba); } if (cd->sc_link->quirks & ADEV_LITTLETOC) { th->len = letoh16(th->len); } else th->len = betoh16(th->len); len = min(len, th->len - (sizeof(th->starting_track) + sizeof(th->ending_track))); error = copyout(toc->entries, te->data, len); free(toc, M_TEMP); break; } case CDIOREADMSADDR: { struct cd_toc *toc; int sessno = *(int *)addr; struct cd_toc_entry *cte; if (sessno != 0) { error = EINVAL; break; } toc = malloc(sizeof(*toc), M_TEMP, M_WAITOK | M_ZERO); error = cd_read_toc(cd, 0, 0, toc, sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry), 0x40 /* control word for "get MS info" */); if (error) { free(toc, M_TEMP); break; } cte = &toc->entries[0]; if (cd->sc_link->quirks & ADEV_LITTLETOC) { #if BYTE_ORDER == BIG_ENDIAN swap16_multi((u_int16_t *)&cte->addr, sizeof(cte->addr) / 2); #endif } else cte->addr.lba = betoh32(cte->addr.lba); if (cd->sc_link->quirks & ADEV_LITTLETOC) toc->header.len = letoh16(toc->header.len); else toc->header.len = betoh16(toc->header.len); *(int *)addr = (toc->header.len >= 10 && cte->track > 1) ? cte->addr.lba : 0; free(toc, M_TEMP); break; } case CDIOCSETPATCH: { struct ioc_patch *arg = (struct ioc_patch *)addr; error = cd_setchan(cd, arg->patch[0], arg->patch[1], arg->patch[2], arg->patch[3], 0); break; } case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *)addr; error = cd_getvol(cd, arg, 0); break; } case CDIOCSETVOL: { struct ioc_vol *arg = (struct ioc_vol *)addr; error = cd_setvol(cd, arg, 0); break; } case CDIOCSETMONO: error = cd_setchan(cd, BOTH_CHANNEL, BOTH_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETSTEREO: error = cd_setchan(cd, LEFT_CHANNEL, RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETMUTE: error = cd_setchan(cd, MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETLEFT: error = cd_setchan(cd, LEFT_CHANNEL, LEFT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCSETRIGHT: error = cd_setchan(cd, RIGHT_CHANNEL, RIGHT_CHANNEL, MUTE_CHANNEL, MUTE_CHANNEL, 0); break; case CDIOCRESUME: error = cd_pause(cd, 1); break; case CDIOCPAUSE: error = cd_pause(cd, 0); break; case CDIOCSTART: error = scsi_start(cd->sc_link, SSS_START, 0); break; case CDIOCSTOP: error = scsi_start(cd->sc_link, SSS_STOP, 0); break; close_tray: case CDIOCCLOSE: error = scsi_start(cd->sc_link, SSS_START|SSS_LOEJ, SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE); break; case MTIOCTOP: if (((struct mtop *)addr)->mt_op == MTRETEN) goto close_tray; if (((struct mtop *)addr)->mt_op != MTOFFL) { error = EIO; break; } /* FALLTHROUGH */ case CDIOCEJECT: /* FALLTHROUGH */ case DIOCEJECT: cd->sc_link->flags |= SDEV_EJECTING; break; case CDIOCALLOW: error = scsi_prevent(cd->sc_link, PR_ALLOW, 0); break; case CDIOCPREVENT: error = scsi_prevent(cd->sc_link, PR_PREVENT, 0); break; case DIOCLOCK: error = scsi_prevent(cd->sc_link, (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0); break; case CDIOCSETDEBUG: cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2); break; case CDIOCCLRDEBUG: cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); break; case CDIOCRESET: case SCIOCRESET: error = cd_reset(cd); break; case CDIOCLOADUNLOAD: { struct ioc_load_unload *args = (struct ioc_load_unload *)addr; error = cd_load_unload(cd, args->options, args->slot); break; } case DVD_AUTH: error = dvd_auth(cd, (union dvd_authinfo *)addr); break; case DVD_READ_STRUCT: error = dvd_read_struct(cd, (union dvd_struct *)addr); break; default: if (DISKPART(dev) != RAW_PART) { error = ENOTTY; break; } error = scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p); break; } exit: device_unref(&cd->sc_dev); return (error); }
static GstStateChangeReturn cdplayer_change_state (GstElement * element, GstStateChange transition) { CDPlayer *cdp; GstState state = GST_STATE (element); GstState pending = GST_STATE_PENDING (element); g_return_val_if_fail (GST_IS_CDPLAYER (element), GST_STATE_CHANGE_FAILURE); cdp = CDPLAYER (element); switch (pending) { case GST_STATE_READY: if (state != GST_STATE_PAUSED) { if (cd_init (CDPLAYER_CD (cdp), cdp->device) == FALSE) { return GST_STATE_CHANGE_FAILURE; } cdp->num_tracks = cdp->cd.num_tracks; cdp->cddb_discid = cd_cddb_discid (CDPLAYER_CD (cdp)); } break; case GST_STATE_PAUSED: /* ready->paused is not useful */ if (state != GST_STATE_READY) { if (cd_pause (CDPLAYER_CD (cdp)) == FALSE) { return GST_STATE_CHANGE_FAILURE; } cdp->paused = TRUE; } break; case GST_STATE_PLAYING: if (cdp->paused == TRUE) { if (cd_resume (CDPLAYER_CD (cdp)) == FALSE) { return GST_STATE_CHANGE_FAILURE; } cdp->paused = FALSE; } else { if (cd_start (CDPLAYER_CD (cdp), cdp->start_track, cdp->end_track) == FALSE) { return GST_STATE_CHANGE_FAILURE; } } break; case GST_STATE_NULL: /* stop & close fd */ if (cd_stop (CDPLAYER_CD (cdp)) == FALSE || cd_close (CDPLAYER_CD (cdp)) == FALSE) { return GST_STATE_CHANGE_FAILURE; } break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) { GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); } return GST_STATE_CHANGE_SUCCESS; }
static GstStateChangeReturn gst_cdaudio_change_state (GstElement * element, GstStateChange transition) { GstCDAudio *cdaudio; GstStateChangeReturn ret; gint res; cdaudio = GST_CDAUDIO (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: if ((res = cd_init_device (cdaudio->device)) < 0) goto init_failed; cdaudio->cd_desc = res; /* close tray */ if ((res = cd_close (cdaudio->cd_desc)) < 0) goto close_failed; if ((res = cd_stat (cdaudio->cd_desc, &cdaudio->info)) < 0) { /* we just give a warning here */ GST_ELEMENT_WARNING (cdaudio, LIBRARY, INIT, ("Could not retrieve CD track info."), (NULL)); } else { debug_track_info (cdaudio); cdaudio->discid = cddb_discid (cdaudio->cd_desc); /* FIXME, post message with discid */ } cdaudio->was_playing = FALSE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { if (cdaudio->was_playing) res = cd_resume (cdaudio->cd_desc); else res = cd_play (cdaudio->cd_desc, 1); if (res < 0) goto play_failed; cdaudio->was_playing = TRUE; g_timer_start (cdaudio->timer); break; } default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: if ((res = cd_pause (cdaudio->cd_desc)) < 0) goto pause_failed; g_timer_stop (cdaudio->timer); break; case GST_STATE_CHANGE_PAUSED_TO_READY: if ((res = cd_stop (cdaudio->cd_desc)) < 0) goto stop_failed; if ((res = cd_finish (cdaudio->cd_desc)) < 0) goto finish_failed; cdaudio->cd_desc = -1; break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; /* ERRORS */ init_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not init CD device %s. (%d)", cdaudio->device, res), (NULL)); cdaudio->cd_desc = -1; return GST_STATE_CHANGE_FAILURE; } close_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not close CD tray for device %s. (%d)", cdaudio->device, res), (NULL)); return GST_STATE_CHANGE_FAILURE; } play_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not play CD device %s. (%d)", cdaudio->device, res), (NULL)); return GST_STATE_CHANGE_FAILURE; } pause_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not pause CD device %s. (%d)", cdaudio->device, res), (NULL)); return GST_STATE_CHANGE_FAILURE; } stop_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not stop CD device %s. (%d)", cdaudio->device, res), (NULL)); return GST_STATE_CHANGE_FAILURE; } finish_failed: { GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT, ("Could not finish CD device %s. (%d)", cdaudio->device, res), (NULL)); return GST_STATE_CHANGE_FAILURE; } }
void count() { FILE *title_fp = fopen(title_cdb, "r"); FILE *track_fp = fopen(tracks_file, "r"); if (NULL == title_fp || NULL == track_fp) { mvprintw(ERROR_LINE, OUTPUT_COL, "%s\n", "save_record(): fopen error"); refresh(); return; } refresh_screen(); int cur_print_line = MESSAGE_LINE; mvprintw(cur_print_line, OUTPUT_COL, "cat\tcd_name\ttracks"); refresh(); cur_print_line += 2; char buf[1024]; memset(buf, 0, sizeof(buf)); int tracks = 0; while (fgets(buf, sizeof(buf), title_fp)) { count_record(buf, tracks_file, &tracks); char *tmp_ptr = buf; char *tmp_ptr2 = buf; int string_len = 0; int separator_count = 0; char cat[MAX_STRING_LEN + 1]; memset(cat, 0, sizeof(cat)); char cd_name[MAX_STRING_LEN + 1]; memset(cd_name, 0, sizeof(cd_name)); memset(cat, 0, sizeof(cat)); memset(cd_name, 0, sizeof(cd_name)); while (*tmp_ptr != '\0') { if (*tmp_ptr == ',') { ++ separator_count; if (1 == separator_count) { strncpy(cat, tmp_ptr2, string_len); } if (2 == separator_count) { strncpy(cd_name, tmp_ptr2, string_len); break; } tmp_ptr2 = ++tmp_ptr; string_len = 0; continue; } ++ tmp_ptr; ++ string_len; } mvprintw(cur_print_line ++, OUTPUT_COL, "%s\t%s\t%d", cat, cd_name, tracks); } fclose(title_fp); fclose(track_fp); cd_pause(cur_print_line + 1); }
void find_cd() { mvprintw(PROMOTE_LINE, 0, "Enter a string to search for in CD titles: "); char buf[MAX_STRING_LEN + 1]; memset(buf, 0, sizeof(buf)); getstring(buf, sizeof(buf) - 1); FILE *fp = fopen(title_cdb, "r"); if (NULL == fp) { mvprintw(ERROR_LINE, OUTPUT_COL, "%s\n", "find_record(): fopen error"); refresh(); return; } int record_count = 0; char *record = count_record(buf, title_cdb, &record_count); if (record_count > 0 && record != NULL) { char *tmp_ptr = record; char *tmp_ptr2 = record; int string_len = 0; int separator_count = 0; while (*tmp_ptr != '\0') { if (*tmp_ptr == ',') { ++ separator_count; if (1 == separator_count) { strncpy(cur_cd_cat, tmp_ptr2, string_len); } if (2 == separator_count) { strncpy(cur_cd_name, tmp_ptr2, string_len); break; } tmp_ptr2 = ++tmp_ptr; string_len = 1; continue; } ++ tmp_ptr; ++ string_len; } } else { mvprintw(ERROR_LINE, 0, "Nothing found in database"); refresh(); cd_pause(ERROR_LINE + 2); } fclose(fp); }
int main() { char cmd[20]; int done = 0; int ret, trk, a, b; if (cd_init() < 0) { printf("Error initialising libcda (%s)\n", cd_error); return 1; } show_cmds(); do { printf(">>> "); fflush(stdout); scanf("%s", cmd); switch (cmd[0]) { case '?': show_cmds(); break; case 'p': trk = input_int("Track"); ret = cd_play(trk); if (ret != 0) printf("Error occurred (%s)\n", cd_error); break; case 'r': a = input_int("First track"); b = input_int("Last track"); ret = cd_play_range(a, b); if (ret != 0) printf("Error occurred (%s)\n", cd_error); break; case 'f': trk = input_int("Start track"); ret = cd_play_from(trk); if (ret != 0) printf("Error occurred (%s)\n", cd_error); break; case 'P': trk = cd_current_track(); if (trk) printf("Playing track %d\n", trk); else printf("Not playing\n"); break; case 'w': cd_pause(); break; case 'W': cd_resume(); break; case 'S': ret = cd_is_paused(); if (ret) printf("Paused\n"); else printf("Not paused\n"); break; case 's': cd_stop(); break; case 'i': ret = cd_get_tracks(&a, &b); if (ret != 0) printf("Error occurred (%s)\n", cd_error); else printf("First track: %d\nLast track: %d\n", a, b); break; case 'a': trk = input_int("Track"); ret = cd_is_audio(trk); if (ret < 0) printf("Error occurred (%s)\n", cd_error); else printf("Track %d is %s\n", trk, (ret ? "audio" : "data")); break; case 'v': a = input_int("Left (0-255)"); b = input_int("Right (0-255)"); cd_set_volume(a, b); break; case 'V': cd_get_volume(&a, &b); printf("Left volume: %d\nRight volume: %d\n", a, b); break; case 'e': cd_eject(); break; case 'c': cd_close(); break; case 'q': done = 1; break; default: printf("Unrecognised command: `%c'\n", cmd[0]); } } while (!done); cd_exit(); return 0; }