--- a/mpd2src/mpd2sc.cpp
+++ b/mpd2src/mpd2sc.cpp
@@ -63,6 +63,7 @@
 #include "audioreader.h"
 #include "openaudio.h"
 #include "base64.hxx"
+#include "songcastsender.h"
 
 using namespace std;
 
@@ -88,89 +89,16 @@
     }
 }
 
-class PcmSender {
-
-public:
-    static const TUint kPeriodMs = 10;
-    static const TUint kSpeedNormal = 100;
-    static const TUint kSpeedMin = 75;
-    static const TUint kSpeedMax = 150;
-    static const TUint kMaxPacketBytes = 4096;
-        
-public:
-    PcmSender(Environment& aEnv, OhmSender* aSender,
-              OhmSenderDriver* aDriver, const Brx& aUri,
-              AudioReader* audio, bool paced);
-    bool Start(TBool aEnabled);
-    void Play();
-    void PlayPause();
-    void Stop();
-    void Restart();
-    ~PcmSender();
-    void busyRdWr();
-    TBool Paused();
-        
-private:
-    void CalculatePacketBytes();
-    void TimerExpired();
-        
-private:
-    Environment& iEnv;
-    OhmSender* iSender;
-    OhmSenderDriver* iDriver;
-    Bws<OhmSender::kMaxTrackUriBytes> iUri;
-    AudioReader *m_audio;
-    Timer iTimer;
-    Mutex iMutex;
-    TBool iPaused;
-    TUint iSpeed;           // percent, 100%=normal
-    TUint iIndex;           // byte offset read position in source data
-    TUint iPacketBytes;     // how many bytes of audio in each packet
-    TUint iPacketFrames;    // how many audio frames in each packet
-    TUint iPacketTime;      // how much audio time in each packet, uS
-    TUint64 iLastTimeUs;    // last time stamp from system
-    TInt32 iTimeOffsetUs;   // running offset in usec from ideal time
-    //  <0 means sender is behind
-    //  >0 means sender is ahead
-    TBool iVerbose;
-    TBool iPaced;
-};
-
-PcmSender::PcmSender(Environment& aEnv, OhmSender* aSender,
-                     OhmSenderDriver* aDriver,
-                     const Brx& aUri, AudioReader* audio, bool paced)
-    : iEnv(aEnv)
-    , iSender(aSender)
-    , iDriver(aDriver)
-    , iUri(aUri)
-    , m_audio(audio)
-    , iTimer(aEnv, MakeFunctor(*this, &PcmSender::TimerExpired), "PcmSender")
-    , iMutex("WAVP")
-    , iPaused(true)
-    , iSpeed(kSpeedNormal)
-    , iIndex(0)
-    , iLastTimeUs(0)
-    , iTimeOffsetUs(0)
-    , iVerbose(false)
-    , iPaced(paced)
-      
-{
-    CalculatePacketBytes();
-    LOGDEB("bytes per packet: " << iPacketBytes << endl);
-    LOGDEB("frames per packet: " << iPacketFrames << endl);
-    LOGDEB("usec per packet:   "<< iPacketTime << endl);
-}
-
 #define SOCK_PATH "/tmp/mpd2sc.sock"
 #define BUF_SIZE 16
