Ticket #6538: 6538-aodx_trunk.patch

File 6538-aodx_trunk.patch, 40.2 KB (added by Jeff Lu <jll544@…>, 15 years ago)

Replaces previous aodx patch. Adds additional buffer check to avoid looping audio when CPU is overloaded

  • libs/libmyth/audiooutputdx.h

     
    11#ifndef AUDIOOUTPUTDX
    22#define AUDIOOUTPUTDX
    33
    4 /* ACK! <windows.h> and <dsound.h> should only be in cpp's compiled
    5  * in windows only. Some of the variables in AudioOutputDX need to
    6  * be moved to a private class before removing these includes though.
    7  */
    8 #include <windows.h> // HACK HACK HACK
    9 #include <dsound.h>  // HACK HACK HACK
    10 
    114// MythTV headers
    125#include "audiooutputbase.h"
    136
     7class AudioOutputDXPrivate;
     8
    149class AudioOutputDX : public AudioOutputBase
    1510{
    16 public:
     11  friend class AudioOutputDXPrivate;
     12  public:
    1713    AudioOutputDX(const AudioSettings &settings);
    1814    virtual ~AudioOutputDX();
    1915
    20     /// BEGIN HACK HACK HACK HACK These need to actually be implemented!
    21     bool OpenDevice(void) { return false; }
    22     virtual void CloseDevice(void) {}
    23     virtual void WriteAudio(unsigned char*, int) {}
    24     virtual int  GetSpaceOnSoundcard(void)    const { return 0; }
    25     virtual int  GetBufferedOnSoundcard(void) const { return 0; }
    26 #warning Several methods in AudioOutputDX need to be implemented...
    27     /// END HACK HACK HACK HACK
    28        
    29     virtual void Reset(void);
    30     virtual void Reconfigure(const AudioSettings &settings);
    31     virtual void SetBlocking(bool blocking);
    32 
    33     virtual bool AddSamples(char *buffer, int samples, long long timecode);
    34     virtual bool AddSamples(char *buffers[], int samples, long long timecode);
    35     virtual void SetEffDsp(int dsprate);
    36     virtual void SetTimecode(long long timecode);
    37 
    38     virtual bool IsPaused(void) const { return paused; }
    39     virtual void Pause(bool paused);
    40 
    41     virtual void Drain(void);
    42 
    43     virtual int GetAudiotime(void);
    44 
    4516    // Volume control
    4617    virtual int GetVolumeChannel(int channel) const; // Returns 0-100
    4718    virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol
    4819
    49  private:
    50     HINSTANCE dsound_dll;      /* handle of the opened dsound dll */
    51     LPDIRECTSOUND dsobject;
    52     LPDIRECTSOUNDBUFFER dsbuffer;   /* the sound buffer we use (direct sound
    53                                        * takes care of mixing all the
    54                                        * secondary buffers into the primary) */
    55     LPDIRECTSOUNDNOTIFY dsnotify;         /* the position notify interface */
    56     DSBPOSITIONNOTIFY notif[4];
     20  protected:
     21    virtual bool OpenDevice(void);
     22    virtual void CloseDevice(void);
     23    virtual void WriteAudio(unsigned char *buffer, int size);
     24    virtual void Pause(bool pause);
     25    virtual int GetSpaceOnSoundcard(void) const;
     26    virtual int GetBufferedOnSoundcard(void) const;   
    5727
    58     DWORD write_cursor;
    59     DWORD buffer_size;
    60     bool blocking;
    61    
    62     bool awaiting_data;
    63  
    64     int effdsp; // from the recorded stream
    65     int audio_bytes_per_sample;
    66     int audio_bits;
    67     int audio_channels;
    68     int audbuf_timecode;    /* timecode of audio most recently placed into
    69                    buffer */
    70     bool can_hw_pause;
    71     bool paused;
    72    
    73     int InitDirectSound();
    74     int CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe);
    75     void DestroyDSBuffer();
    76     int FillBuffer(int frames, char *buffer);
     28  protected:
     29    AudioOutputDXPrivate    *m_priv;
     30    bool                     m_UseSPDIF;
     31    static const uint        kFramesNum;
    7732};
    7833
    7934#endif // AUDIOOUTPUTDX
  • libs/libmyth/audiooutputdx.cpp

     
    11#include <iostream>
     2#include <cmath>
    23//#include <stdlib.h>
    34
    45using namespace std;
     
    1011#include <mmsystem.h>
    1112#include <dsound.h>
    1213
    13 #define FRAMES_NUM 65536
     14#define LOC QString("AODX: ")
     15#define LOC_ERR QString("AODX, ERROR: ")
    1416
     17const uint AudioOutputDX::kFramesNum = 32;
     18
    1519/*****************************************************************************
    1620 * DirectSound GUIDs.
    1721 * Defining them here allows us to get rid of the dxguid library during
     
    2024#include <initguid.h>
    2125DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
    2226
    23 /*****************************************************************************
    24  * Useful macros
    25  *****************************************************************************/
    26 #ifndef WAVE_FORMAT_IEEE_FLOAT
    27 #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
    28 #endif
    29 
    3027#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
    3128#   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
    3229#endif
     
    3532#define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
    3633#endif
    3734
    38 #ifndef SPEAKER_FRONT_LEFT
    39 #   define SPEAKER_FRONT_LEFT             0x1
    40 #   define SPEAKER_FRONT_RIGHT            0x2
    41 #   define SPEAKER_FRONT_CENTER           0x4
    42 #   define SPEAKER_LOW_FREQUENCY          0x8
    43 #   define SPEAKER_BACK_LEFT              0x10
    44 #   define SPEAKER_BACK_RIGHT             0x20
    45 #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
    46 #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
    47 #   define SPEAKER_BACK_CENTER            0x100
    48 #   define SPEAKER_SIDE_LEFT              0x200
    49 #   define SPEAKER_SIDE_RIGHT             0x400
    50 #   define SPEAKER_TOP_CENTER             0x800
    51 #   define SPEAKER_TOP_FRONT_LEFT         0x1000
    52 #   define SPEAKER_TOP_FRONT_CENTER       0x2000
    53 #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
    54 #   define SPEAKER_TOP_BACK_LEFT          0x8000
    55 #   define SPEAKER_TOP_BACK_CENTER        0x10000
    56 #   define SPEAKER_TOP_BACK_RIGHT         0x20000
    57 #   define SPEAKER_RESERVED               0x80000000
    58 #endif
    59 
    60 #ifndef DSSPEAKER_HEADPHONE
    61 #   define DSSPEAKER_HEADPHONE         0x00000001
    62 #endif
    63 #ifndef DSSPEAKER_MONO
    64 #   define DSSPEAKER_MONO              0x00000002
    65 #endif
    66 #ifndef DSSPEAKER_QUAD
    67 #   define DSSPEAKER_QUAD              0x00000003
    68 #endif
    69 #ifndef DSSPEAKER_STEREO
    70 #   define DSSPEAKER_STEREO            0x00000004
    71 #endif
    72 #ifndef DSSPEAKER_SURROUND
    73 #   define DSSPEAKER_SURROUND          0x00000005
    74 #endif
    75 #ifndef DSSPEAKER_5POINT1
    76 #   define DSSPEAKER_5POINT1           0x00000006
    77 #endif
    78 
    7935#ifndef _WAVEFORMATEXTENSIBLE_
    8036typedef struct {
    8137    WAVEFORMATEX    Format;
     
    9046} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
    9147#endif
    9248
    93 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9449DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9550DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9651
    97 
    98 AudioOutputDX::AudioOutputDX(const AudioSettings &settings) :
    99     AudioOutputBase(settings),
    100     dsound_dll(NULL),
    101     dsobject(NULL),
    102     dsbuffer(NULL),
    103     write_cursor(0),
    104     buffer_size(0),
    105     blocking(false),
    106     awaiting_data(false),
    107     effdsp(0),                 /* Should this be audio_bits ? */
    108     audio_bytes_per_sample(0), /* ACK! hides version in AudioOutputBase */
    109     audio_bits(0),             /* ACK! hides version in AudioOutputBase */
    110     audio_channels(0),         /* ACK! hides version in AudioOutputBase */
    111     audbuf_timecode(0),
    112     can_hw_pause(false),
    113     paused(false)
     52class AudioOutputDXPrivate
    11453{
    115     InitDirectSound();
    116    
    117     Reconfigure(settings);
    118 }
    119 
    120 void AudioOutputDX::SetBlocking(bool blocking)
    121 {
    122     // FIXME: kedl: not sure what else could be required here?
    123 }
    124 
    125 void AudioOutputDX::Reconfigure(const AudioSettings &settings)
    126 {
    127     if (dsbuffer)
    128         DestroyDSBuffer();
    129        
    130     CreateDSBuffer(settings.bits, settings.channels, settings.samplerate, false);
    131    
    132     awaiting_data = true;
    133     paused = true;
    134        
    135     effdsp = settings.samplerate;
    136     this->audio_bits = settings.bits;
    137     this->audio_channels = settings.channels;
    138     this->audio_passthru = settings.use_passthru;
    139 }
    140 
    141 AudioOutputDX::~AudioOutputDX()
    142 {
    143     DestroyDSBuffer();
    144 
    145     /* release the DirectSound object */
    146     if (dsobject)
    147         IDirectSound_Release(dsobject);
    148    
    149     /* free DSOUND.DLL */
    150     if (dsound_dll)
    151        FreeLibrary(dsound_dll);
    152 }
    153 
    154 void AudioOutputDX::Reset(void)
    155 {
    156     audbuf_timecode = 0;
    157     awaiting_data = true;
    158     write_cursor = 0;
    159 
    160     if (dsbuffer)   
    161     {
    162         IDirectSoundBuffer_Stop(dsbuffer);
    163         IDirectSoundBuffer_SetCurrentPosition(dsbuffer, 0);
    164     }
    165 
    166 }
    167 
    168 bool AudioOutputDX::AddSamples(char *buffer, int frames, long long timecode)
    169 {
    170     FillBuffer(frames, buffer);
    171 
    172     HRESULT dsresult;
    173    
    174     if (awaiting_data)
    175     {
    176 //        dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
    177 //        if (dsresult == DSERR_BUFFERLOST)
    178 //        {
    179 //            IDirectSoundBuffer_Restore(dsbuffer);
    180 //            dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
    181 //        }
    182 //        if (dsresult != DS_OK)
    183 //        {
    184 //            VERBOSE(VB_IMPORTANT, "cannot start playing buffer" );
    185 //        }
    186        
    187         awaiting_data = false;
    188     }
    189 
    190 
    191    
    192 //    VERBOSE(VB_IMPORTANT, "add_samples(a) " << frames << " " << timecode);
    193 
    194     if (timecode < 0)
    195         timecode = audbuf_timecode; // add to current timecode
    196    
    197     /* we want the time at the end -- but the file format stores
    198        time at the start of the chunk. */
    199     audbuf_timecode = timecode + (int)((frames*1000.0) / effdsp);
    200 
    201     return true;
    202 }
    203 
    204 
    205 bool AudioOutputDX::AddSamples(char *buffers[], int frames, long long timecode)
    206 {
    207 //    VERBOSE(VB_IMPORTANT, "add_samples(b) " << frames << " " << timecode);
    208 
    209 /*    int err;
    210     int waud=0;
    211     int audio_bytes = audio_bits / 8;
    212     int audbufsize = frames*audio_bytes*audio_channels;
    213     char *audiobuffer = (char *) calloc(1,audbufsize);
    214 
    215     if (audiobuffer==NULL)
    216     {
    217         fprintf(stderr, "couldn't get memory to write audio to artsd\n");
    218     return;
    219     }
    220 
    221     if (pcm_handle == NULL)
    222     {
    223         free(audiobuffer);
    224         return;
    225     }
    226 
    227     for (int itemp = 0; itemp < frames*audio_bytes; itemp+=audio_bytes)
    228     {
    229         for(int chan = 0; chan < audio_channels; chan++)
     54    public:
     55        AudioOutputDXPrivate(AudioOutputDX *in_parent) :
     56            parent(in_parent),
     57            dsound_dll(NULL),
     58            dsobject(NULL),
     59            dsbuffer(NULL),
     60            playStarted(false),
     61            writeCursor(0),
     62            lastValidTime(0)
    23063        {
    231             audiobuffer[waud++] = buffers[chan][itemp];
    232             if (audio_bits == 16)
    233                 audiobuffer[waud++] = buffers[chan][itemp+1];
    234             if (waud >= audbufsize)
    235                 waud -= audbufsize;
     64            InitDirectSound();
    23665        }
    237     }
    23866
    239     err = arts_write(pcm_handle, audiobuffer, frames*4);
    240     free(audiobuffer);
     67        ~AudioOutputDXPrivate()
     68        {
     69            DestroyDSBuffer();
    24170
    242     if (err < 0)
    243     {
    244         fprintf(stderr, "arts_write error: %s\n", arts_error_text(err));
    245         return;
    246     }
    247 
    248     if (timecode < 0)
    249         timecode = audbuf_timecode; // add to current timecode*/
     71            if (dsobject)
     72                IDirectSound_Release(dsobject);
    25073   
    251     /* we want the time at the end -- but the file format stores
    252        time at the start of the chunk. */
    253     //audbuf_timecode = timecode + (int)((frames*100000.0) / effdsp);
     74            if (dsound_dll)
     75               FreeLibrary(dsound_dll);
     76        }
    25477
    255     return true;
    256 }
     78        int InitDirectSound(void);
     79        void DestroyDSBuffer(void);
     80        void FillBuffer(unsigned char *buffer, int size);
     81        bool StartPlayback(void);
     82        void StopPlayback(bool reset);
    25783
    258 void AudioOutputDX::SetTimecode(long long timecode)
    259 {
    260     audbuf_timecode = timecode;
    261 }
     84    public:
     85        AudioOutputDX *parent;
     86        HINSTANCE dsound_dll;
     87        LPDIRECTSOUND dsobject;
     88        LPDIRECTSOUNDBUFFER dsbuffer;
     89        bool playStarted;       
     90        DWORD writeCursor;       
     91        DWORD lastValidTime;       
     92};
    26293
    263 void AudioOutputDX::SetEffDsp(int dsprate)
    264 {
    265     VERBOSE(VB_IMPORTANT, "setting dsprate = " << dsprate);
    266    
    267     HRESULT dsresult;
    26894
    269     dsresult = IDirectSoundBuffer_SetFrequency(dsbuffer, dsprate / 100);
    270 
    271     if (dsresult != DS_OK)
    272     {
    273         VERBOSE(VB_IMPORTANT, "cannot set frequency");
    274     }
    275 
    276     effdsp = dsprate / 100;
    277 }
    278 
    279 void AudioOutputDX::Pause(bool pause)
     95AudioOutputDX::AudioOutputDX(const AudioSettings &settings) :
     96    AudioOutputBase(settings),
     97    m_priv(new AudioOutputDXPrivate(this)),
     98    m_UseSPDIF(settings.use_passthru)
    28099{
    281     HRESULT dsresult;
    282 
    283     VERBOSE(VB_IMPORTANT, "pause: " << pause);
    284 
    285     if (pause == paused)
    286         return;
    287        
    288     if (paused)
    289     {
    290         VERBOSE(VB_IMPORTANT, "unpausing");
    291    
    292         dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
    293         if (dsresult == DSERR_BUFFERLOST)
    294         {
    295             IDirectSoundBuffer_Restore(dsbuffer);
    296             dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
    297         }
    298         if (dsresult != DS_OK)
    299         {
    300             VERBOSE(VB_IMPORTANT, "cannot start playing buffer" );
    301         }
    302     }
    303     else
    304     {
    305         VERBOSE(VB_IMPORTANT, "pausing");
    306    
    307         IDirectSoundBuffer_Stop(dsbuffer);
    308     }
    309 
    310     paused = pause;
     100    timeBeginPeriod(1);
     101    Reconfigure(settings);
    311102}
    312103
    313 int AudioOutputDX::GetAudiotime(void)
     104AudioOutputDX::~AudioOutputDX()
    314105{
    315     DWORD play_pos;
    316     HRESULT dsresult;
     106    KillAudio();
    317107
    318     dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, NULL);
    319 
    320     if (dsresult != DS_OK)
     108    if (m_priv)
    321109    {
    322         VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    323         return -1;
     110        delete m_priv;
     111        m_priv = NULL;
    324112    }
    325 
    326     int frames = (write_cursor - play_pos) / audio_bytes_per_sample;
    327    
    328     if (frames < 0)
    329         frames += buffer_size;
    330 
    331     return audbuf_timecode - (int)((frames*1000.0) / effdsp);
     113    timeEndPeriod(1);
    332114}
    333115
    334 
    335116typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
    336117
    337 /*****************************************************************************
    338  * InitDirectSound: handle all the gory details of DirectSound initialisation
    339  *****************************************************************************/
    340 int AudioOutputDX::InitDirectSound()
     118int AudioOutputDXPrivate::InitDirectSound(void)
    341119{
    342 //    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
     120
    343121    LPFNDSC OurDirectSoundCreate;
    344122
    345     VERBOSE(VB_IMPORTANT, "initialising DirectSound");
     123    VERBOSE(VB_AUDIO, LOC + "initialising DirectSound");
    346124   
    347125    dsound_dll = LoadLibrary("DSOUND.DLL");
    348126    if (dsound_dll == NULL )
    349127    {
    350         VERBOSE(VB_IMPORTANT, "cannot open DSOUND.DLL" );
     128        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot open DSOUND.DLL" );
    351129        goto error;
    352130    }
    353131
    354     OurDirectSoundCreate = (LPFNDSC)
    355                                 GetProcAddress(dsound_dll, "DirectSoundCreate");
     132    OurDirectSoundCreate =
     133        (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate");
    356134    if (OurDirectSoundCreate == NULL)
    357135    {
    358         VERBOSE(VB_IMPORTANT, "GetProcAddress FAILED" );
     136        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProcAddress FAILED" );
    359137        goto error;
    360138    }
    361139
    362     VERBOSE(VB_IMPORTANT, "create DS object");
     140    // VERBOSE(VB_IMPORTANT, "create DS object");
    363141
    364142    /* Create the direct sound object */
    365143    if FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL))
    366144    {
    367         VERBOSE(VB_IMPORTANT, "cannot create a direct sound device" );
     145        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" );
    368146        goto error;
    369147    }
    370148
    371     VERBOSE(VB_IMPORTANT, "setting cooperative level");
     149    // VERBOSE(VB_IMPORTANT, "setting cooperative level");
    372150
    373151    /* Set DirectSound Cooperative level, ie what control we want over Windows
    374152     * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
     
    380158     * sound without any video, and so what window handle should we use ???
    381159     * The hack for now is to use the Desktop window handle - it seems to be
    382160     * working */
    383     if (IDirectSound_SetCooperativeLevel(dsobject,
     161    if FAILED(IDirectSound_SetCooperativeLevel(dsobject,
    384162                                         GetDesktopWindow(),
    385163                                         DSSCL_EXCLUSIVE))
    386164    {
    387         VERBOSE(VB_IMPORTANT, "cannot set direct sound cooperative level" );
     165        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot set DS cooperative level" );
    388166    }
    389167
    390     VERBOSE(VB_IMPORTANT, "creating notificatoin events");
     168    VERBOSE(VB_AUDIO, LOC + "initialised DirectSound");
    391169
    392     /* Then create the notification events */
    393     for (int i = 0; i < 4; i++)
    394         notif[i].hEventNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
    395 
    396     VERBOSE(VB_IMPORTANT, "initialised DirectSound");
    397 
    398170    return 0;
    399171
    400172 error:
     
    405177        dsound_dll = NULL;
    406178    }
    407179    return -1;
     180}
    408181
     182void AudioOutputDXPrivate::DestroyDSBuffer(void)
     183{
     184    if (dsbuffer)
     185    {
     186        VERBOSE(VB_AUDIO, LOC + "destroying DirectSound buffer");
     187        IDirectSoundBuffer_Stop(dsbuffer);
     188        IDirectSoundBuffer_Release(dsbuffer);
     189        dsbuffer = NULL;
     190    }
     191    writeCursor = 0;
     192    playStarted = false;       
    409193}
    410194
     195void AudioOutputDXPrivate::FillBuffer(unsigned char *buffer, int size)
     196{
     197    void *p_write_position, *p_wrap_around;
     198    DWORD l_bytes1, l_bytes2;
     199    HRESULT dsresult;
    411200
    412 /*****************************************************************************
    413  * CreateDSBuffer: Creates a direct sound buffer of the required format.
    414  *****************************************************************************
    415  * This function creates the buffer we'll use to play audio.
    416  * In DirectSound there are two kinds of buffers:
    417  * - the primary buffer: which is the actual buffer that the soundcard plays
    418  * - the secondary buffer(s): these buffers are the one actually used by
    419  *    applications and DirectSound takes care of mixing them into the primary.
    420  *
    421  * Once you create a secondary buffer, you cannot change its format anymore so
    422  * you have to release the current one and create another.
    423  *****************************************************************************/
    424 int AudioOutputDX::CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe)
     201    /* Before copying anything, we have to lock the buffer */
     202    dsresult = IDirectSoundBuffer_Lock(
     203                dsbuffer,                /* DS buffer */
     204                writeCursor,             /* Start offset */
     205                size,                    /* Number of bytes */
     206                &p_write_position,       /* Address of lock start */
     207                &l_bytes1,               /* Bytes locked before wrap */
     208                &p_wrap_around,          /* Buffer address (if wrap around) */
     209                &l_bytes2,               /* Count of bytes after wrap around */
     210                0);                      /* Flags */
     211    if (dsresult == DSERR_BUFFERLOST)
     212    {
     213        IDirectSoundBuffer_Restore(dsbuffer);
     214        dsresult = IDirectSoundBuffer_Lock(
     215                               dsbuffer,
     216                               writeCursor,
     217                               size,
     218                               &p_write_position,
     219                               &l_bytes1,
     220                               &p_wrap_around,
     221                               &l_bytes2,
     222                               0);
     223    }
     224    if (dsresult != DS_OK)
     225    {
     226        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot lock buffer, audio dropped");
     227        return;
     228    }
     229
     230    if (buffer == NULL)
     231    {
     232        VERBOSE(VB_AUDIO, LOC + "Writing null bytes");
     233   
     234        memset(p_write_position, 0, l_bytes1);
     235        if (p_wrap_around)
     236            memset(p_wrap_around, 0, l_bytes2);
     237           
     238        writeCursor += l_bytes1 + l_bytes2;
     239           
     240        while (writeCursor >= (DWORD)parent->soundcard_buffer_size)
     241            writeCursor -= parent->soundcard_buffer_size;
     242    }
     243    else   
     244    {
     245        memcpy(p_write_position, buffer, l_bytes1);
     246        if (p_wrap_around) {
     247            memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2);
     248        }
     249           
     250        writeCursor += l_bytes1 + l_bytes2;
     251           
     252        while (writeCursor >= (DWORD)parent->soundcard_buffer_size)
     253            writeCursor -= parent->soundcard_buffer_size;
     254    }
     255
     256    /* Now the data has been copied, unlock the buffer */
     257    IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1,
     258                              p_wrap_around, l_bytes2 );
     259}
     260
     261bool AudioOutputDXPrivate::StartPlayback(void)
    425262{
    426     WAVEFORMATEXTENSIBLE waveformat;
    427     DSBUFFERDESC         dsbdesc;
    428     unsigned int         i;
     263    HRESULT dsresult;
     264    lastValidTime = 0;
    429265
    430     /* First set the sound buffer format */
    431 /*    waveformat.dwChannelMask = 0;
    432     for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ )
     266    dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
     267    if (dsresult == DSERR_BUFFERLOST)
    433268    {
    434         if ( i_channels & pi_channels_in[i] )
    435             waveformat.dwChannelMask |= pi_channels_out[i];
    436     }*/
     269        IDirectSoundBuffer_Restore(dsbuffer);
     270        dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
     271    }
     272    if (dsresult != DS_OK)
     273    {
     274        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot start playing buffer" );
     275        playStarted=false;
     276        return false;
     277    }
     278    playStarted=true;
     279   
     280    // set buffer expiration time (adding 1ms due to integer math)
     281    lastValidTime = 1 + timeGetTime() + (parent->GetBufferedOnSoundcard() *
     282            1000 / (parent->audio_bytes_per_sample * parent->audio_samplerate));
    437283
    438 /*    switch( i_format )
     284    return true;
     285}
     286
     287void AudioOutputDXPrivate::StopPlayback(bool reset)
     288{
     289    IDirectSoundBuffer_Stop(dsbuffer);
     290    lastValidTime=0;
     291    if (reset)
    439292    {
    440     case VLC_FOURCC('s','p','d','i'):
    441         i_nb_channels = 2;
    442         / * To prevent channel re-ordering * /
    443         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
    444         waveformat.Format.wBitsPerSample = 16;
    445         waveformat.Samples.wValidBitsPerSample =
    446             waveformat.Format.wBitsPerSample;
    447         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
    448         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
    449         break;
     293        writeCursor = 0;
     294        IDirectSoundBuffer_SetCurrentPosition(dsbuffer, writeCursor);
     295        FillBuffer(NULL, parent->soundcard_buffer_size);
     296        playStarted=false;
     297    }
     298}
    450299
    451     case VLC_FOURCC('f','l','3','2'):
    452         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
    453         waveformat.Samples.wValidBitsPerSample =
    454             waveformat.Format.wBitsPerSample;
    455         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
    456         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
    457         break;
     300bool AudioOutputDX::OpenDevice(void)
     301{
     302    WAVEFORMATEXTENSIBLE wf;
     303    DSBUFFERDESC         dsbdesc;
    458304
    459     case VLC_FOURCC('s','1','6','l'):*/
    460         waveformat.Format.wBitsPerSample = audio_bits;
    461         waveformat.Samples.wValidBitsPerSample =
    462             waveformat.Format.wBitsPerSample;
    463         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
    464         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
    465 /*        break;
    466     }*/
     305    if (!m_priv->dsobject || !m_priv->dsound_dll)
     306    {
     307        Error("DirectSound initialization failed");
     308        return false;
     309    }
    467310
    468     waveformat.Format.nChannels = audio_channels;
    469     waveformat.Format.nSamplesPerSec = audio_samplerate;
    470     waveformat.Format.nBlockAlign =
    471                      waveformat.Format.wBitsPerSample / 8 * audio_channels;
    472     waveformat.Format.nAvgBytesPerSec =
    473                waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
     311    CloseDevice();
    474312
    475     audio_bytes_per_sample = waveformat.Format.wBitsPerSample / 8 * audio_channels;
     313    SetBlocking(true);
     314    fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144;
     315    if (audio_channels > 2)
     316        fragment_size *= 2;
     317    soundcard_buffer_size = kFramesNum * fragment_size;
     318    audio_bytes_per_sample = audio_bits / 8 * audio_channels;
     319    if (m_UseSPDIF && (audio_channels != 2))
     320    {
     321        Error("SPDIF passthru requires 2 channel data");
     322        return false;
     323    }
    476324
    477     VERBOSE(VB_IMPORTANT, "New format: " << audio_bits << "bits, " << audio_channels << "ch, " << audio_samplerate << "Hz");
     325    /* First set the sound buffer format */
     326    wf.Format.wFormatTag =
     327        (m_UseSPDIF) ? WAVE_FORMAT_DOLBY_AC3_SPDIF : WAVE_FORMAT_PCM;
     328    wf.Format.nChannels = audio_channels;
     329    wf.Format.nSamplesPerSec = audio_samplerate;
     330    wf.Format.nBlockAlign = audio_bytes_per_sample;
     331    wf.Format.nAvgBytesPerSec =
     332        wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
     333    wf.Format.wBitsPerSample = audio_bits;
     334    wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
     335    wf.SubFormat = (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF
     336                                : _KSDATAFORMAT_SUBTYPE_PCM;
     337 
     338    VERBOSE(VB_AUDIO, LOC + "New format: " << audio_bits << "bits, "
     339            << audio_channels << "ch, " << audio_samplerate << "Hz");
    478340
    479341    /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
    480342    if (audio_channels <= 2)
    481343    {
    482         waveformat.Format.cbSize = 0;
     344        wf.Format.cbSize = 0;
    483345    }
    484346    else
    485347    {
    486         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
    487         waveformat.Format.cbSize =
     348        wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
     349        wf.dwChannelMask = 0x003F;          // 0x003F = 5.1 channels
     350        wf.Format.cbSize =
    488351            sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    489352    }
    490353
    491 
    492354    /* Then fill in the direct sound descriptor */
    493355    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    494356    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    495357    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
    496                     | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
    497358                    | DSBCAPS_GLOBALFOCUS       /* Allows background playing */
    498359                    | DSBCAPS_LOCHARDWARE;      /* Needed for 5.1 on emu101k */
    499     dsbdesc.dwBufferBytes = FRAMES_NUM * audio_bits/8 * audio_channels;   /* buffer size */
    500     dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;
     360    if (!m_UseSPDIF)
     361        dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME;  /* Allow volume control */
     362    dsbdesc.dwBufferBytes = soundcard_buffer_size;   /* buffer size */
     363    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
    501364
    502     if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     365    if FAILED(IDirectSound_CreateSoundBuffer(
     366                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL))
    503367    {
     368        /* Vista does not support hardware mixing */
    504369        /* Try without DSBCAPS_LOCHARDWARE */
    505370        dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
    506         if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     371        HRESULT dsresult = IDirectSound_CreateSoundBuffer(
     372                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL);
     373        if FAILED(dsresult)
    507374        {
    508             return -1;
     375           Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult));
     376           return false;
    509377        }
    510         if ( !b_probe ) VERBOSE(VB_IMPORTANT, "couldn't use hardware sound buffer" );
     378        VERBOSE(VB_AUDIO, LOC + "Using software mixer" );
    511379    }
     380    VERBOSE(VB_AUDIO, LOC + "created DirectSound buffer");
    512381
    513     write_cursor = 0;
    514     buffer_size = FRAMES_NUM * audio_bits/8 * audio_channels;
     382    return true;
     383}
    515384
    516     /* Stop here if we were just probing */
    517     if ( b_probe )
    518     {
    519         IDirectSoundBuffer_Release(dsbuffer);
    520         dsbuffer = NULL;
    521         return 0;
    522     }
    523 
    524     /* Now the secondary buffer is created, we need to setup its position
    525      * notification */
    526     for (i = 0; i < 4; i++)
    527     {
    528         notif[i].dwOffset = buffer_size / 4 * i;
    529     }
    530 
    531     /* Get the IDirectSoundNotify interface */
    532     if FAILED(IDirectSoundBuffer_QueryInterface(dsbuffer, IID_IDirectSoundNotify, (LPVOID*) &dsnotify))
    533     {
    534         VERBOSE(VB_IMPORTANT, "cannot get IDirectSoundNotify interface" );
    535         goto error;
    536     }
    537 
    538     if FAILED(IDirectSoundNotify_SetNotificationPositions(dsnotify, 4, notif))
    539     {
    540         VERBOSE(VB_IMPORTANT, "cannot set position notification" );
    541         goto error;
    542     }
    543 
    544 //    p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;
    545 //    CheckReordering( p_aout, i_nb_channels );
    546 
    547     VERBOSE(VB_IMPORTANT, "created DirectSound buffer");
    548 
    549     return 0;
    550 
    551  error:
    552     DestroyDSBuffer();
    553     return -1;
     385void AudioOutputDX::CloseDevice(void)
     386{
     387    if (m_priv->dsbuffer)
     388        m_priv->DestroyDSBuffer();
    554389}
    555390
    556 
    557 /*****************************************************************************
    558  * DestroyDSBuffer
    559  *****************************************************************************
    560  * This function destroys the secondary buffer.
    561  *****************************************************************************/
    562 void AudioOutputDX::DestroyDSBuffer()
     391void AudioOutputDX::WriteAudio(unsigned char * buffer, int size)
    563392{
    564     if (dsnotify)
    565     {
    566         IDirectSoundNotify_Release(dsnotify);
    567         dsnotify = NULL;
    568     }
     393        if (size == 0)
     394        return;
    569395
    570     VERBOSE(VB_IMPORTANT, "destroying DirectSound buffer");
    571 
    572     if (dsbuffer)
     396    if (audio_channels == 6)
    573397    {
    574         IDirectSoundBuffer_Stop(dsbuffer);
    575         IDirectSoundBuffer_Release(dsbuffer);
    576         dsbuffer = NULL;
     398        // Linux and Windows have different 5.1 channel order conventions
     399        const uint kReorder[6] = {0,1,4,5,2,3};
     400        int abytes = audio_bits / 8;
     401        unsigned char p_tmp[24];
     402        unsigned char *obuf = buffer;
     403        for(int i = 0; i < size / audio_channels / abytes; i++)
     404        {
     405            for(int j = 0; j < audio_channels; j++)
     406            {
     407                for(int k = 0; k < abytes; k++)
     408                {
     409                    p_tmp[abytes * kReorder[j] + k] = buffer[abytes * j + k];
     410                }
     411            }
     412            memcpy(buffer, p_tmp, abytes * audio_channels);
     413            buffer += abytes * audio_channels;
     414        }
     415        buffer = obuf;
    577416    }
     417
     418    m_priv->FillBuffer(buffer, size);
     419    m_priv->StartPlayback();
    578420}
    579421
    580 /*****************************************************************************
    581  * FillBuffer: Fill in one of the direct sound frame buffers.
    582  *****************************************************************************
    583  * Returns VLC_SUCCESS on success.
    584  *****************************************************************************/
    585 int AudioOutputDX::FillBuffer(int frames, char *buffer)
     422void AudioOutputDX::Pause(bool pause)
    586423{
    587     DWORD play_pos, write_pos, end_write;
    588     void *p_write_position, *p_wrap_around;
    589     DWORD l_bytes1, l_bytes2;
    590     HRESULT dsresult;
    591 
    592     if (!awaiting_data && !paused)
     424    if (m_priv->dsbuffer)
    593425    {
    594    
    595 //        VERBOSE(VB_IMPORTANT, "checking buffer positions");
    596    
    597         dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
    598 
    599         if (dsresult != DS_OK)
     426        if (pause)
    600427        {
    601             VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    602             return -1;
     428            m_priv->StopPlayback(false);
     429            VERBOSE(VB_AUDIO, LOC + "buffer paused");
    603430        }
    604 
    605         end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;
    606 
    607         while (!(((play_pos < write_pos) && (write_cursor >= write_pos || write_cursor < play_pos) &&
    608                                         (end_write >= write_pos || end_write < play_pos)) ||
    609             ((play_pos < write_pos) && (write_cursor >= write_pos && write_cursor < play_pos) &&
    610                                         (end_write >= write_pos && end_write < play_pos))))
     431        else
    611432        {
    612 //            VERBOSE(VB_IMPORTANT, "cannot write audio data: " << write_cursor << " " << write_pos << " " << play_pos << " sleeping");
     433            if (! m_priv->StartPlayback())
     434                VERBOSE(VB_IMPORTANT, LOC_ERR + "unpause failed" );
     435            VERBOSE(VB_AUDIO, LOC + "buffer unpaused");
     436        }
     437    }
    613438
    614             HANDLE  notification_events[4];
     439    AudioOutputBase::Pause(pause);
     440}
    615441
    616             for(int i = 0; i < 4; i++)
    617                 notification_events[i] = notif[i].hEventNotify;
     442int AudioOutputDX::GetSpaceOnSoundcard(void) const
     443{
     444    if (!m_priv->playStarted)
     445        return soundcard_buffer_size;
    618446
    619                 WaitForMultipleObjects(4, notification_events, 0, INFINITE );
    620                
    621 //                VERBOSE(VB_IMPORTANT, "woken");
    622                
    623             dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
     447    HRESULT dsresult;
     448    DWORD play_pos, write_pos;
     449    DWORD currentTime = timeGetTime();
    624450
    625             if (dsresult != DS_OK)
    626             {
    627                 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    628                 return -1;
    629             }
    630 
    631             end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;
    632         }
     451    dsresult = IDirectSoundBuffer_GetCurrentPosition(
     452            m_priv->dsbuffer, &play_pos, &write_pos);
     453    if (dsresult != DS_OK)
     454    {
     455        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     456            return 0;
    633457    }
    634                                    
    635458
    636 //    VERBOSE(VB_IMPORTANT, "Locking buffer");
     459    int buffer_free = (int)play_pos - (int)m_priv->writeCursor;
     460    if ( buffer_free < 0 )
     461        buffer_free += soundcard_buffer_size;
    637462
    638     /* Before copying anything, we have to lock the buffer */
    639     dsresult = IDirectSoundBuffer_Lock(
    640                 dsbuffer,                                       /* DS buffer */
    641                 write_cursor,                                   /* Start offset */
    642                 frames * audio_bytes_per_sample,          /* Number of bytes */
    643                 &p_write_position,                  /* Address of lock start */
    644                 &l_bytes1,       /* Count of bytes locked before wrap around */
    645                 &p_wrap_around,            /* Buffer adress (if wrap around) */
    646                 &l_bytes2,               /* Count of bytes after wrap around */
    647                 0);                                                   /* Flags */
    648     if (dsresult == DSERR_BUFFERLOST)
     463    if (((write_pos > play_pos) && (m_priv->writeCursor <= write_pos)
     464                && (m_priv->writeCursor > play_pos))
     465        || ((write_pos < play_pos) && ((m_priv->writeCursor <= write_pos)
     466                || (play_pos < m_priv->writeCursor))))
    649467    {
    650         IDirectSoundBuffer_Restore(dsbuffer);
    651         dsresult = IDirectSoundBuffer_Lock(
    652                                dsbuffer,
    653                                write_cursor,
    654                                frames * audio_bytes_per_sample,
    655                                &p_write_position,
    656                                &l_bytes1,
    657                                &p_wrap_around,
    658                                &l_bytes2,
    659                                0);
     468        VERBOSE(VB_AUDIO, LOC + "buffer underrun(1) "
     469               << play_pos << " " << write_pos << " " << m_priv->writeCursor);
     470        // WriteCursor is in unsafe zone - stop playback for now
     471        // Next call to WriteAudio will restart the buffer
     472        m_priv->StopPlayback(false);
    660473    }
    661     if (dsresult != DS_OK)
     474    else if (m_priv->lastValidTime && (currentTime > m_priv->lastValidTime))
    662475    {
    663         VERBOSE(VB_IMPORTANT, "cannot lock buffer");
    664         return -1;
     476        VERBOSE(VB_AUDIO, LOC + "buffer underrun(2) "
     477               << play_pos << " " << write_pos << " " << m_priv->writeCursor
     478               << " " << currentTime - m_priv->lastValidTime);
     479        m_priv->StopPlayback(true);
    665480    }
    666481
    667     if (buffer == NULL)
    668     {
    669         VERBOSE(VB_IMPORTANT, "Writing null bytes");
    670    
    671         memset(p_write_position, 0, l_bytes1);
    672         if (p_wrap_around)
    673             memset(p_wrap_around, 0, l_bytes2);
    674            
    675            write_cursor += l_bytes1 + l_bytes2;
    676            
    677            while (write_cursor >= buffer_size)
    678                write_cursor -= buffer_size;
    679     }
    680 /*    else if ( p_aout->output.p_sys->b_chan_reorder )
    681     {
    682         /* Do the channel reordering here * /
     482    return buffer_free;
     483}
    683484
    684         if ( p_aout->output.output.i_format ==  VLC_FOURCC('s','1','6','l') )
    685           InterleaveS16( (int16_t *)p_buffer->p_buffer,
    686                          (int16_t *)p_write_position,
    687                          p_aout->output.p_sys->pi_chan_table,
    688                          aout_FormatNbChannels( &p_aout->output.output ) );
    689         else
    690           InterleaveFloat32( (float *)p_buffer->p_buffer,
    691                              (float *)p_write_position,
    692                              p_aout->output.p_sys->pi_chan_table,
    693                              aout_FormatNbChannels( &p_aout->output.output ) );
     485int AudioOutputDX::GetBufferedOnSoundcard(void) const
     486{
     487    if (!m_priv->playStarted)
     488        return 0;
    694489
    695         aout_BufferFree( p_buffer );
    696     }*/
    697     else   
     490    HRESULT dsresult;
     491    DWORD play_pos;
     492
     493    dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->dsbuffer,
     494            &play_pos, NULL);
     495    if (dsresult != DS_OK)
    698496    {
    699 //        VERBOSE(VB_IMPORTANT, "filling buffer");
    700    
    701         memcpy(p_write_position, buffer, l_bytes1);
    702 //        VERBOSE(VB_IMPORTANT, "buf_fill: " << l_bytes1 << " bytes, " << p_write_position << "-" << ((int)p_write_position + l_bytes1));
    703         if (p_wrap_around) {
    704             memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2);
    705 //        VERBOSE(VB_IMPORTANT, "buf_fill2: " << l_bytes2 << " bytes, " << p_wrap_around << "-" << ((int)p_wrap_around + l_bytes2));
    706         }
    707            
    708            write_cursor += l_bytes1 + l_bytes2;
    709            
    710            while (write_cursor >= buffer_size)
    711                write_cursor -= buffer_size;
     497        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     498            return 0;
    712499    }
    713500
    714 //    VERBOSE(VB_IMPORTANT, "unlocking buffer");
     501    int buffered = (int)m_priv->writeCursor - (int)play_pos;
     502    if (buffered <= 0)
     503        buffered += soundcard_buffer_size;
     504    return buffered;
     505}
    715506
    716     /* Now the data has been copied, unlock the buffer */
    717     IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1,
    718                               p_wrap_around, l_bytes2 );
     507int AudioOutputDX::GetVolumeChannel(int channel) const
     508{
     509    HRESULT dsresult;
     510    long dxVolume = 0;
     511    int volume;
    719512
     513    if (m_UseSPDIF)
     514        return 100;
    720515
    721 //    VERBOSE(VB_IMPORTANT, "finished fillbuffer");
     516    dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);
     517    if (dsresult != DS_OK)
     518        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get volume " << dxVolume );
    722519
    723     return 0;
     520    volume = (int)(pow(10,(float)dxVolume/20)*100);
     521    VERBOSE(VB_AUDIO, LOC + "got volume " << volume );
     522
     523    return volume;
    724524}
    725525
    726 // Wait for all data to finish playing
    727 void AudioOutputDX::Drain()
     526void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    728527{
    729     // TODO: Wait until all data has been played...
     528    HRESULT dsresult;
     529    float dbAtten = 20 * log10((float)volume/100);
     530    long dxVolume = (volume == 0) ? DSBVOLUME_MIN : 100 * dbAtten;
    730531
    731 }
     532    if (m_UseSPDIF)
     533        return;
    732534
    733 int AudioOutputDX::GetVolumeChannel(int channel) const
    734 {
    735     // Do nothing
    736     return 100;
     535    // dxVolume is attenuation in 100ths of a decibel
     536    dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);
     537
     538    if (dsresult != DS_OK)
     539        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set volume " << dxVolume );
     540   
     541    VERBOSE(VB_AUDIO, LOC + "set volume " << dxVolume );
    737542}
    738 void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    739 {
    740     // Do nothing
    741 }
    742543
     544/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    44814481        if (audioOutput)
    44824482        {
    44834483            audioOutput->SetStretchFactor(play_speed);
    4484 #ifdef USING_DIRECTX
    4485             audioOutput->Reset();
    4486 #endif
    44874484        }
    44884485    }
    44894486