Re: [Musicpd-dev-team] [git pull] http output configure.ac cleanups

2009-03-16 Thread Max Kellermann
On 2009/03/15 21:32, Avuton Olrich avu...@gmail.com wrote:
 Please pull from my tree, lots of cleanups for generalization post
 http output. The one patch removes unnecessary warnings against
 various optional libaries; if these warnings are going to be displayed
 they should only be when the user tries to enable them.

Looks good!  Merged all of them.

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


Re: [Musicpd-dev-team] New HTTP streaming output plugin

2009-03-16 Thread Max Kellermann
On 2009/03/16 14:16, Stefan Monnier monn...@iro.umontreal.ca wrote:
  yesterday, I had some free time to write a HTTP server for MPD.  With
  the new httpd plugin, MPD can be a streaming server, without an
  icecast / shoutcast server.
 
 Last I heard, the HTTP protocol did have any special provision for
 audio content, so what protocol does it actually use?

It aims to be compatible to shoutcast.  Basically, that means that the
HTTP response has no content-length header, and the HTTP response body
is continuously generated by an encoder plugin (e.g. vorbis/ogg),
until MPD stops playing (and closes the TCP connection, effectively
ending the response body).

Technically, I believe this is an awful solution, and Vasily Stepanov
is working on a RTP output plugin.  HTTP streaming is what everybody
understands, and what just works.

 PS: While we're adding ways to send the songs out (to visualizers,
 and other such things)...: when are MPD clients going to be able to
 download songs (so an MPD client can download them to an MP3
 player)?

Similar to this feature request?

 http://musicpd.org/mantis/view.php?id=1924

Nobody is currently working on an implementation of that.

Max

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


Re: [Musicpd-dev-team] New HTTP streaming output plugin

2009-03-16 Thread Stefan Monnier
 Last I heard, the HTTP protocol did have any special provision for
 audio content, so what protocol does it actually use?
 It aims to be compatible to shoutcast.

Good, thanks.

 PS: While we're adding ways to send the songs out (to visualizers,
 and other such things)...: when are MPD clients going to be able to
 download songs (so an MPD client can download them to an MP3
 player)?

 Similar to this feature request?
  http://musicpd.org/mantis/view.php?id=1924
 Nobody is currently working on an implementation of that.

Kind of, except it doesn't need UPnD or DLNA, just a new command
download file.  I had sent a sample patch that provided this command
a long time ago.  My implementation was purposefully naive, so that it
could be used to download any file from the `music' subdirectories (and
`playlist', tho this part is not needed any more now that we have
listplaylistinfo), which I abused in my MPC.el client to also download
files like dir/cover.jpg.


Stefan

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


Re: [Musicpd-dev-team] New HTTP streaming output plugin

2009-03-16 Thread Max Kellermann
On 2009/03/16 15:22, Stefan Monnier monn...@iro.umontreal.ca wrote:
 Kind of, except it doesn't need UPnD or DLNA, just a new command
 download file.  I had sent a sample patch that provided this command
 a long time ago.  My implementation was purposefully naive, so that it
 could be used to download any file from the `music' subdirectories (and
 `playlist', tho this part is not needed any more now that we have
 listplaylistinfo), which I abused in my MPC.el client to also download
 files like dir/cover.jpg.

I have two problems with that concept:

- big danger of security problems, of course.

- the MPD protocol is UTF-8/line based.  Shaking this fundamental
  concept of the protocol by allowing the switch to binary mode is
  something we should think twice about.  But maybe we can make this
  part of the HTTP server (move the httpd code into MPD core, and let
  the httpd output plugin mount itself as a special case)?

I understand that album cover management is an interesting feature
request for MPD.  I have been thinking about adding some sort of
binary stickers for images, lyrics, ...

Max

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


Re: [Musicpd-dev-team] New HTTP streaming output plugin

