<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>CDDB server access library (libcddb)</title> <link href="libcddb.css" rel="stylesheet" type="text/css"> </head> <body> <table class="menu"> <tbody> <tr class="menu"> <td class="menu"><a class="menu" href="index.html">Libcddb home</a></td> <td class="menu"><a class="menu" href="download.html">Download</a></td> <td class="menu"><a class="menu" href="faq.html">FAQ</a></td> <td class="menu"><a class="menu" href="tutorial.html">Tutorial</a></td> <td class="menu"><a class="menu" href="API/index.html">API Documentation</a></td> <td class="menu"><a class="menu" href="links.html">Links</a></td> <td class="menu"><a class="menu" href="contact.html">Contact Info</a></td> </tr> </tbody> </table> <table class="section1"><tr><td><a name="section1">1 Introduction</a></td><td class="sectionnav"><a href="#section2"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section0"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> This tutorial describes the steps that you, as a developer, have to take when using libcddb. It starts with the creation and configuration of the CDDB connection. Afterwards it explains how you can retrieve data from the server and even submit new entries. Finally, it shows you what to do if you do not need the connection or any related in-memory structures anymore. </p> <p> Throughout this page there are a lot of direct links to the libcddb API reference. In the tutorial text they are easily located because of their different color. But similar links are also present in the example source code. Every libcddb function, structure and definition in those code snippets will link directly to the corresponding API page. </p> <p> If you have any questions or remarks about this tutorial, if something is not completely clear, if you find any errors or broken links, do not hesitate to contact me so I can clarify and/or correct the issue. My coordinates can be found on <a href="contact.html">Contact Info</a> page. </p> <table class="section1"><tr><td><a name="section2">2 Coding suggestions</a></td><td class="sectionnav"><a href="#section3"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section1"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> No, I'm not going to bother you with where you place your braces and stuff like that. That's not my problem. :-) But what I would like to suggest is that whenever you have to retrieve something from a libcddb data structure or when you have to change something in such a structure, that you use the provided get and set functions for that field. This is good OO practice and it will make your life easier if and when I decide to change the implementation of one of those structures. If you want to access something for which there is no getter and or setter, then just report it to me and I'll add it. </p> <p> Another thing I would like to mention is that you only have to include one header file to use libcddb. The other header files depend on each other and have to be included in the correct order for it to work. So, the following statement is enough: </p> <pre class="example"><code>#include <cddb/cddb.h> </code></pre> <table class="section1"><tr><td><a name="section3">3 Working with tracks and discs</a></td><td class="sectionnav"><a href="#section4"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section2"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> Before we start with the sections that explain how you can access a CDDB server, we have to explain two important libcddb data structures: the track and the disc. These structures are used as parameters and return values in the functions that access the server. The following two section describe how you can create, use and destroy these tracks and discs. </p> <table class="section2"><tr><td><a name="section3.1">3.1 Tracks</a></td><td class="sectionnav"><a href="#section3.2"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section3.0"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p class="noindent"> Creation and destruction of a track can be done as shown below. </p> <pre class="example"><code><a href="API/cddb__track_8h.html#1f656d30547194e5a6d9b75406f6b515">cddb_track_t</a> *track = NULL; /*<i> create </i>*/ track = <a href="API/cddb__track_8h.html#1ff23780b5f261609d253d5f382a9dbe">cddb_track_new</a>(); if (track == NULL) { fprintf(stderr, "out of memory, unable to create track"); } /*<i> ... use ... </i>*/ /*<i> destroy </i>*/ <a href="API/cddb__track_8h.html#2e2a6b9d7dede4137355181716e372d5">cddb_track_destroy</a>(track); </code></pre> <p> Next to the two functions used in this example, there is another way to create a new track structure. An existing track can be duplicated with <a href="API/cddb__track_8h.html#4f5e232db8905a37e8e21e86d07a3a8b">cddb_track_clone</a>. This function will make an exact copy of the existing track, reserving new blocks of memory along the way. It is used internally by libcddb but can also be useful for developers in need of a duplicate of a certain track. </p> <p> A similar function is <a href="API/cddb__track_8h.html#1918ba8826aed51573b9187821c668a1">cddb_track_copy</a>. It requires two existing track structures and will copy data from one to the other. Note that a field that is not present in the source track will not cause a reset of the corresponding field in the destination track. </p> <p> All the other track functions are getters and setters for the data fields of the track. In this section a description of those fields is given. Examples of how to use these will be shown in code snippets throughout the next sections. </p> <ul> <li> <b>Number:</b> The number of the track on the disc. There is only a getter for this field (<a href="API/cddb__track_8h.html#c56671ac6022cccbb71724cb5116f169">cddb_track_get_number</a>). It gets set implicitly when you add the track to a disc structure. </li> <li> <b>Frame offset:</b> The frame offset of the track on the disc. This is one of the fields that is used to calculate the CDDB disc ID. Both a getter and setter function are available (<a href="API/cddb__track_8h.html#ca213caee5c7075ee077c89bea7cbdd2">cddb_track_get_frame_offset</a>, <a href="API/cddb__track_8h.html#1db69a3085ebf75430ccc3f4cca7025c">cddb_track_set_frame_offset</a>). </li> <li> <b>Length:</b> The length of the track in seconds. You can manually set this field (<a href="API/cddb__track_8h.html#f3d9820f75e10322bf1847316fcb3e98">cddb_track_set_length</a>). Libcddb can also calculate it for you (<a href="API/cddb__track_8h.html#ec922bbc2dc375c2c272db133f13e16e">cddb_track_get_length</a>) if certain requirements are met: the track has to be part of a disc, all tracks on the disc need to have their frame offsets defined and the disc length has to be known. If one of these missing, the length can not be calculated and -1 will be returned. </li> <li> <b>Title:</b> The title of the track. Besides the usual get and set functions (<a href="API/cddb__track_8h.html#c0fd2e634bd2594e1dbed53d44b01355">cddb_track_get_title</a>, <a href="API/cddb__track_8h.html#105143caf0f925d39a8672279270fdcf">cddb_track_set_title</a>) there is also a function to append a string to an already existing title (<a href="API/cddb__track_8h.html#7c12cbe3ba0c2cba52b503d85bedec98">cddb_track_append_title</a>). This function is used internally by libcddb, and I do not directly see any use for it by libcddb users, but you never known. </li> <li> <b>Artist name:</b> The artist performing the song on this track. You should not set this field if the track is part of a disc and all songs on the disc are performed by the same artist. In other words, this field is only useful for compilation CDs. There is a getter, setter and append function for this field (<a href="API/cddb__track_8h.html#06ef335da307c849d57eead1bb059391">cddb_track_get_artist</a>, <a href="API/cddb__track_8h.html#78764d0cf156ecaa5e907067e424494e">cddb_track_set_artist</a>, <a href="API/cddb__track_8h.html#a8df7b050e2d76dfc7185430de5dee51">cddb_track_append_artist</a>). If the artist name is not set, the get function will return the disc artist if the track is part of a disc. </li> <li> <b>Extra data:</b> This field contains any extra data pertaining to the track (e.g. composer, lyrics, ...). As with the title and the artist name, you have a getter, setter and append function (<a href="API/cddb__track_8h.html#a09b734d43c50759a707e0d563f88c3d">cddb_track_get_ext_data</a>, <a href="API/cddb__track_8h.html#9dfe7e399216d6cbdc8ef44336878ce4">cddb_track_set_ext_data</a>, <a href="API/cddb__track_8h.html#3e6ff99c770637568911b4a1050f19c5">cddb_track_append_ext_data</a>). </li> </ul> <p> You might wonder how you could retrieve or calculate the frame offsets for the tracks of a CD you possess. I already tried two solutions myself. The first one is to use the command-line tool <a href="http://www.xiph.org/paranoia">cdparanoia</a>. The example below shows how you can query a CD in your CD-ROM drive. </p> <pre class="example"><code>$ cdparanoia -Q cdparanoia III release 9.8 (March 23, 2001) (C) 2001 Monty <monty@xiph.org> and Xiphophorus Report bugs to paranoia@xiph.org http://www.xiph.org/paranoia/ Table of contents (audio tracks only): track length begin copy pre ch =========================================================== 1. 2334 [00:31.09] 0 [00:00.00] OK no 2 2. 19054 [04:14.04] 2334 [00:31.09] OK no 2 ... 15. 16432 [03:39.07] 250987 [55:46.37] OK no 2 16. 15924 [03:32.24] 267419 [59:25.44] OK no 2 TOTAL 283343 [62:57.68] (audio only) </code></pre> <p> From the <code>begin</code> column you can derive the frame offset of the tracks. The only thing you have to do with these values is add two seconds of lead-in. You can use the libcddb <a href="API/cddb__disc_8h.html#b1094dade3bf6305a0961885a9a89f0f">SECONDS_TO_FRAMES</a> macro to convert these two seconds to a frame count. This first solution is useful when you quickly want to try out some stuff. </p> <p> The second solution is to use libcdio, a library for accessing and controlling a CD-ROM device (see <a href="links.html">links</a> page for coordinates). The example program supplied with libcddb uses this library, if installed, to access the CD-ROM. The following code snippet shows how to retrieve the frame offset with this library. For the complete code check out the <code>cd_access.c</code> file in the libcddb <code>examples</code> directory. </p> <pre class="example"><code>CdIo_t *cdio = (NULL, DRIVER_DEVICE);/*<i> libcdio CD access structure </i>*/ track_t t; /*<i> libcdio track number </i>*/ lba_t lba; /*<i> libcdio Logical Block Address </i>*/ int frame_offset; /*<i> libcddb frame offset </i>*/ t = ... /*<i> initialize track t </i>*/ lba = cdio_get_track_lba(cdio, t); if (lba == CDIO_INVALID_LBA) { libcdio_error_exit("track %d has invalid Logical Block Address", t); } </code></pre> <p> The use of this library is probably more elegant than the use of an external program. Especially if you are working on some code that is also going to be used by other people. </p> <p> Note: the <code>libcdio_error_exit</code> function is not part of the libcdio library, but a macro defined in the example code. </p> <table class="section2"><tr><td><a name="section3.2">3.2 Discs</a></td><td class="sectionnav"><a href="#section3.3"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section3.1"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> The life time of a disc is started and ended with similar functions as that of a track (see example below). </p> <pre class="example"><code><a href="API/cddb__disc_8h.html#42efa38614123ddc2bcc8a889443ceda">cddb_disc_t</a> *disc = NULL; /*<i> create </i>*/ disc = <a href="API/cddb__disc_8h.html#d3f011e11da576beb06fc0873aa769bc">cddb_disc_new</a>(); if (disc == NULL) { fprintf(stderr, "out of memory, unable to create disc"); } /*<i> ... use ... </i>*/ /*<i> destroy </i>*/ <a href="API/cddb__disc_8h.html#9bf985f08f176b23dffdee7af8440b21">cddb_disc_destroy</a>(disc); </code></pre> <p> As with tracks, it is also possible to duplicate or copy a disc using either <a href="API/cddb__disc_8h.html#f2d40d56a702f692fb6c359d0af83277">cddb_disc_clone</a> or <a href="API/cddb__disc_8h.html#dbd8b7d0ecf569edf10af5e304a86f3d">cddb_disc_copy</a>. The clone function will make a brand new copy of the disc and all of its tracks. The copy function will copy data from the source disc to the destination disc. Existing data fields and tracks will be overwritten with the new data and tracks. If the source disc has more tracks than the destination disc, then new tracks will be added. </p> <p> </p> <ul> <li> <b>CDDB ID:</b> The CDDB disc ID. Together with the disc category explained below, this field uniquely identifies a disc in the CDDB database. This field is calculated using the length of the disc and the frame offsets of the individual tracks. You can get and set this field (<a href="API/cddb__disc_8h.html#6a2d71c68dfd943575d43094eb96a43b">cddb_disc_get_discid</a>, <a href="API/cddb__disc_8h.html#5c30ddb662dbfc62cc0992aa6898b794">cddb_disc_set_discid</a>). If you do not know the disc ID but the disc length and track offsets are initialized, you can have libcddb calculate it for you (<a href="API/cddb__disc_8h.html#b2fa8d342aceba66a116c24dda7a7d61">cddb_disc_calc_discid</a>). </li> <li> <b>CDDB category:</b> The CDDB disc category. The CDDB specification defines a set of eleven possible disc categories: <i>data</i>, <i>folk</i>, <i>jazz</i>, <i>misc</i>, <i>rock</i>, <i>country</i>, <i>blues</i>, <i>newage</i>, <i>reggae</i>, <i>classical</i> and <i>soundtrack</i>. Next to the standard get and set functions that use one of the values defined by the <a href="API/cddb__disc_8h.html#ea1998e6495d2f0dfa3b6e45b4fcd50d">cddb_cat_t</a> enumeration (<a href="API/cddb__disc_8h.html#6456f3f885f08a54efd1382ccd0408f4">cddb_disc_get_category</a>, <a href="API/cddb__disc_8h.html#fb23b487f2168c0fa75ebf8b7d641b38">cddb_disc_set_category</a>), there are two alternative functions that use and return strings (<a href="API/cddb__disc_8h.html#b7aa4e8f6be9849f434db3d62bceb5cb">cddb_disc_get_category_str</a>, <a href="API/cddb__disc_8h.html#a2af35dfbffa7c8a91c9a5fc36671264">cddb_disc_set_category_str</a>). </li> <li> <b>Music genre:</b> The musical genre of the disc. As opposed to the categories from above, this can be any string (<a href="API/cddb__disc_8h.html#091f945e67254eb4fc07082c0fb4c484">cddb_disc_get_genre</a>, <a href="API/cddb__disc_8h.html#35e3e624c4d55d16faf0f7563d965f1f">cddb_disc_set_genre</a>). </li> <li> <b>Length:</b> The disc length in seconds (<a href="API/cddb__disc_8h.html#22b7b572663a4ebc3aa605c25601b74b">cddb_disc_get_length</a>, <a href="API/cddb__disc_8h.html#403ea0c84c8075fefa6adfaad8184c8c">cddb_disc_set_length</a>). </li> <li> <b>Year:</b> The year of the disc's release (<a href="API/cddb__disc_8h.html#93babf05aaf15b2d933163d8b737586f">cddb_disc_get_year</a>, <a href="API/cddb__disc_8h.html#160b7bade529a2c286f51e57e37e9aae">cddb_disc_set_year</a>). </li> <li> <b>Title:</b> The title of the disc. As with tracks, for the disc title there is also a get, set and append function (<a href="API/cddb__disc_8h.html#9d48a38c091fe03197e9fe49b0085b72">cddb_disc_get_title</a>, <a href="API/cddb__disc_8h.html#b0c2032a4f21ad0e61c30583cc1bb941">cddb_disc_set_title</a>, <a href="API/cddb__disc_8h.html#0e8654c2dd88aa7df9973553d728c805">cddb_disc_append_title</a>). </li> <li> <b>Artist name:</b> The artist performing the tracks on this disc. If this is a compilation disc with different performers for different tracks, set it to "Various" and use the artist name field of the individual tracks. Functions are available to get, set and append (<a href="API/cddb__disc_8h.html#9f966d8c5085d0673257a8b05e31e1af">cddb_disc_get_artist</a>, <a href="API/cddb__disc_8h.html#f565e51732e48511ce5eb50d4849f09e">cddb_disc_set_artist</a>, <a href="API/cddb__disc_8h.html#37ba4c6c3aa25702e5523dba68169326">cddb_disc_append_artist</a>). </li> <li> <b>Extra data:</b> This field contains any extra data pertaining to the disc (e.g. composer, producer, ...). As with the title and the artist name, you have a getter, setter and append function (<a href="API/cddb__disc_8h.html#78c6056e55bb22274d6867b7b2db09d7">cddb_disc_get_ext_data</a>, <a href="API/cddb__disc_8h.html#ad940b347f5ef58cec2da0fd105ab0b6">cddb_disc_set_ext_data</a>, <a href="API/cddb__disc_8h.html#3f1ec775985eb470dcbe6b07221c4ce0">cddb_disc_append_ext_data</a>). </li> </ul> <table class="section2"><tr><td><a name="section3.3">3.3 Tracks on discs</a></td><td class="sectionnav"><a href="#section3.4"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section3.2"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> Now that you have seen tracks and discs, let's combine them and put some tracks in a disc structure. With the current API it is only possible to append a new track to the end of an existing track list. On the other hand, there are two methods to iterate over the tracks on a disc. The following example illustrates this. </p> <pre class="example"><code><a href="API/cddb__disc_8h.html#42efa38614123ddc2bcc8a889443ceda">cddb_disc_t</a> *disc; <a href="API/cddb__track_8h.html#1f656d30547194e5a6d9b75406f6b515">cddb_track_t</a> *track, *track1, *track2, *track3; int i, cnt; /*<i> ... initialize disc and tracks ... </i>*/ /*<i> add some tracks </i>*/ <a href="API/cddb__disc_8h.html#efcd9b6f9709284955af3f02598ba339">cddb_disc_add_track</a>(disc, track1); <a href="API/cddb__disc_8h.html#efcd9b6f9709284955af3f02598ba339">cddb_disc_add_track</a>(disc, track2); <a href="API/cddb__disc_8h.html#efcd9b6f9709284955af3f02598ba339">cddb_disc_add_track</a>(disc, track3); /*<i> iteration method 1 </i>*/ cnt = <a href="API/cddb__disc_8h.html#53b3f46734570bd853ae9b1689c8529d">cddb_disc_get_track_count</a>(disc); for (t = 0; t < cnt; t++) { track = <a href="API/cddb__disc_8h.html#af9a585d49e308b061a06119f4466f93">cddb_disc_get_track</a>(disc, t); if (track != NULL) { /*<i> ... use track ... </i>*/ } } /*<i> iteration method 2 </i>*/ track = <a href="API/cddb__disc_8h.html#d77ce7b226c41f297af9270a97a0c5e1">cddb_disc_get_track_first</a>(disc); while (track != NULL) { /*<i> ... use track ... </i>*/ track = <a href="API/cddb__disc_8h.html#64792c14e85b0d5419c1d2ed5596843f">cddb_disc_get_track_next</a>(disc); } </code></pre> <p> When using the first iteration method you should know that the <a href="API/cddb__disc_8h.html#af9a585d49e308b061a06119f4466f93">cddb_disc_get_track</a> function starts counting at zero. Also note that the track number, that you get when calling <a href="API/cddb__track_8h.html#c56671ac6022cccbb71724cb5116f169">cddb_track_get_number</a>, starts at one. The <a href="API/cddb__disc_8h.html#af9a585d49e308b061a06119f4466f93">cddb_disc_get_track</a> function is probably more useful when you already know the number of the track that you want to retrieve. It will return the actual track if the number is valid, or NULL when it is not. </p> <p> For the second method we first reset the internal iteration pointer with <a href="API/cddb__disc_8h.html#d77ce7b226c41f297af9270a97a0c5e1">cddb_disc_get_track_first</a>. The function also returns the first track. Any subsequent tracks can be retrieved with the <a href="API/cddb__disc_8h.html#64792c14e85b0d5419c1d2ed5596843f">cddb_disc_get_track_next</a> function. This function returns the next track in the list or NULL if there are no more tracks left. </p> <table class="section1"><tr><td><a name="section4">4 Connection set up</a></td><td class="sectionnav"><a href="#section5"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section3"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> The first thing to do when you want to start using any of the libcddb functionality is to create a connection structure. </p> <pre class="example"><code><a href="API/cddb__conn_8h.html#56aabb81a12e2653f737f1fde87285d9">cddb_conn_t</a> *conn = NULL; conn = <a href="API/cddb__conn_8h.html#207796cf79ed9a83a772cde49f7579e4">cddb_new</a>(); if (conn == NULL) { fprintf(stderr, "out of memory, " "unable to create connection structure"); } </code></pre> <p> The <a href="API/cddb__conn_8h.html#207796cf79ed9a83a772cde49f7579e4">cddb_new</a> function will return a new <a href="API/cddb__conn_8h.html#56aabb81a12e2653f737f1fde87285d9">cddb_conn_t</a> structure. This structure keeps the state of the current connection and will have to be passed to most of the other libcddb functions. If something goes wrong during the creation of this structure, NULL will be returned to signal that error. </p> <p> The structure that is returned will have a set of default connection settings. If you use this connection without changing any of these settings: </p> <ul> <li> it will connect to the CDDB server at <a href="http://freedb.org">freedb.org</a> using the CDDBP protocol; </li> <li> caching will be enabled, writing any data that is retrieved to a subdirectory of the user's home directory (<code>$HOME/.cddbslave</code>); </li> <li> and finally, the user and host names used when connecting to a server are 'anonymous' and 'localhost'. </li> </ul> <p> These default values can be changed after you have created the structure. The following sections explain how to do this. </p> <table class="section2"><tr><td><a name="section4.1">4.1 Server settings</a></td><td class="sectionnav"><a href="#section4.2"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section4.0"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> The first thing to do when you want to change the server settings, is decide how you want to contact the server. The list below describes the three options. </p> <ul> <li> <b>CDDBP (default):</b> This is the default setting. It uses a custom protocol to interact with the server. It has the advantage that a single TCP connection can be used to send multiple commands. There is of course the disadvantage that this protocol might not work if the user is behind a firewall. </li> <li> <b>HTTP:</b> It is possible to tunnel the CDDB commands in ordinary HTTP traffic. This method has the disadvantage that there is more overhead since a new TCP session has to be established for every command and there is extra data to be parsed (HTTP responses). But the advantage is that it will most likely work from behind a firewall. </li> <li> <b>HTTP proxy:</b> Some network setups only allow web access through a firewalled proxy server. This last option enables those users to also connect to the CDDB server through that proxy server. There is also support for proxy authentication (currently only BasicAuth). </li> </ul> <p> The example below shows the steps you have to take when you want to change the server settings for the options described above. Of course you only have to make the changes for the option you choose. The example also specifies which settings are required with the <code>/*<i> REQ </i>*/</code> comment at the end of those lines. The values that are set for the optional fields are also the hard coded defaults used by libcddb. </p> <pre class="example"><code>/*<i> CDDBP settings </i>*/ <a href="API/cddb__conn_8h.html#54641c0dac5234713f1916d8d70d8e8b">cddb_set_server_name</a>(conn, "freedb.org"); <a href="API/cddb__conn_8h.html#f401470406a0139b0ea78c24960361b1">cddb_set_server_port</a>(conn, 888); /*<i> HTTP settings </i>*/ <a href="API/cddb__conn_8h.html#7a864e89e1d1eb17b958bdd7ed21d260">cddb_http_enable</a>(conn); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#f401470406a0139b0ea78c24960361b1">cddb_set_server_port</a>(conn, 80); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#54641c0dac5234713f1916d8d70d8e8b">cddb_set_server_name</a>(conn, "freedb.org"); <a href="API/cddb__conn_8h.html#149b142eaa370b6032ce997fd0ab387e">cddb_set_http_path_query</a>(conn, "/~cddb/cddb.cgi"); <a href="API/cddb__conn_8h.html#689e000fc2739c94dcee2c396564d2dd">cddb_set_http_path_submit</a>(conn, "/~cddb/submit.cgi"); /*<i> HTTP proxy settings </i>*/ <a href="API/cddb__conn_8h.html#8e33685500b1f00f6a6b3216a5d501a0">cddb_http_proxy_enable</a>(conn); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#8484ac5eb6a1efee1cb440f1bd9de0f7">cddb_set_http_proxy_server_name</a>(conn, "my.proxy.com"); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#f6cbc387b2c20eae3d122577e80196c3">cddb_set_http_proxy_server_port</a>(conn, 8080); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#f401470406a0139b0ea78c24960361b1">cddb_set_server_port</a>(conn, 80); /*<i> REQ </i>*/ <a href="API/cddb__conn_8h.html#54641c0dac5234713f1916d8d70d8e8b">cddb_set_server_name</a>(conn, "freedb.org"); <a href="API/cddb__conn_8h.html#149b142eaa370b6032ce997fd0ab387e">cddb_set_http_path_query</a>(conn, "/~cddb/cddb.cgi"); <a href="API/cddb__conn_8h.html#689e000fc2739c94dcee2c396564d2dd">cddb_set_http_path_submit</a>(conn, "/~cddb/submit.cgi"); /*<i> option 1: stores cleartext credentials </i>*/ <a href="API/cddb__conn_8h.html#0eb1aed5a60b987b68e35aab6f8a789e">cddb_set_http_proxy_username</a>(conn, "myuser"); <a href="API/cddb__conn_8h.html#596f6f53c24aa16ba7618cc068c814db">cddb_set_http_proxy_password</a>(conn, "mypassword"); /*<i> option 2: does not store cleartext credentials </i>*/ <a href="API/cddb__conn_8h.html#aa4a07780a2d4602a9d42b4bd42e284d">cddb_set_http_proxy_credentials</a>(conn, "myuser", "mypassword"); </code></pre> <p> As shown in the example the actual location of the CDDB server (not proxy server) can be changed with calls to <a href="API/cddb__conn_8h.html#54641c0dac5234713f1916d8d70d8e8b">cddb_set_server_name</a> and <a href="API/cddb__conn_8h.html#f401470406a0139b0ea78c24960361b1">cddb_set_server_port</a>. That first function accepts both DNS names and IP addresses. </p> <p> Note that when you enable HTTP, you have to correctly initialize the server port. The <a href="API/cddb__conn_8h.html#7a864e89e1d1eb17b958bdd7ed21d260">cddb_http_enable</a> function will not automatically set the server port to 80. When using an HTTP proxy server you have to make sure that you correctly initialize both the address of the CDDB server and that of the proxy server as shown in the example. </p> <p> All the set functions shown above also have a get counterpart. You can consult the API reference for the correct syntax. </p> <table class="section2"><tr><td><a name="section4.2">4.2 Cache settings</a></td><td class="sectionnav"><a href="#section4.3"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section4.1"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> As stated above, the default libcddb cache directory is <code>$HOME/.cddbslave</code>. You can change this directory with the <a href="API/cddb__conn_8h.html#4279db07e78685fb1a502bbd6096dbb4">cddb_cache_set_dir</a> function. It will copy the string that is passed to it, so any memory used by that string can be freed after the function returns. This function will also expand a '<code>~</code>' as the first character to the contents of the <code>$HOME</code> environment variable. If you want to check what the current cache directory is, use the <a href="API/cddb__conn_8h.html#0b279d3ee74ce0e7948f25b2176c86fd">cddb_cache_get_dir</a> function. It returns a reference to a field inside the connection structure. You should not alter this string directly but use the set-function. </p> <p class="noindent"> Caching can be used in three different modes: </p> <ul> <li> <b>Enabled (default):</b> When caching is enabled a query or read operation will first check whether the requested data is present in the local cache. If it is, then that data will be returned. If it is not, then the server will be accessed. After the data has been read from the server it will be stored in the cache. Any subsequent reads will result in a cache hit. You can enable the cache with <a href="API/cddb__conn_8h.html#cd50c16de3aa51dcdc751d2d280c449a">cddb_cache_enable</a>. </li> <li> <b>Cache only:</b> When using this caching mode, libcddb will never contact a remote server. If the requested data is not found in the local cache, an appropriate error code will be returned. Enable this feature with <a href="API/cddb__conn_8h.html#ea8e701c4ebeddc6833186cd46b0d357">cddb_cache_only</a>. </li> <li> <b>Disabled:</b> You can also completely disable the cache. Any libcddb command will now always contact the remote server. No data will ever be retrieved from the cache or stored in the cache. To disable the cache use <a href="API/cddb__conn_8h.html#b39d8c98dcab69671ecb0c00e880e3a7">cddb_cache_disable</a>. </li> </ul> <p> If you want to check what the current caching mode is, you should us <a href="API/cddb__conn_8h.html#f51571f2931ec69c8ef6211eaeeff9d7">cddb_cache_mode</a>. This function will return one of three values: <a href="API/cddb__conn_8h.html#264ac059c9a7ba457e4054efc7aaa69b916a7dbc1d2807513a9a0ad10c9b13bc">CACHE_ON</a>, <a href="API/cddb__conn_8h.html#264ac059c9a7ba457e4054efc7aaa69b7ca046cd60ca10f3a4ceca753c217567">CACHE_ONLY</a> or <a href="API/cddb__conn_8h.html#264ac059c9a7ba457e4054efc7aaa69b89ceda9ff7fcc69ea74bfb81c1527512">CACHE_OFF</a>. Each of these values maps to the corresponding mode described above. </p> <table class="section2"><tr><td><a name="section4.3">4.3 Miscellaneous settings</a></td><td class="sectionnav"><a href="#section4.4"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section4.2"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> When contacting a CDDB server the protocol requires you to send a user and host name before asking any data from the server. As described above, libcddb will use 'anonymous' and 'localhost' as the defaults. These two values are also used when submitting new disc entries to the server. They will be concatenated to form the required e-mail address (user@hostname). This has to be a valid e-mail address for the submit to work correctly. It is not possible to submit a disc entry when the default values have not been changed. You can change both these fields in one go with <a href="API/cddb__conn_8h.html#cfcd1cffe82707f325d8e47355a243f9">cddb_set_email_address</a>. </p> <p> Another set of values that are also required by the protocol are the client name and version. By default these are set to 'libcddb' and the version number of libcddb that you are using. It is however possible to change these values to the name and version of the program that is using the library. Use the <a href="API/cddb__conn_8h.html#1c1d0afabce7dfd17759e46795c3f637">cddb_set_client</a> function to change these client settings. </p> <p> Finally, the libcddb networking code supports time outs. This means that any function that connects to, reads from and writes to a remote CDDB server, will not block indefinitely when there is a network problem. By default any of these actions will time-out after ten seconds and return with an error status. You can change this time-out interval with the <a href="API/cddb__conn_8h.html#4c4b3c013eb29951c34d161501eb8ca4">cddb_set_timeout</a> function. </p> <table class="section1"><tr><td><a name="section5">5 Querying the database</a></td><td class="sectionnav"><a href="#section6"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section4"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> Unless you know the exact disc ID and category of a certain disc--in which case you can skip to the section about reading disc details--you will first have to query the database to see whether there are any matches for your disc. A CDDB query can return </p> <ul> <li> no matches; </li> <li> one exact match; </li> <li> multiple exact matches (same disc present in multiple categories); or </li> <li> multiple inexact matches (similar disc present in multiple categories). </li> </ul> <p> Each match that is found will contain the disc ID and disc category for that matching disc. With these two fields a CDDB read command can be executed to get the other disc data. This is discussed below. </p> <p> To perform a query operation you will need a disc structure. The disc length has to be initialized in this structure and the tracks within need to have their frame offset set. An illustration follows. </p> <pre class="example"><code>static int disc_length = 3822; static int frame_offsets[11] = { 150, 28690, 51102, 75910, 102682, 121522, 149040, 175772, 204387, 231145, 268065 }; <a href="API/cddb__disc_8h.html#42efa38614123ddc2bcc8a889443ceda">cddb_disc_t</a> *disc = NULL; <a href="API/cddb__track_8h.html#1f656d30547194e5a6d9b75406f6b515">cddb_track_t</a> *track = NULL; int i, matches; /*<i> (1) initialize disc and tracks </i>*/ disc = <a href="API/cddb__disc_8h.html#d3f011e11da576beb06fc0873aa769bc">cddb_disc_new</a>(); if (disc == NULL) { fprintf(stderr, "out of memory, unable to create disc"); exit(-1); } <a href="API/cddb__disc_8h.html#403ea0c84c8075fefa6adfaad8184c8c">cddb_disc_set_length</a>(disc, disc_length); for (i = 0; i < 11; i++) { track = <a href="API/cddb__track_8h.html#1ff23780b5f261609d253d5f382a9dbe">cddb_track_new</a>(); if (track == NULL) { fprintf(stderr, "out of memory, unable to create track"); exit(-1); } <a href="API/cddb__track_8h.html#1db69a3085ebf75430ccc3f4cca7025c">cddb_track_set_frame_offset</a>(track, frame_offsets[i]); <a href="API/cddb__disc_8h.html#efcd9b6f9709284955af3f02598ba339">cddb_disc_add_track</a>(disc, track); } /*<i> (2) execute query command </i>*/ matches = <a href="API/cddb__cmd_8h.html#3be764c9073b53160ed6560d5c25fe03">cddb_query</a>(conn, disc); if (matches == -1) { /*<i> something went wrong, print error </i>*/ <a href="API/cddb__error_8h.html#7c1307f124ccc494bf9def45985c0225">cddb_error_print</a>(<a href="API/cddb__conn_8h.html#41d1b47b9ad3e64f6fa3e94d7547e6e5">cddb_errno</a>(conn)); exit(-1); } while (matches > 0) { /*<i> (3) ... use disc ... </i>*/ /*<i> (4) get next query result if there is one left </i>*/ matches--; if (matches > 0) { if (!<a href="API/cddb__cmd_8h.html#0db3f96efbb125a5ebc11f2074431be5">cddb_query_next</a>(conn, disc)) { fprintf(stderr, "query index out of bounds"); exit(-1); } } } </code></pre> <p> The example first creates a disc structure, initializes the total length of the disc to 3822 seconds and adds eleven tracks to it (1). Then it calls the <a href="API/cddb__cmd_8h.html#3be764c9073b53160ed6560d5c25fe03">cddb_query</a> function (2). This function will recalculate the disc ID of the disc provided to it and then query the local cache or the remote server for the requested information. The first disc in the query can now be processed (3). We decrement the match counter and if it has not yet reached zero, we retrieve the next match with <a href="API/cddb__cmd_8h.html#0db3f96efbb125a5ebc11f2074431be5">cddb_query_next</a> (4). </p> <table class="section1"><tr><td><a name="section6">6 Searching the database</a></td><td class="sectionnav"><a href="#section7"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section5"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> An alternative to querying is searching. If you do not know the frame offsets of the tracks on the disc then querying as described above is not possible. In this case you can still search for disc data using a text string. The results returned by the search command are similar to those of the query command. </p> <pre class="example"><code>static char *search_str = "mezzanine"; <a href="API/cddb__disc_8h.html#42efa38614123ddc2bcc8a889443ceda">cddb_disc_t</a> *disc = NULL; int i, matches; /*<i> (1) initialize disc </i>*/ disc = <a href="API/cddb__disc_8h.html#d3f011e11da576beb06fc0873aa769bc">cddb_disc_new</a>(); if (disc == NULL) { fprintf(stderr, "out of memory, unable to create disc"); exit(-1); } /*<i> (2) execute search command </i>*/ matches = <a href="API/cddb__cmd_8h.html#3be764c9073b53160ed6560d5c25fe03">cddb_query</a>(conn, disc, search_str); if (matches == -1) { /*<i> something went wrong, print error </i>*/ <a href="API/cddb__error_8h.html#7c1307f124ccc494bf9def45985c0225">cddb_error_print</a>(<a href="API/cddb__conn_8h.html#41d1b47b9ad3e64f6fa3e94d7547e6e5">cddb_errno</a>(conn)); exit(-1); } while (matches > 0) { /*<i> (3) ... use disc ... </i>*/ /*<i> (4) get next search result if there is one left </i>*/ matches--; if (matches > 0) { if (!<a href="API/cddb__cmd_8h.html#a648bcb583dae3e108a38bb514c24799">cddb_search_next</a>(conn, disc)) { fprintf(stderr, "search index out of bounds"); exit(-1); } } } </code></pre> <p> Again the example code first creates a disc structure in which the results will be returned (1). Then it calls the <a href="API/cddb__cmd_8h.html#68e5f0a66815266245121aba7e82686e">cddb_search</a> function (2). This function will perform a text search on the freedb.org web server. The first disc in the query can now be processed (3). We decrement the match counter and if it has not yet reached zero, we retrieve the next match with <a href="API/cddb__cmd_8h.html#a648bcb583dae3e108a38bb514c24799">cddb_search_next</a> (4). </p> <p> By default the text search command will only consider the artist name field and the disc title field when searching. It will search in every category for the specified string. You can fine-tune this behaviour as shown in the example below. </p> <pre class="example"><code>unsigned int fields = <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207596ecb69d2e3480c4b5bad071d758de5">SEARCH_ALL</a>; unsigned int fields = <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207f22a7dcf1e5539628c03c3bd305b8e95">SEARCH_ARTIST</a> | <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207098d21d3074984ecab7951bf3db7abc4">SEARCH_TRACK</a>; <a href="API/cddb__conn_8h.html#98bcdf45d34339bd3b9bee82e5dc4bc3">cddb_search_set_fields</a>(conn, fields); unsigned int cats = <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207596ecb69d2e3480c4b5bad071d758de5">SEARCH_ALL</a>; unsigned int cats = <a href="API/cddb__conn_8h.html#e1655d536ba835be95af11110a519cb4">SEARCHCAT</a>(<a href="API/cddb__disc_8h.html#ea1998e6495d2f0dfa3b6e45b4fcd50d57a322c8a25ae9a30b77f0fcea838872">CDDB_CAT_ROCK</a>) | <a href="API/cddb__conn_8h.html#e1655d536ba835be95af11110a519cb4">SEARCHCAT</a>(<a href="API/cddb__disc_8h.html#ea1998e6495d2f0dfa3b6e45b4fcd50d0f8ff1f94ad8c134bd34c791772d60e7">CDDB_CAT_MISC</a>); <a href="API/cddb__conn_8h.html#42926ccaf6269a28e4a8bde07ef7b985">cddb_search_set_categories</a>(conn, cats); </code></pre> <p> For the configuration of the fields any of the <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207">cddb_search_t</a> values can be used. When specifying which categories to search you can use the <a href="API/cddb__conn_8h.html#c3528eb88b27e833f1b239dab018b207596ecb69d2e3480c4b5bad071d758de5">SEARCH_ALL</a> value or you can specify individual categories. When specifying individual <a href="API/cddb__disc_8h.html#ea1998e6495d2f0dfa3b6e45b4fcd50d">cddb_cat_t</a> categories you have to use the <a href="API/cddb__conn_8h.html#e1655d536ba835be95af11110a519cb4">SEARCHCAT</a> macro as shown in the example. </p> <p> NOTE: The query and search commands should not be mixed. They both use the same internal list for storing their results. When starting a new query or search, this list is flushed. </p> <table class="section1"><tr><td><a name="section7">7 Reading disc details</a></td><td class="sectionnav"><a href="#section8"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section6"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> Once you know the category and disc ID of a certain CD, you are ready to retrieve the rest of the data from the server (or cache). </p> <pre class="example"><code><a href="API/cddb__disc_8h.html#42efa38614123ddc2bcc8a889443ceda">cddb_disc_t</a> *disc = NULL; int success; /*<i> (1) initialize disc </i>*/ disc = <a href="API/cddb__disc_8h.html#d3f011e11da576beb06fc0873aa769bc">cddb_disc_new</a>(); if (disc == NULL) { fprintf(stderr, "out of memory, unable to create disc"); exit(-1); } <a href="API/cddb__disc_8h.html#a2af35dfbffa7c8a91c9a5fc36671264">cddb_disc_set_category_str</a>(disc, "misc"); <a href="API/cddb__disc_8h.html#5c30ddb662dbfc62cc0992aa6898b794">cddb_disc_set_discid</a>(disc, 0x920ef00b); /*<i> (2) execute read command </i>*/ success = <a href="API/cddb__cmd_8h.html#9920c2ce0ebca2a943f3fe28049b5618">cddb_read</a>(conn, disc); if (!success) { /*<i> something went wrong, print error </i>*/ <a href="API/cddb__error_8h.html#7c1307f124ccc494bf9def45985c0225">cddb_error_print</a>(<a href="API/cddb__conn_8h.html#41d1b47b9ad3e64f6fa3e94d7547e6e5">cddb_errno</a>(conn)); exit(-1); } /*<i> (3) ... use disc ... </i>*/ </code></pre> <p> After we have created the disc structure we initialize the two parameters that are required by the read command: the category and the disc ID. An alternative method for setting the category is to use the <a href="API/cddb__disc_8h.html#fb23b487f2168c0fa75ebf8b7d641b38">cddb_disc_set_category</a> function with <a href="API/cddb__disc_8h.html#ea1998e6495d2f0dfa3b6e45b4fcd50d0f8ff1f94ad8c134bd34c791772d60e7">CDDB_CAT_MISC</a> as the second parameter. The only thing left to be done, is calling the <a href="API/cddb__cmd_8h.html#9920c2ce0ebca2a943f3fe28049b5618">cddb_read</a> function. This function will return true on success and false on failure. </p> <table class="section1"><tr><td><a name="section8">8 Cleaning up</a></td><td class="sectionnav"><a href="#section9"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section7"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> When you do not need a libcddb connection anymore, you should call the <a href="API/cddb__conn_8h.html#6e82c862d1338be57dccd92309149854">cddb_destroy</a> function. This function will properly disconnect from the server (if needed) and free all resources that were being used by the connection. </p> <p> As already mentioned in the track and disc section of this tutorial you should call <a href="API/cddb__track_8h.html#2e2a6b9d7dede4137355181716e372d5">cddb_track_destroy</a> and <a href="API/cddb__disc_8h.html#9bf985f08f176b23dffdee7af8440b21">cddb_disc_destroy</a> for freeing the memory used by those structures. </p> <p> If you are completely done with all libcddb functionality you should also call the <a href="API/cddb_8h.html#5a002ab61c0a144e140844f8705266de">libcddb_shutdown</a> function. This function will free up any global resources that are being shared by all connections. </p> <table class="section1"><tr><td><a name="section9">9 Miscellaneous</a></td><td class="sectionnav"><a href="#section10"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section8"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> This section talks about some details that do not fit in any of the section above, but nevertheless they are important enough to be mentioned </p> <table class="section2"><tr><td><a name="section9.1">9.1 Error handling</a></td><td class="sectionnav"><a href="#section9.2"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section9.0"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> As with all programs, with libcddb it is also possible that something goes wrong. The connection structure also keeps information about the result of the last function that has been executed. If this functioned completed successfully, then no other actions have to be taken. On the other hand most functions signal an error condition when something goes wrong. To determine whether a return value corresponds to an error you will have to consult the API documentation for that function. </p> <p> If something went wrong, then you can retrieve the error code with the <a href="API/cddb__conn_8h.html#41d1b47b9ad3e64f6fa3e94d7547e6e5">cddb_errno</a> function. This function will return one of the values defined by the <a href="API/cddb__error_8h.html#b8f3141dff6945177d70de613eff6ddb">cddb_error_t</a> enumeration. Some other error handling functions are provided to turn this error code into a more descriptive error message. As a start you can use <a href="API/cddb__error_8h.html#4a5070a84e46c80a551dcc1a2eef765a">cddb_error_str</a> to retrieve a string that describes the error condition for a given error code. Alternatively, it is also possible to directly print that string to <code>stderr</code> or any other stream with <a href="API/cddb__error_8h.html#7c1307f124ccc494bf9def45985c0225">cddb_error_print</a> and cddb_error stream_print respectively. </p> <table class="section2"><tr><td><a name="section9.2">9.2 Logging</a></td><td class="sectionnav"><a href="#section9.3"><img class="sectionimg" src="images/arrow_dn.png"></a> <a href="#section9.1"><img class="sectionimg" src="images/arrow_up.png"></a></td></tr></table> <p> Libcddb has a logging framework that can be customized to your needs. Any log message generated by the library functions can be categorized into one of five levels: <i>debug</i>, <i>informational</i>, <i>warning</i>, <i>error</i> and <i>critical</i> (in order of significance). </p> <p> The default log handler will print out any log messages to the standard error stream if it has a log level equal or higher than a certain minimum level. By default this minimum is set to <i>warning</i>, but it can be changed with the <a href="API/cddb__log_8h.html#840bf4742c82ae63cf61b6bb5032ce81">cddb_log_set_level</a> function. This function accepts any of the log levels from the <a href="API/cddb__log_8h.html#1067c83af78e9da497ae86c8defd39ae">cddb_log_level_t</a> enumeration. One of these levels is <a href="API/cddb__log_8h.html#1067c83af78e9da497ae86c8defd39aeba7ad5e887af04201eb0c9f3f2bed1d9">CDDB_LOG_NONE</a>, which can be used to disable the printing of any log messages. </p> <p> You can change the library's default minimum log level by providing the <code>--enable-loglevel</code> parameter to the <code>configure</code> script when compiling libcddb. </p> <p> If you want to do something else with the log messages instead of printing them to <code>stderr</code>, then you can create your own log handler and set it with <a href="API/cddb__log_8h.html#18a730cfc28bd8ac7bca95d8cfce0c13">cddb_log_set_handler</a>. The signature of the handler function is defined by the <a href="API/cddb__log_8h.html#89950157a9af55e9f71e034775ceaba7">cddb_log_handler_t</a> type. The example below shows how you can write a log handler that writes its messages to a file. </p> <pre class="example"><code>FILE *_logfile; void log_to_file(<a href="API/cddb__log_8h.html#1067c83af78e9da497ae86c8defd39ae">cddb_log_level_t</a> level, const char *message) { fprintf(_logfile, "(%d) %s", level, message); fflush(_logfile); } </code></pre> <table class="status"> <tbody> <tr> <td id="sflogo"> <a href="http://sourceforge.net"> <img src="http://sourceforge.net/sflogo.php?group_id=65237&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo"/> </a> </td> <td id="sflogo"> <a href="http://sourceforge.net/donate/index.php?group_id=65237"> <img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project"/> </a> </td> <td> <address><a href="mailto:airborne@advalvas.be"></a></address> Last modified: Sun Oct 15 14:49:16 CEST 2006 </td> </tr> </tbody> </table> </body> </html>