Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp,v
retrieving revision 1.472
diff -a -u -r1.472 NuppelVideoPlayer.cpp
--- libs/libmythtv/NuppelVideoPlayer.cpp	24 May 2005 02:59:13 -0000	1.472
+++ libs/libmythtv/NuppelVideoPlayer.cpp	29 May 2005 02:20:08 -0000
@@ -211,6 +212,7 @@
     videosync = NULL;
 
     errored = false;
+    audio_timecode_offset = 0;
 }
 
 NuppelVideoPlayer::~NuppelVideoPlayer(void)
@@ -1436,14 +1477,36 @@
         lastsync = true;
     }
 
     if (audioOutput && normal_speed)
     {
         // ms, same scale as timecodes
-        lastaudiotime = audioOutput->GetAudiotime();
+        lastaudiotime = audioOutput->GetAudiotime() + audio_timecode_offset;
+        VERBOSE(VB_PLAYBACK, QString("A/V timecodes audio %1 video %2 frameinterval %3 avdel %4 avg %5 tcoffset %6")
+                .arg(lastaudiotime)
+                .arg(buffer->timecode)
+                .arg(frame_interval)
+                .arg(buffer->timecode - lastaudiotime)
+                .arg(avsync_avg)
+                .arg(audio_timecode_offset)
+                );
         if (lastaudiotime != 0 && buffer->timecode != 0)
-        { // lastaudiotime = 0 after a seek
+        { // lastaudiotime == 0 after a seek
+            if (labs(buffer->timecode - lastaudiotime)>1000000)
+            {
+                VERBOSE(VB_IMPORTANT, QString("A/V timecodes audio %1 video %2 frameinterval %3 avdel %4 avg %5")
+                        .arg(lastaudiotime)
+                        .arg(buffer->timecode)
+                        .arg(frame_interval)
+                        .arg(buffer->timecode - lastaudiotime)
+                        .arg(avsync_avg)
+                        );
+                lastaudiotime = audioOutput->GetAudiotime();
+                audio_timecode_offset = buffer->timecode - lastaudiotime;
+                VERBOSE(VB_IMPORTANT, QString("A/V audio timecode instantaneously diverged by %1")
+                        .arg(audio_timecode_offset));
+            }
             // The time at the start of this frame (ie, now) is given by
             // last->timecode
             prevtc = buffer->timecode;
             //cerr << delta << " ";
 
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/NuppelVideoPlayer.h,v
retrieving revision 1.179
diff -a -u -r1.179 NuppelVideoPlayer.h
--- libs/libmythtv/NuppelVideoPlayer.h	5 May 2005 02:51:15 -0000	1.179
+++ libs/libmythtv/NuppelVideoPlayer.h	29 May 2005 02:20:09 -0000
@@ -207,8 +209,14 @@
 
     long long CalcMaxFFTime(long long ff);
 
     bool IsErrored() { return errored; }
 
+    long long GetAudioTimecodeOffset() { return audio_timecode_offset; }
+    long long AdjustAudioTimecodeOffset(long long v) { 
+        audio_timecode_offset += v;
+        return audio_timecode_offset; 
+    }
+
  protected:
     void DisplayPauseFrame(void);
     void DisplayNormalFrame(void);
@@ -425,13 +444,14 @@
     DecoderBase *decoder;
 
     /* avsync stuff */
-    int lastaudiotime;
+    long long lastaudiotime;
     int delay;
     int avsync_delay;
     int avsync_adjustment;
     int avsync_avg;
     int avsync_oldavg;
     int refreshrate;
+    long long audio_timecode_offset;
 
     QMutex decoder_lock;
     int frame_interval; // always adjusted for play_speed
Index: libs/libmythtv/tv_play.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/tv_play.cpp,v
retrieving revision 1.270
diff -a -u -r1.270 tv_play.cpp
--- libs/libmythtv/tv_play.cpp	27 May 2005 00:59:21 -0000	1.270
+++ libs/libmythtv/tv_play.cpp	29 May 2005 02:20:24 -0000
@@ -185,7 +185,9 @@
       internalState(kState_None), nextState(kState_None), changeState(false),
       menurunning(false), runMainLoop(false), wantsToQuit(true), 
       exitPlayer(false), paused(false), errored(false),
-      stretchAdjustment(false), editmode(false), zoomMode(false),
+      stretchAdjustment(false), 
+      audiosyncAdjustment(false),
+      editmode(false), zoomMode(false),
       update_osd_pos(false), endOfRecording(false), requestDelete(false),
       doSmartForward(false), switchingCards(false), lastRecorderNum(-1),
       queuedTranscode(false), getRecorderPlaybackInfo(false), 
@@ -1591,6 +1600,28 @@
         }
     }
    
+    if (audiosyncAdjustment)
+    {
+        for (unsigned int i = 0; i < actions.size(); i++)
+        {
+            action = actions[i];
+            handled = true;
+
+            if (action == "LEFT")
+                ChangeAudioSync(-1);
+            else if (action == "RIGHT")
+                ChangeAudioSync(1);
+            else if (action == "UP")
+                ChangeAudioSync(-10);
+            else if (action == "DOWN")
+                ChangeAudioSync(10);
+            else if (action == "TOGGLEAUDIOSYNC")
+                ClearOSD();
+            else
+                handled = false;
+        }
+    }
+   
     if (handled)
         return;
 
@@ -1657,6 +1688,8 @@
         {
             ChangeTimeStretch(0);   // just display
         }
+        else if (action == "TOGGLEAUDIOSYNC")
+            ChangeAudioSync(0);   // just display
         else if (action == "TOGGLEPICCONTROLS")
         {
             if (usePicControls)
@@ -3393,6 +3433,29 @@
     }
 }
 