2009-03-16 Thread Avuton Olrich
On Mon, Mar 16, 2009 at 7:22 AM, Stefan Monnier
monn...@iro.umontreal.ca wrote:
 Kind of, except it doesn't need UPnD or DLNA, just a new command
 download file.  I had sent a sample patch that provided this command
 a long time ago.  My implementation was purposefully naive, so that it
 could be used to download any file from the `music' subdirectories (and
 `playlist', tho this part is not needed any more now that we have
 listplaylistinfo), which I abused in my MPC.el client to also download
 files like dir/cover.jpg.

Why in the hell would anyone want their music player to become a
network filesystem protocol? I hope this never comes to fruition and
would rail against it in every way that I possibly can. I'm glad
people like amarok but kitchen sink applications are nonsense and they
don't allow even decent user interfaces. MPDs protocol already is
large and in many ways senseless. Something to download anything in
music would be disgusting (not the word, but I couldn't think of a
worse word) and I would have to hope that we have a maintainer at that
point that keeps the mainline project from heading in that direction.

There are so many other things out there that are fit for this
purpose, sshfs, nfs, cifs which dedicate their whole existance to
creating a good way to download files from remote servers.
-- 
avuton
--
|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| ()_() world domination.

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


[Musicpd-dev-team] New download command (was: New HTTP streaming output plugin)

2009-03-16 Thread Stefan Monnier
 Kind of, except it doesn't need UPnD or DLNA, just a new command
 download file.  I had sent a sample patch that provided this command
 a long time ago.  My implementation was purposefully naive, so that it
 could be used to download any file from the `music' subdirectories (and
 `playlist', tho this part is not needed any more now that we have
 listplaylistinfo), which I abused in my MPC.el client to also download
 files like dir/cover.jpg.

 I have two problems with that concept:
 - big danger of security problems, of course.