-void HandleUserCmd(OhmSender* sender, PcmSender* pcmsender)
+void HandleUserCmd(OhmSender* sender, SongcastSender* scsender)
 {
     struct sockaddr_un server_addr, client_addr;
     socklen_t len;
     ssize_t num_bytes;
     char buf[BUF_SIZE];
 
-    LOGDEB("PcmSender: Running user command handler\n");
+    LOGDEB("SongcastSender: Running user command handler\n");
 
     g_sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
     if (g_sockfd == -1) {
@@ -213,15 +141,17 @@
             LOGDEB("HandleUserCmd: Received " << num_bytes << " bytes: " <<
                             string(buf, num_bytes) << endl);
             if (strncmp("play", buf, num_bytes) == 0)
-                pcmsender->Play();
+                scsender->Play();
             else if (strncmp("stop", buf, num_bytes) == 0)
-                pcmsender->Stop();
+                scsender->Stop();
             else if (strncmp("playpause", buf, num_bytes) == 0)
-                pcmsender->PlayPause();
+                scsender->PlayPause();
             else if (strncmp("restart", buf, num_bytes) == 0)
-                pcmsender->Restart();
+                scsender->Restart();
+            else if (strncmp("codec", buf, num_bytes) == 0)
+                response = scsender->CodecName();
             else if (strncmp("state", buf, num_bytes) == 0)
-                response = pcmsender->Paused() ? "Stopped" : "Playing";
+                response = scsender->Paused() ? "Stopped" : "Playing";
             else if (strncmp("enable", buf, num_bytes) == 0)
                 sender->SetEnabled(true);
             else if (strncmp("disable", buf, num_bytes) == 0)
@@ -244,229 +174,7 @@
     if (g_sockfd > 0)
         close(g_sockfd);
 _leave:
-    LOGDEB("PcmSender: Leaving user command handler\n");
-}
-
-// We return true if the main thread should pause.
-bool PcmSender::Start(TBool aEnabled)
-{
-    iDriver->SetAudioFormat(m_audio->sampleRate(), m_audio->byteRate() * 8,
-                            m_audio->numChannels(),
-                            m_audio->bitsPerSample(), true, Brn("WAV"));
-    iSender->SetEnabled(true);
-
-    iSender->SetTrack(iUri, Brx::Empty(), m_audio->sampleCount(), 0);
-    iSender->SetMetatext(Brn("PcmSender repeated play"));
-
-    // It seems that both hijacking the main thread and using the
-    // timer with a short timeout (see TimerExpired()) work.
-    // Don't know what's best. The timer approach is closer to the original
-    // code and leaves the main thread free for control ops if needed.
-    // Otoh, if no data appears on the fifo, the timer thread is stuck in read
-    // and the upnp side stops working (no sender advertised).
-    // Maybe the best approach would be to start a separate thread and
-    // use busyreading. Using the main thread for now.
-    static const bool optionbusy = true;
-    if (iPaced || !optionbusy) {
-        LOGDEB("PcmSender::Start: using timers. Enabled? " << aEnabled << endl);
-        if (aEnabled)
-            Play();
-        return true;
-    } else {
-        LOGDEB("PcmSender::Start: block on reading only\n");
-        busyRdWr();
-        return false;
-    }
-}
-
-void PcmSender::Play()
-{
-    if (m_audio)
-        m_audio->open();
-
-    iMutex.Wait();
-    iPaused = false;
-    iLastTimeUs = 0;
-    iTimeOffsetUs = 0;
-    iTimer.FireIn(kPeriodMs);
-    iMutex.Signal();
-}
-
-void PcmSender::Stop()
-{
-    if (m_audio)
-        m_audio->close();
-
-    iMutex.Wait();
-    iPaused = true;
-    iMutex.Signal();
-}
-
-void PcmSender::PlayPause()
-{
-    if (iPaused)
-        Play();
-    else
-        Stop();
-}
-
-void PcmSender::Restart()
-{
-    iMutex.Wait();
-    iIndex = 0;
-    iMutex.Signal();
-}
-
-TBool PcmSender::Paused()
-{
-    return (iPaused);
-}
-
-void PcmSender::CalculatePacketBytes()
-{
-    // in order to let wavsender change the playback rate,
-    // we keep constant it's idea of how much audio time is in each packet,
-    // but vary the amount of data that is actually sent
-
-    // calculate the amount of time in each packet
-    TUint norm_bytes = (m_audio->sampleRate() * m_audio->bytesPerFrame() *
-                        kPeriodMs) / 1000;
-    if (norm_bytes > kMaxPacketBytes) {
-        norm_bytes = kMaxPacketBytes;
-    }
-    TUint norm_packet_samples = norm_bytes / m_audio->bytesPerFrame();
-    iPacketTime = (norm_packet_samples*1000000/(m_audio->sampleRate()/10) + 5)/10;
-
-    // calculate the adjusted speed packet size
-    TUint bytes = (norm_bytes * iSpeed) / 100;
-    if (bytes > kMaxPacketBytes) {
-        bytes = kMaxPacketBytes;
-    }
-    iPacketFrames = bytes / m_audio->bytesPerFrame();
-    iPacketBytes = iPacketFrames * m_audio->bytesPerFrame();
-}
-
-void PcmSender::busyRdWr()
-{
-    LOGDEB("PcmSender:busyRdWr: packetbytes " << iPacketBytes << endl);
-    while (true) {
-        if (g_quitrequest) {
-            return;
-        }
-        ssize_t nread = 0;
-        const unsigned char *cp = m_audio->data((size_t)iPacketBytes, nread);
-        if (cp == 0) {
-            return;
-        }
-        if (g_quitrequest) {
-            return;
-        }
-#ifdef HAVE_SENDAUDIO_PAUSE_FLAG
-        iDriver->SendAudio(cp, iPacketBytes, iPaused);
-#else
-        iDriver->SendAudio(cp, iPacketBytes);
-#endif
-    }
-}
-
-void PcmSender::TimerExpired()
-{
-    iMutex.Wait();
-    ssize_t nread = 0;
-    const unsigned char *cp = m_audio->data((size_t)iPacketBytes, nread);
-
-    if (nread > 0) {
-        if ((size_t)nread < iPacketBytes) {
-            LOGDEB("PcmSender::TimerExpired: requested " << iPacketBytes
-                 << " bytes, read " << nread << " bytes"  << endl);
-        }
-#ifdef HAVE_SENDAUDIO_PAUSE_FLAG
-        iDriver->SendAudio(cp, iPacketBytes, iPaused || g_quitrequest);
-#else
-        iDriver->SendAudio(cp, iPacketBytes);
-#endif
-    } else if (iPaused) {
-        // The audio stream was paused and no data could be read from the
-        // audio source anymore. To notify the receivers, send an empty audio
-        // message with the halt flag set.
-#ifdef HAVE_SENDAUDIO_PAUSE_FLAG
-        LOGDEB("PcmSender::Send empty audio message\n");
-        iDriver->SendAudio(cp, 0, iPaused || g_quitrequest);
-#endif
-    }
-
-    if (!iPaused && !g_quitrequest) {
-        TUint64 now = OsTimeInUs(iEnv.OsCtx());
-
-        if (!iPaced) {
-            // Means we're doing blocking reads on the source, and
-            // it's setting the pace.  I'd like to actually use 0 here
-            // (ala qt processEvents()), but this appears to busyloop
-            // and not let the sender do its thing.  Anyway, as long
-            // as we can read from the fifo in much less than (period-2),
-            // which should always be true, we should be ok.
-            // I can see not much difference between doing this or
-            // hijacking the main thread for busy read/write
-            iTimer.FireIn(2);
-        } else {
-            // skip the first packet, and any time the clock value wraps
-            if (iLastTimeUs && iLastTimeUs < now) {
-
-                // will contain the new time out in ms
-                TUint new_timer_ms = kPeriodMs;
-
-                // the difference in usec from where we should be
-                TInt32 diff = (TInt32)(now - iLastTimeUs) - iPacketTime;
-
-                // increment running offset
-                iTimeOffsetUs -= diff;
-
-                // determine new timer value based upon current offset from ideal
-                if (iTimeOffsetUs < -1000) {
-                    // we are late
-                    TInt32 time_offset_ms = iTimeOffsetUs/1000;
-                    if (time_offset_ms < 1-(TInt32)kPeriodMs) {
-                        // in case callback is severely late, we can only
-                        // catch up so much
-                        new_timer_ms = 1;
-                    } else {
-                        new_timer_ms = kPeriodMs + time_offset_ms;
-                    }
-                } else if (iTimeOffsetUs > 1000) {
-                    // we are early
-                    new_timer_ms = kPeriodMs+1;
-                } else {
-                    // we are about on time
-                    new_timer_ms = kPeriodMs;
-                }
-
-                // set timer
-                iTimer.FireIn(new_timer_ms);
-
-                // logging
-                if (iVerbose) {
-                    if (iTimeOffsetUs >= 1000)
-                        printf ("tnow:%d tlast:%d actual:%4d diff:%4d offset:%5d timer:%d\n", (TUint)now, (TUint)iLastTimeUs, (TUint)(now-iLastTimeUs), diff, iTimeOffsetUs, new_timer_ms);
-                    else
-                        printf ("tnow:%d tlast:%d actual:%4d diff:%4d offset:%4d timer:%d\n", (TUint)now, (TUint)iLastTimeUs, (TUint)(now-iLastTimeUs), diff, iTimeOffsetUs, new_timer_ms);
-                }
-            } else {
-                iTimer.FireIn(kPeriodMs);
-            }
-            iLastTimeUs = now;
-        }
-    } else {
-        LOGDEB("PcmSender::TimerExpired: Sender is paused. Stop firing\n");
-    }
-        
-    iMutex.Signal();
-}
-
-PcmSender::~PcmSender()
-{
-    iTimer.Cancel();
-    delete (iSender);
-    delete (iDriver);
+    LOGDEB("SongcastSender: Leaving user command handler\n");
 }
 
 static char *thisprog;
@@ -476,6 +184,7 @@
 "    swap==1 if the input is little-endian. Set this only if the data can't be\n"
 "    obtained from the file. Conflicting values will cause an error. \n"
 "  -a, --adapter, [adapter] index of network adapter to use.\n"
+"  -C, --codec, [PCM|FLAC] select streaming codec.\n"
 "  -c, --channel, [0..65535] sender channel.\n"
 "  -d, --disabled, [disabled] start up disabled.\n"
 "  -f, --file, [file] file name to read and send.\n"
@@ -509,10 +218,12 @@
 #define OPT_p    0x100
 #define OPT_t    0x200
 #define OPT_u    0x400
+#define OPT_C    0x800
 
 static struct option long_options[] = {
     {"audio", required_argument, 0, 'A'},
     {"adapter", required_argument, 0, 'a'},
+    {"codec", required_argument, 0, 'C'},
     {"channel", required_argument, 0, 'c'},
     {"disabled", 0, 0, 'd'},
     {"file", required_argument, 0, 'f'},
@@ -532,13 +243,15 @@
     int ret;
     (void)op_flags;
     string audioparams, sfile, sname("Openhome WavSender"), sudn("12345678");
+    string codec;
     string ofile;
     unsigned int adaptidx(0), channel(0), ttl(1), latency(100);
-    while ((ret = getopt_long(argc, argv, "A:a:c:df:o:l:mn:pt:u:",
+    while ((ret = getopt_long(argc, argv, "A:a:C:c:df:o:l:mn:pt:u:",
                               long_options, NULL)) != -1) {
         switch (ret) {
         case 'A': audioparams = optarg;op_flags |= OPT_A; break;
         case 'a': adaptidx = atoi(optarg);op_flags |= OPT_a; break;
+        case 'C': codec = optarg;op_flags |= OPT_C; break;
         case 'c': channel = atoi(optarg);op_flags |= OPT_c; break;
         case 'd': op_flags |= OPT_d; break;
         case 'f': sfile = optarg;op_flags |= OPT_f; break;
@@ -626,9 +339,8 @@
     OhmSender* sender =
         new OhmSender(lib->Env(), *device, *driver, name, channel, adapter, ttl,
                       latency, multicast, !disabled, icon, Brn("image/png"), 0);
-        
-    PcmSender* pcmsender = new PcmSender(lib->Env(), sender, driver, file,
-                                         audio, needpace);
+    SongcastSender* scsender = new SongcastSender(lib->Env(), sender, driver,
+                                         file, audio, codec, needpace);
     
     device->SetEnabled();
 
@@ -649,8 +361,8 @@
     signal(SIGUSR1, sigcatcher);
     signal(SIGINT, sigcatcher);
     signal(SIGTERM, sigcatcher);
-    if (pcmsender->Start(!disabled)) {
-        HandleUserCmd(sender, pcmsender);
+    if (scsender->Start(!disabled)) {
+        HandleUserCmd(sender, scsender);
         // If HandleUserCmd() fails with an error we do not want to exit, but
         // wait for termination.
         if (!g_quitrequest)
@@ -662,7 +374,7 @@
     }
 
     LOGDEB("Main: cleaning up\n");
-    delete (pcmsender);
+    delete (scsender);
 
     delete (device);