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
00024
00025 static bool already_inited = false;
00026 if (already_inited) return;
00027 already_inited = true;
00028
00029
00030
00031
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;
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
00054 cl_info(info_sound, err.message.c_str());
00055 }
00056 }
00057 }
00058
00059 endmntent(mount_file);
00060 if (found_in_mount_file) return;
00061 }
00062
00063
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
00083
00084 struct stat status;
00085 int err = stat(filename, &status);
00086 if (err <= -1)
00087 {
00088
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
00112 errno == EIO ||
00113 errno == ENOENT ||
00114 errno == EINVAL)
00115 {
00116
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
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
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
00330 if(!readtocentry(first_track,&cur_track_info))
00331 return false;
00332
00333
00334 for(int i = first_track+1;i<=last_track+1;i++)
00335 {
00336 STrack track;
00337
00338
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
00361 if (track_no==last_track+1)
00362 track_info->cdte_track = CDROM_LEADOUT;
00363
00364
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