Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

cdaudio_linux.cpp

Go to the documentation of this file.
00001 
00002 #include "Core/precomp.h"
00003 
00004 #include <API/Core/System/error.h>
00005 #include <API/Core/System/cl_assert.h>
00006 #include <fcntl.h>
00007 #include <mntent.h>
00008 #include <unistd.h>
00009 #include <errno.h>
00010 
00011 #include <sys/types.h>
00012 #include <sys/stat.h>
00013 #include <sys/ioctl.h>
00014 
00015 #include <strstream>
00016 
00017 #include <linux/cdrom.h>
00018 
00019 #include "cdaudio_linux.h"
00020 
00021 void CL_CDDrive_Linux::init_cdaudio()
00022 {
00023         // Make sure init only happen once:
00024 
00025         static bool already_inited = false;
00026         if (already_inited) return;
00027         already_inited = true;
00028         
00029         // Locate all CDROM drives available on the system.
00030         
00031         // We start by looking the mounttab:
00032         
00033         FILE *mount_file = setmntent("/etc/fstab", "r");
00034         if (mount_file != NULL)
00035         {
00036                 bool found_in_mount_file = false;
00037                 while (true)
00038                 {
00039                         mntent *entry = getmntent(mount_file);
00040                         if (entry == NULL) break; // no more entries.
00041                         
00042                         if (strcmp(entry->mnt_type, "iso9660") == 0)
00043                         {
00044                                 try
00045                                 {
00046                                         CL_CDAudio::cd_drives.push_back(
00047                                                 new CL_CDDrive_Linux(entry->mnt_fsname));
00048                                         
00049                                         found_in_mount_file = true;
00050                                 }
00051                                 catch (CL_Error err)
00052                                 {
00053                                         // Damn.
00054                                         cl_info(info_sound, err.message.c_str());
00055                                 }
00056                         }
00057                 }
00058 
00059                 endmntent(mount_file);
00060                 if (found_in_mount_file) return; // success! :)
00061         }
00062         
00063         // Ok. None there - assume he linked it from /dev/cdrom.
00064         
00065         try
00066         {
00067                 CL_CDAudio::cd_drives.push_back(new CL_CDDrive_Linux("/dev/cdrom"));
00068         }
00069         catch (CL_Error)
00070         {
00071                 std::cout << "Now CDROM drives found." << std::endl;
00072                 std::cout << "Either symlink it from /dev/cdrom, or add it to /etc/fstab." << std::endl;
00073         }
00074 }
00075 
00076 /**************************************************************/
00077 
00078 CL_CDDrive_Linux::CL_CDDrive_Linux(const char *filename)
00079 {
00080         this->filename = filename;
00081         
00082         // Is this really a cdrom drive??
00083         
00084         struct stat status;
00085         int err = stat(filename, &status);
00086         if (err <= -1)
00087         {
00088                 // File doesn't exist! (or something else failed.)
00089                 strstream err;
00090                 err << "Device " << filename << " not found!" << '\0';
00091                 throw CL_Error(err.str());
00092         }
00093         
00094         if (!S_ISCHR(status.st_mode) && !S_ISBLK(status.st_mode))
00095         {
00096                 strstream err;
00097                 err << "Device " << filename << " is not a block device!" << '\0';
00098                 throw CL_Error(err.str());
00099         }
00100         
00101         file_handle = open(filename,O_RDONLY|O_NONBLOCK);
00102         if (file_handle <= 0)
00103         {
00104                 strstream err;
00105                 err << "Device " << filename << " could not be opened!" << '\0';
00106                 throw CL_Error(err.str());
00107         }
00108         
00109         cdrom_subchnl info;
00110         if (ioctl(file_handle, CDROMSUBCHNL, &info) == 0 ||
00111                 /* is the disk not present?: */
00112                 errno == EIO || 
00113                 errno == ENOENT ||
00114                 errno == EINVAL)
00115         {
00116                 // Hurray. Found a cdrom drive.
00117                 cl_info_debug(info_sound, "HURRAY! We found a cdrom drive.");
00118         }
00119         else
00120         {
00121                 close(file_handle);
00122         
00123                 strstream err;
00124                 err << "Device " << filename << " is not a cdrom device!" << '\0';
00125                 throw CL_Error(err.str());
00126                 file_handle = -1;
00127         }
00128         close(file_handle);
00129         file_handle = -1;
00130 }
00131 
00132 CL_CDDrive_Linux::~CL_CDDrive_Linux()
00133 {
00134         if (file_handle != -1) close(file_handle);
00135 }
00136 
00137 bool CL_CDDrive_Linux::init()
00138 {
00139         file_handle = open(filename.c_str(),O_RDONLY|O_NONBLOCK);
00140         if (file_handle < 0)
00141         {
00142                 file_handle = -1;
00143                 return false;
00144         }
00145         
00146     if(!readtoc())
00147     {
00148                 close(file_handle);
00149         
00150                 strstream err;
00151                 err << "TOC Read error on Device " << filename << '\0';
00152                 throw CL_Error(err.str());
00153                 file_handle = -1;
00154     }
00155         return true;
00156 }
00157 
00158 std::string CL_CDDrive_Linux::get_drive_path()
00159 {
00160         return filename;
00161 }
00162 
00163 std::string CL_CDDrive_Linux::get_cd_name()
00164 {
00165         return std::string("UnKnown");
00166 }
00167 
00168 int CL_CDDrive_Linux::get_num_tracks()
00169 {
00170         return num_tracks;
00171 }
00172 
00173 bool CL_CDDrive_Linux::is_playing()
00174 {
00175     struct cdrom_subchnl sub_channel;
00176 
00177     sub_channel.cdsc_format = CDROM_LBA;
00178     
00179     if(!ioctl(file_handle,CDROMSUBCHNL,&sub_channel))
00180     {
00181         if(sub_channel.cdsc_audiostatus == CDROM_AUDIO_PLAY)
00182             {
00183             return true;
00184             }
00185             else
00186             {
00187                 return false;
00188                 }
00189         }
00190         else
00191         {
00192             return false;
00193         }
00194 }
00195 
00196 int CL_CDDrive_Linux::get_cur_track()
00197 {
00198     struct cdrom_subchnl sub_channel;
00199 
00200     sub_channel.cdsc_format=CDROM_LBA;
00201     ioctl(file_handle,CDROMSUBCHNL,&sub_channel);
00202     return sub_channel.cdsc_trk;
00203 }
00204 
00205 int CL_CDDrive_Linux::get_cur_frame()
00206 {
00207     struct cdrom_subchnl sub_channel;
00208 
00209     sub_channel.cdsc_format=CDROM_LBA;
00210     ioctl(file_handle,CDROMSUBCHNL,&sub_channel);
00211     return sub_channel.cdsc_reladdr.lba;
00212 }
00213 
00214 bool CL_CDDrive_Linux::play_tracks(int track, int end_track)
00215 {
00216     if((track < first_track) || (track > last_track))
00217         return false;
00218         if((end_track < track) || (end_track > last_track))
00219             return false;
00220             
00221     struct cdrom_msf msf;
00222     msf.cdmsf_min0 = tracks[track-1].start_lba/CD_FRAMES/CD_SECS;
00223     msf.cdmsf_sec0 = (tracks[track-1].start_lba/CD_FRAMES%CD_SECS)+2;
00224     msf.cdmsf_frame0 = tracks[track-1].start_lba%CD_FRAMES;
00225     
00226     msf.cdmsf_min1 = (tracks[end_track-1].start_lba+tracks[end_track-1].track_length)/CD_FRAMES/CD_SECS;
00227     msf.cdmsf_sec1 = ((tracks[end_track-1].start_lba+tracks[end_track-1].track_length)/CD_FRAMES%CD_SECS)+2;
00228     msf.cdmsf_frame1 = (tracks[end_track-1].start_lba+tracks[end_track-1].track_length)%CD_FRAMES;
00229         
00230         if(ioctl(file_handle,CDROMPLAYMSF,&msf))
00231         {
00232                 strstream err;
00233                 err << "Could not play track " << track << '\0';
00234                 
00235                 cl_info(info_sound, err.str());
00236                 return false;
00237         }
00238             
00239         return true;
00240 }
00241 
00242 bool CL_CDDrive_Linux::play_frames(int frame, int end_frame)
00243 {
00244     struct cdrom_msf msf;
00245     
00246     msf.cdmsf_min0 = frame/CD_FRAMES/CD_SECS;
00247     msf.cdmsf_sec0 = (frame/CD_FRAMES%CD_SECS)+2;
00248     msf.cdmsf_frame0 = frame%CD_FRAMES;
00249     
00250     msf.cdmsf_min1 = end_frame/CD_FRAMES/CD_SECS;
00251     msf.cdmsf_sec1 = (end_frame/CD_FRAMES%CD_SECS)+2;
00252     msf.cdmsf_frame1 = end_frame%CD_FRAMES;
00253         
00254         if(ioctl(file_handle,CDROMPLAYMSF,&msf))
00255         {
00256                 strstream err;
00257 
00258                 err << "Could not play from frame " << frame << " to frame " << end_frame << '\0';
00259                 
00260                 cl_info(info_sound, err.str());
00261         return false;
00262         }
00263         return true;
00264 }
00265 
00266 bool CL_CDDrive_Linux::play_track(int track)
00267 {
00268     if((track< first_track)||(track > last_track))
00269         return false;
00270         
00271     struct cdrom_msf msf;
00272     msf.cdmsf_min0 = tracks[track-1].start_lba/CD_FRAMES/CD_SECS;
00273     msf.cdmsf_sec0 = (tracks[track-1].start_lba/CD_FRAMES%CD_SECS)+2;
00274     msf.cdmsf_frame0 = tracks[track-1].start_lba%CD_FRAMES;
00275     
00276     msf.cdmsf_min1 = (tracks[track-1].start_lba+tracks[track-1].track_length)/CD_FRAMES/CD_SECS;
00277     msf.cdmsf_sec1 = ((tracks[track-1].start_lba+tracks[track-1].track_length)/CD_FRAMES%CD_SECS)+2;
00278     msf.cdmsf_frame1 = (tracks[track-1].start_lba+tracks[track-1].track_length)%CD_FRAMES;
00279         
00280         if(ioctl(file_handle,CDROMPLAYMSF,&msf))
00281         {
00282                 strstream err;
00283                 err << "Could not play track " << track << '\0';
00284                 
00285                 cl_info(info_sound, err.str());
00286                 return false;
00287         }
00288         return true;
00289 }
00290 
00291 void CL_CDDrive_Linux::stop()
00292 {
00293     ioctl(file_handle,CDROMSTOP);
00294 }
00295 
00296 void CL_CDDrive_Linux::pause()
00297 {
00298     ioctl(file_handle,CDROMPAUSE);
00299 }
00300 
00301 void CL_CDDrive_Linux::resume()
00302 {
00303     ioctl(file_handle,CDROMRESUME);
00304 }
00305 
00306 bool CL_CDDrive_Linux::readtoc()
00307 {
00308     struct cdrom_tochdr tochdr;
00309     // Read the TOC header
00310     if(ioctl(file_handle, CDROMREADTOCHDR, &tochdr))
00311     {
00312                 close(file_handle);
00313                 
00314                 strstream err;
00315                 err << "Could not read table of contents in Device " << filename << '\0';
00316                 throw CL_Error(err.str());
00317                 file_handle = -1;
00318     }
00319     
00320     // get the first and last tracks
00321     first_track = tochdr.cdth_trk0;
00322     last_track = tochdr.cdth_trk1;
00323     
00324     num_tracks = last_track - first_track +1;
00325 
00326     struct cdrom_tocentry cur_track_info;
00327     struct cdrom_tocentry next_track_info;
00328         
00329         // read TOC for first track
00330         if(!readtocentry(first_track,&cur_track_info))
00331             return false;
00332         
00333     // read the TOC Entry for each track
00334     for(int i = first_track+1;i<=last_track+1;i++)
00335     {
00336         STrack track;
00337         
00338             // read for next track
00339             if(!readtocentry(i,&next_track_info))
00340                 return false;
00341             
00342             track.start_lba = cur_track_info.cdte_addr.lba;
00343             track.track_length = next_track_info.cdte_addr.lba - cur_track_info.cdte_addr.lba;
00344             track.is_audio = true;
00345             if(cur_track_info.cdte_ctrl == CDROM_DATA_TRACK)
00346                 track.is_audio = false;
00347                 
00348                 tracks.push_back(track);
00349                 cur_track_info.cdte_addr.lba = next_track_info.cdte_addr.lba;
00350                 cur_track_info.cdte_ctrl     = next_track_info.cdte_ctrl;
00351     }
00352     return true;
00353 }
00354 
00355 
00356 bool CL_CDDrive_Linux::readtocentry(int track_no, struct cdrom_tocentry* track_info)
00357 {
00358     track_info->cdte_track = track_no;
00359     
00360     // check for leadout
00361     if (track_no==last_track+1)
00362             track_info->cdte_track = CDROM_LEADOUT;
00363     
00364     // We want the LBA format so that we can switch our play format
00365     track_info->cdte_format = CDROM_LBA;
00366     
00367     if(ioctl(file_handle, CDROMREADTOCENTRY, track_info))
00368     {
00369             strstream err;
00370             err << "Could not read table of contents in Device " << filename << '\0';
00371             cl_info(info_sound,err.str());
00372         return false;
00373     }
00374     
00375     return true;
00376 } 
00377 

Generated at Wed Apr 4 19:53:59 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001