+// dir in 10ms jumps
+void TV::ChangeAudioSync(int dir, bool allowEdit)
+{
+    if (!audiosyncAdjustment)
+        audiosyncBaseline = activenvp->GetAudioTimecodeOffset();
+
+    audiosyncAdjustment = allowEdit;
+
+    long long newval = activenvp->AdjustAudioTimecodeOffset(dir*10) - 
+                        audiosyncBaseline;
+
+    if (osd && !browsemode)
+    {
+        QString text = QString(" %1 ms").arg(newval);
+        text = tr("Audio Sync") + text;
+
+        int val = (int)newval;
+        osd->StartPause((val/2)+500, false, tr("Adjust Audio Sync"), text, 10, 
+                        kOSDFunctionalType_AudioSyncAdjust);
+        update_osd_pos = false;
+    }
+}
+
 void TV::ToggleMute(void)
 {
     kMuteState mute_status;
@@ -3766,6 +3829,9 @@
         case kOSDFunctionalType_TimeStretchAdjust:
             stretchAdjustment = false;
             break;
+        case kOSDFunctionalType_AudioSyncAdjust:
+            audiosyncAdjustment = false;
+            break;
         case kOSDFunctionalType_Default:
             break;
     }
@@ -3948,6 +4014,8 @@
 
         ChangeTimeStretch(0, !floatRead);   // just display
     }
+    else if (action.left(15) == "TOGGLEAUDIOSYNC")
+        ChangeAudioSync(0);
     else if (action.left(11) == "TOGGLESLEEP")
     {
         ToggleSleepTimer(action.left(13));
@@ -4161,6 +4229,8 @@
     item = new OSDGenericTree(treeMenu, tr("Manual Zoom Mode"), 
                              "TOGGLEMANUALZOOM");
 
+    item = new OSDGenericTree(treeMenu, tr("Adjust Audio Sync"), "TOGGLEAUDIOSYNC");
+
     int speedX100 = (int)(round(normal_speed * 100));
     item = new OSDGenericTree(treeMenu, tr("Adjust Time Stretch"), "TOGGLESTRETCH");
     subitem = new OSDGenericTree(item, tr("Adjust"), "TOGGLESTRETCH");
Index: libs/libmythtv/tv_play.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/tv_play.h,v
retrieving revision 1.91
diff -a -u -r1.91 tv_play.h
--- libs/libmythtv/tv_play.h	27 May 2005 00:59:21 -0000	1.91
+++ libs/libmythtv/tv_play.h	29 May 2005 02:20:32 -0000
@@ -153,6 +153,7 @@
     void NormalSpeed(void);
     void ChangeSpeed(int direction);
     void ChangeTimeStretch(int dir, bool allowEdit = true);
+    void ChangeAudioSync(int dir, bool allowEdit = true);
     float StopFFRew(void);
     void ChangeFFRew(int direction);
     void SetFFRew(int index);
@@ -245,6 +246,8 @@
     bool paused;
     bool errored;
     bool stretchAdjustment; // is time stretch turned on
+    bool audiosyncAdjustment; // is audiosync turned on
+    long long audiosyncBaseline;
     bool editmode;       // are we in video editing mode
     bool zoomMode;
     bool update_osd_pos; // redisplay osd?
Index: libs/libmythtv/osd.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/osd.h,v
retrieving revision 1.65
diff -a -u -r1.65 osd.h
--- libs/libmythtv/osd.h	1 Apr 2005 02:38:31 -0000	1.65
+++ libs/libmythtv/osd.h	29 May 2005 02:20:33 -0000
@@ -21,7 +21,8 @@
     kOSDFunctionalType_PictureAdjust,
     kOSDFunctionalType_RecPictureAdjust,
     kOSDFunctionalType_SmartForward,
-    kOSDFunctionalType_TimeStretchAdjust
+    kOSDFunctionalType_TimeStretchAdjust,
+    kOSDFunctionalType_AudioSyncAdjust
 };
 
 class QImage;