Easy to solve: only allow downloads of song-files.  Tho, allowing
reading any file under the `music' directory would be perfectly safe for
my setup, and I expect it would also be perfectly safe for
most people's.  Of course you'd want to be careful with ...

 - the MPD protocol is UTF-8/line based.

No problem here: just encode the data somehow to make it fit, or use
a separate connection (more problematic but more efficient), or ...
The world of possible solutions is wide open.

 But maybe we can make this part of the HTTP server (move the httpd code
 into MPD core, and let the httpd output plugin mount itself as
 a special case)?

As long as I can download while MPD is playing some other song, that'd
be probably be OK.

 I understand that album cover management is an interesting feature
 request for MPD.  I have been thinking about adding some sort of
 binary stickers for images, lyrics, ...

Yes, my sample implementation covered a whole bunch of different
features, by providing dirty low-level access.  But there's no need to
do it this way (it was just easier for me to implement and saved several
problems at once).  One aspect is just download a song from MPD so
I can stuff it into my portable Ogg player, this may need/want to worry
about re-encoding the song in a different format (e.g. I keep my music
in Flac but like to reencode it into Ogg-96Kb/s before stuffing it into
my Ogg player), but that can left to the client for now.


Stefan


--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


[Musicpd-dev-team] New download command (was: New HTTP streaming output plugin)

2009-03-16 Thread Stefan Monnier
 Kind of, except it doesn't need UPnD or DLNA, just a new command
 download file.  I had sent a sample patch that provided this command
 a long time ago.  My implementation was purposefully naive, so that it
 could be used to download any file from the `music' subdirectories (and
 `playlist', tho this part is not needed any more now that we have
 listplaylistinfo), which I abused in my MPC.el client to also download
 files like dir/cover.jpg.

 Why in the hell would anyone want their music player to become a
 network filesystem protocol? I hope this never comes to fruition and

Thanks for bashing my implementation (which I didn't write to submit it
for inclusion, but because I needed to solve an actual problem).
Now, what do you think about my feature request (which can be
implemented in many different ways)?


Stefan


--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


[Musicpd-dev-team] [PATCH] pulse_mixer: close

2009-03-16 Thread David Guibert
when the mixer is closed,
- the mainloop is stopped.
- the context is disconnected.
- then the mainloop is freed.

Signed-off-by: David Guibert david.guib...@gmail.com

---
 src/mixer/pulse_mixer.c |   15 ++-
 1 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c
index 481fec2..a300a29 100644
--- a/src/mixer/pulse_mixer.c
+++ b/src/mixer/pulse_mixer.c
@@ -237,7 +237,20 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data)
 static void
 pulse_mixer_close(G_GNUC_UNUSED struct mixer *data)
 {
-   return;
+   struct pulse_mixer *pm=(struct pulse_mixer *) data;
+   if (pm-mainloop)
+   pa_threaded_mainloop_stop(pm-mainloop);
+
+   if (pm-context) {
+   pa_context_disconnect(pm-context);
+   pa_context_unref(pm-context);
+   pm-context = NULL;
+   }
+
+   if (pm-mainloop) {
+   pa_threaded_mainloop_free(pm-mainloop);
+   pm-mainloop = NULL;
+   }
 }
 
 static int
-- 
tg: (b4de244..) t/pulse_mixer_close (depends on: t/offline-only-removed-sink)

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team


[Musicpd-dev-team] [PATCH] pulse_mixer: clarify debug messages.

2009-03-16 Thread David Guibert
Signed-off-by: David Guibert david.guib...@gmail.com
---
Avuton,

I hope this help to find which part clearly fails.
It should give me more information about bugs
- 2136
- 2138
- 2139

Regards

 src/mixer/pulse_mixer.c |   45 ++---
 1 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c
index a300a29..7f2651a 100644
--- a/src/mixer/pulse_mixer.c
+++ b/src/mixer/pulse_mixer.c
@@ -48,22 +48,19 @@ sink_input_cb(G_GNUC_UNUSED pa_context *context, const 
pa_sink_input_info *i,
 {
 
struct pulse_mixer *pm = userdata;
-   if (eol) {
-   g_debug(eol error sink_input_cb);
+   if (eol)
return;
-   }
 
if (!i) {
g_debug(Sink input callback failure);
return;
}
-   g_debug(sink input cb %s, index %d ,i-name,i-index);
-   if(strcmp(i-name,pm-output_name)==0) {
-   pm-index=i-index;
-   pm-online=true;
-   *pm-volume=i-volume;
-   } else
-   g_debug(bad name);
+   if(strcmp(i-name,pm-output_name) == 0) {
+   g_debug(Sink input cb %s, index %d,i-name,i-index);
+   pm-index   = i-index;
+   pm-online  = true;
+   *pm-volume = i-volume;
+   }
 }
 
 static void
@@ -72,21 +69,19 @@ sink_input_vol(G_GNUC_UNUSED pa_context *context, const 
pa_sink_input_info *i,
 {
 
struct pulse_mixer *pm = userdata;
-   if (eol) {
-   g_debug(eol error sink_input_vol);
+   if (eol)
return;
-   }
 
if (!i) {
-   g_debug(Sink input callback failure);
+   g_debug(Sink input volume failure);
return;
}
-   g_debug(sink input vol %s, index %d , i-name, i-index);
-   *pm-volume=i-volume;
+   g_debug(Sink input vol %s, index %d, i-name, i-index);
+   *pm-volume = i-volume;
 }
 
 static void
-subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t,
+subscribe_cb(pa_context *context, pa_subscription_event_type_t t,
 uint32_t idx, void *userdata)
 {
 
@@ -101,7 +96,7 @@ subscribe_cb(G_GNUC_UNUSED pa_context *c, 
pa_subscription_event_type_t t,
else {
pa_operation *o;
 
-   if (!(o = pa_context_get_sink_input_info(pm-context, 
idx, sink_input_cb, pm))) {
+   if (!(o = pa_context_get_sink_input_info(context, idx, 
sink_input_cb, pm))) {
g_debug(pa_context_get_sink_input_info() 
failed);
return;
}
@@ -202,8 +197,9 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data)
return false;
}
 
+   pa_threaded_mainloop_lock(pm-mainloop);
if(!(pm-context = 
pa_context_new(pa_threaded_mainloop_get_api(pm-mainloop),
- Mixer mpd))) {
+ Mixer MPD))) {
g_debug(failed context);
return false;
}
@@ -212,20 +208,21 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data)
 
if (pa_context_connect(pm-context, pm-server,
   (pa_context_flags_t)0, NULL)  0) {
-   g_debug(context server fail);
+   g_warning(Failed to connect to server: %s, 
pa_strerror(pa_context_errno(pm-context)));
return false;
}
 
-   pa_threaded_mainloop_lock(pm-mainloop);
if (pa_threaded_mainloop_start(pm-mainloop)  0) {
-   g_debug(error start mainloop);
+   g_warning(Failed to start main loop);
return false;
}
 
+   /* Wait until the context is ready */
pa_threaded_mainloop_wait(pm-mainloop);
 
if (pa_context_get_state(pm-context) != PA_CONTEXT_READY) {
-   g_debug(error context not ready);
+   g_warning(Failed to connect to server: %s, 
pa_strerror(pa_context_errno(pm-context)));
+   pa_threaded_mainloop_unlock(pm-mainloop);
return false;
}
 
@@ -283,6 +280,8 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume)
 {
struct pulse_mixer *pm=(struct pulse_mixer *) mixer;
pa_operation *o;
+   g_debug(set_volume %s %d,
+   pm-online == TRUE ? online : offline, volume);
if (pm-online) {
pa_cvolume_set(pm-volume, (pm-volume)-channels,
(pa_volume_t)(volume)*PA_VOLUME_NORM/100+0.5);
-- 
tg: (8137a4f..) t/debug-messages (depends on: t/pulse_mixer_close)

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the 

Re: [Musicpd-dev-team] [PATCH] pulse_mixer: clarify debug messages.

2009-03-16 Thread Avuton Olrich
On Mon, Mar 16, 2009 at 2:53 PM, David Guibert david.guib...@gmail.com wrote:
 Signed-off-by: David Guibert david.guib...@gmail.com
 ---
 Avuton,

 I hope this help to find which part clearly fails.
 It should give me more information about bugs
 - 2136
 - 2138
 - 2139

 Regards

  src/mixer/pulse_mixer.c |   45 ++---
  1 files changed, 22 insertions(+), 23 deletions(-)

 diff --git a/src/mixer/pulse_mixer.c b/src/mixer/pulse_mixer.c
 index a300a29..7f2651a 100644
 --- a/src/mixer/pulse_mixer.c
 +++ b/src/mixer/pulse_mixer.c
 @@ -48,22 +48,19 @@ sink_input_cb(G_GNUC_UNUSED pa_context *context, const 
 pa_sink_input_info *i,
  {

        struct pulse_mixer *pm = userdata;
 -       if (eol) {
 -               g_debug(eol error sink_input_cb);
 +       if (eol)
                return;
 -       }

        if (!i) {
                g_debug(Sink input callback failure);
                return;
        }
 -       g_debug(sink input cb %s, index %d ,i-name,i-index);
 -       if(strcmp(i-name,pm-output_name)==0) {
 -               pm-index=i-index;
 -               pm-online=true;
 -               *pm-volume=i-volume;
 -       } else
 -               g_debug(bad name);
 +       if(strcmp(i-name,pm-output_name) == 0) {
 +               g_debug(Sink input cb %s, index %d,i-name,i-index);
 +               pm-index   = i-index;
 +               pm-online  = true;
 +               *pm-volume = i-volume;
 +       }
  }

  static void
 @@ -72,21 +69,19 @@ sink_input_vol(G_GNUC_UNUSED pa_context *context, const 
 pa_sink_input_info *i,
  {

        struct pulse_mixer *pm = userdata;
 -       if (eol) {
 -               g_debug(eol error sink_input_vol);
 +       if (eol)
                return;
 -       }

        if (!i) {
 -               g_debug(Sink input callback failure);
 +               g_debug(Sink input volume failure);
                return;
        }
 -       g_debug(sink input vol %s, index %d , i-name, i-index);
 -       *pm-volume=i-volume;
 +       g_debug(Sink input vol %s, index %d, i-name, i-index);
 +       *pm-volume = i-volume;
  }

  static void
 -subscribe_cb(G_GNUC_UNUSED pa_context *c, pa_subscription_event_type_t t,
 +subscribe_cb(pa_context *context, pa_subscription_event_type_t t,
             uint32_t idx, void *userdata)
  {

 @@ -101,7 +96,7 @@ subscribe_cb(G_GNUC_UNUSED pa_context *c, 
 pa_subscription_event_type_t t,
                else {
                        pa_operation *o;

 -                       if (!(o = pa_context_get_sink_input_info(pm-context, 
 idx, sink_input_cb, pm))) {
 +                       if (!(o = pa_context_get_sink_input_info(context, 
 idx, sink_input_cb, pm))) {
                                g_debug(pa_context_get_sink_input_info() 
 failed);
                                return;
                        }
 @@ -202,8 +197,9 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data)
                return false;
        }

 +       pa_threaded_mainloop_lock(pm-mainloop);
        if(!(pm-context = 
 pa_context_new(pa_threaded_mainloop_get_api(pm-mainloop),
 -                                         Mixer mpd))) {
 +                                         Mixer MPD))) {
                g_debug(failed context);
                return false;
        }
 @@ -212,20 +208,21 @@ pulse_mixer_open(G_GNUC_UNUSED struct mixer *data)

        if (pa_context_connect(pm-context, pm-server,
                               (pa_context_flags_t)0, NULL)  0) {
 -               g_debug(context server fail);
 +               g_warning(Failed to connect to server: %s, 
 pa_strerror(pa_context_errno(pm-context)));
                return false;
        }

 -       pa_threaded_mainloop_lock(pm-mainloop);
        if (pa_threaded_mainloop_start(pm-mainloop)  0) {
 -               g_debug(error start mainloop);
 +               g_warning(Failed to start main loop);
                return false;
        }

 +       /* Wait until the context is ready */
        pa_threaded_mainloop_wait(pm-mainloop);

        if (pa_context_get_state(pm-context) != PA_CONTEXT_READY) {
 -               g_debug(error context not ready);
 +               g_warning(Failed to connect to server: %s, 
 pa_strerror(pa_context_errno(pm-context)));
 +               pa_threaded_mainloop_unlock(pm-mainloop);
                return false;
        }

 @@ -283,6 +280,8 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned 
 volume)
  {
        struct pulse_mixer *pm=(struct pulse_mixer *) mixer;
        pa_operation *o;
 +       g_debug(set_volume %s %d,
 +               pm-online == TRUE ? online : offline, volume);
        if (pm-online) {
                pa_cvolume_set(pm-volume, (pm-volume)-channels,
                                (pa_volume_t)(volume)*PA_VOLUME_NORM/100+0.5);


Guess I'm an impatient guy. I had given up on you guys :). Well, the
good news is the problem doesn't exist anymore, the bad news is the
mixer doesn't do anything now ;)

Getting these once a second with 

Re: [Musicpd-dev-team] [PATCH] pulse_mixer: clarify debug messages.

2009-03-16 Thread Avuton Olrich
On Mon, Mar 16, 2009 at 3:52 PM, Avuton Olrich avu...@gmail.com wrote:
 On Mon, Mar 16, 2009 at 2:53 PM, David Guibert david.guib...@gmail.com 
 wrote:
 Signed-off-by: David Guibert david.guib...@gmail.com
 ---
 Avuton,

 I hope this help to find which part clearly fails.
 It should give me more information about bugs
 - 2136
 - 2138
 - 2139

 Guess I'm an impatient guy. I had given up on you guys :). Well, the
 good news is the problem doesn't exist anymore, the bad news is the
 mixer doesn't do anything now ;)

 Getting these once a second with gmpc open though.
 pulse_mixer: get_volume offline

 When I try to adjust I get:
 client: [1] process command setvol 100
 pulse_mixer: set_volume offline 100

 Nothing too eventful. Anything else I can help with?

 Thanks!

Forgot to mention that before it /did/ adjust the volume, just in very
erratic ways.
-- 
avuton
--
|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| ()_() world domination.

--
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
___
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team