Ticket #6538: aodx_21fixes.patch

File aodx_21fixes.patch, 38.0 KB (added by Jeff Lu <jll544@…>, 15 years ago)

Backport for DirectX audio on 0.21-fixes

  • 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// Qt headers
    125#include <qstring.h>
    136
    147// MythTV headers
    158#include "audiooutputbase.h"
    169
     10class AudioOutputDXPrivate;
     11
    1712class AudioOutputDX : public AudioOutputBase
    1813{
    19 public:
     14  friend class AudioOutputDXPrivate;
     15  public:
    2016    AudioOutputDX(QString laudio_main_device,
    2117                  QString laudio_passthru_device,
    2218                  int laudio_bits,
     
    2521                  bool lset_initial_vol, bool laudio_passthru);
    2622    virtual ~AudioOutputDX();
    2723
    28     /// BEGIN HACK HACK HACK HACK These need to actually be implemented!
    29     bool OpenDevice(void) { return false; }
    30     void CloseDevice(void) {}
    31     void WriteAudio(unsigned char*, int) {}
    32     virtual int getSpaceOnSoundcard(void) { return 0; }
    33     virtual int getBufferedOnSoundcard(void) { return 0; }
    34 #warning Several methods in AudioOutputDX need to be implemented...
    35     /// END HACK HACK HACK HACK
    36        
    37     virtual void Reset(void);
    38     virtual void Reconfigure(int audio_bits,
    39                              int audio_channels,
    40                              int audio_samplerate,
    41                              bool audio_passthru);
    42     virtual void SetBlocking(bool blocking);
    43 
    44     virtual bool AddSamples(char *buffer, int samples, long long timecode);
    45     virtual bool AddSamples(char *buffers[], int samples, long long timecode);
    46     virtual void SetEffDsp(int dsprate);
    47     virtual void SetTimecode(long long timecode);
    48 
    49     virtual bool GetPause(void);
    50     virtual void Pause(bool paused);
    51 
    52     virtual void Drain(void);
    53 
    54     virtual int GetAudiotime(void);
    55 
    5624    // Volume control
    5725    virtual int GetVolumeChannel(int channel); // Returns 0-100
    5826    virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol
    5927
    60  private:
    61     HINSTANCE dsound_dll;      /* handle of the opened dsound dll */
    62     LPDIRECTSOUND dsobject;
    63     LPDIRECTSOUNDBUFFER dsbuffer;   /* the sound buffer we use (direct sound
    64                                        * takes care of mixing all the
    65                                        * secondary buffers into the primary) */
    66     LPDIRECTSOUNDNOTIFY dsnotify;         /* the position notify interface */
    67     DSBPOSITIONNOTIFY notif[4];
     28  protected:
     29    virtual bool OpenDevice(void);
     30    virtual void CloseDevice(void);
     31    virtual void WriteAudio(unsigned char *aubuf, int size);
     32    virtual void Pause(bool pause);
     33    virtual inline int getSpaceOnSoundcard(void);
     34    virtual inline int getBufferedOnSoundcard(void);   
    6835
    69     DWORD write_cursor;
    70     DWORD buffer_size;
    71     bool blocking;
    72    
    73     bool awaiting_data;
    74  
    75     int effdsp; // from the recorded stream
    76     int audio_bytes_per_sample;
    77     int audio_bits;
    78     int audio_channels;
    79     int audbuf_timecode;    /* timecode of audio most recently placed into
    80                    buffer */
    81     bool can_hw_pause;
    82     bool paused;
    83    
    84     int InitDirectSound();
    85     int CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe);
    86     void DestroyDSBuffer();
    87     int FillBuffer(int frames, char *buffer);
     36  protected:
     37    AudioOutputDXPrivate    *m_priv;
     38    bool                     m_PlayStarted;
     39    DWORD                    m_WriteCursor;
     40    bool                     m_UseSPDIF;
     41    static const uint        kFramesNum;
    8842};
    8943
    9044#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
     
    2327/*****************************************************************************
    2428 * Useful macros
    2529 *****************************************************************************/
    26 #ifndef WAVE_FORMAT_IEEE_FLOAT
    27 #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
    28 #endif
    29 
    3030#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
    3131#   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
    3232#endif
     
    3535#define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
    3636#endif
    3737
    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 
    7938#ifndef _WAVEFORMATEXTENSIBLE_
    8039typedef struct {
    8140    WAVEFORMATEX    Format;
     
    9049} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
    9150#endif
    9251
    93 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9452DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9553DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
    9654
     55class AudioOutputDXPrivate
     56{
     57    public:
     58        AudioOutputDXPrivate() :
     59            dsound_dll(NULL),
     60            dsobject(NULL),
     61            dsbuffer(NULL)
     62        {
     63            InitDirectSound();
     64        }
    9765
     66        ~AudioOutputDXPrivate()
     67        {
     68            DestroyDSBuffer();
     69
     70            if (dsobject)
     71                IDirectSound_Release(dsobject);
     72   
     73            if (dsound_dll)
     74               FreeLibrary(dsound_dll);
     75        }
     76
     77        int InitDirectSound(void);
     78        void DestroyDSBuffer(void);
     79        bool StartPlayback(void);
     80
     81    public:
     82        HINSTANCE dsound_dll;
     83        LPDIRECTSOUND dsobject;
     84        LPDIRECTSOUNDBUFFER dsbuffer;
     85};
     86
     87
    9888AudioOutputDX::AudioOutputDX(
    9989    QString laudio_main_device,  QString           laudio_passthru_device,
    10090    int     laudio_bits,         int               laudio_channels,
     
    10494                    laudio_bits,        laudio_channels,
    10595                    laudio_samplerate,  lsource,
    10696                    lset_initial_vol,   laudio_passthru),
    107     dsound_dll(NULL),
    108     dsobject(NULL),
    109     dsbuffer(NULL),
    110     write_cursor(0),
    111     buffer_size(0),
    112     blocking(false),
    113     awaiting_data(false),
    114     effdsp(0),                 /* Should this be audio_bits ? */
    115     audio_bytes_per_sample(0), /* ACK! hides version in AudioOutputBase */
    116     audio_bits(0),             /* ACK! hides version in AudioOutputBase */
    117     audio_channels(0),         /* ACK! hides version in AudioOutputBase */
    118     audbuf_timecode(0),
    119     can_hw_pause(false),
    120     paused(false)
     97    m_priv(new AudioOutputDXPrivate()),
     98    m_PlayStarted(false),
     99    m_WriteCursor(0),
     100    m_UseSPDIF(laudio_passthru)
    121101{
    122     InitDirectSound();
    123    
    124102    Reconfigure(laudio_bits,       laudio_channels,
    125103                laudio_samplerate, laudio_passthru);
    126104}
    127105
    128 void AudioOutputDX::SetBlocking(bool blocking)
    129 {
    130     // FIXME: kedl: not sure what else could be required here?
    131 }
    132 
    133 void AudioOutputDX::Reconfigure(int audio_bits,
    134                                 int audio_channels,
    135                                 int audio_samplerate,
    136                                 bool audio_passthru)
    137 {
    138     if (dsbuffer)
    139         DestroyDSBuffer();
    140        
    141     CreateDSBuffer(audio_bits, audio_channels, audio_samplerate, false);
    142    
    143     awaiting_data = true;
    144     paused = true;
    145        
    146     effdsp = audio_samplerate;
    147     this->audio_bits = audio_bits;
    148     this->audio_channels = audio_channels;
    149     this->audio_passthru = audio_passthru;
    150 }
    151 
    152106AudioOutputDX::~AudioOutputDX()
    153107{
    154     DestroyDSBuffer();
     108    KillAudio();
    155109
    156     /* release the DirectSound object */
    157     if (dsobject)
    158         IDirectSound_Release(dsobject);
    159    
    160     /* free DSOUND.DLL */
    161     if (dsound_dll)
    162        FreeLibrary(dsound_dll);
    163 }
    164 
    165 void AudioOutputDX::Reset(void)
    166 {
    167     audbuf_timecode = 0;
    168     awaiting_data = true;
    169     write_cursor = 0;
    170 
    171     if (dsbuffer)   
     110    if (m_priv)
    172111    {
    173         IDirectSoundBuffer_Stop(dsbuffer);
    174         IDirectSoundBuffer_SetCurrentPosition(dsbuffer, 0);
     112        delete m_priv;
     113        m_priv = NULL;
    175114    }
    176 
    177115}
    178116
    179 bool AudioOutputDX::AddSamples(char *buffer, int frames, long long timecode)
    180 {
    181     FillBuffer(frames, buffer);
    182 
    183     HRESULT dsresult;
    184    
    185     if (awaiting_data)
    186     {
    187 //        dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
    188 //        if (dsresult == DSERR_BUFFERLOST)
    189 //        {
    190 //            IDirectSoundBuffer_Restore(dsbuffer);
    191 //            dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
    192 //        }
    193 //        if (dsresult != DS_OK)
    194 //        {
    195 //            VERBOSE(VB_IMPORTANT, "cannot start playing buffer" );
    196 //        }
    197        
    198         awaiting_data = false;
    199     }
    200 
    201 
    202    
    203 //    VERBOSE(VB_IMPORTANT, "add_samples(a) " << frames << " " << timecode);
    204 
    205     if (timecode < 0)
    206         timecode = audbuf_timecode; // add to current timecode
    207    
    208     /* we want the time at the end -- but the file format stores
    209        time at the start of the chunk. */
    210     audbuf_timecode = timecode + (int)((frames*1000.0) / effdsp);
    211 
    212     return true;
    213 }
    214 
    215 
    216 bool AudioOutputDX::AddSamples(char *buffers[], int frames, long long timecode)
    217 {
    218 //    VERBOSE(VB_IMPORTANT, "add_samples(b) " << frames << " " << timecode);
    219 
    220 /*    int err;
    221     int waud=0;
    222     int audio_bytes = audio_bits / 8;
    223     int audbufsize = frames*audio_bytes*audio_channels;
    224     char *audiobuffer = (char *) calloc(1,audbufsize);
    225 
    226     if (audiobuffer==NULL)
    227     {
    228         fprintf(stderr, "couldn't get memory to write audio to artsd\n");
    229     return;
    230     }
    231 
    232     if (pcm_handle == NULL)
    233     {
    234         free(audiobuffer);
    235         return;
    236     }
    237 
    238     for (int itemp = 0; itemp < frames*audio_bytes; itemp+=audio_bytes)
    239     {
    240         for(int chan = 0; chan < audio_channels; chan++)
    241         {
    242             audiobuffer[waud++] = buffers[chan][itemp];
    243             if (audio_bits == 16)
    244                 audiobuffer[waud++] = buffers[chan][itemp+1];
    245             if (waud >= audbufsize)
    246                 waud -= audbufsize;
    247         }
    248     }
    249 
    250     err = arts_write(pcm_handle, audiobuffer, frames*4);
    251     free(audiobuffer);
    252 
    253     if (err < 0)
    254     {
    255         fprintf(stderr, "arts_write error: %s\n", arts_error_text(err));
    256         return;
    257     }
    258 
    259     if (timecode < 0)
    260         timecode = audbuf_timecode; // add to current timecode*/
    261    
    262     /* we want the time at the end -- but the file format stores
    263        time at the start of the chunk. */
    264     //audbuf_timecode = timecode + (int)((frames*100000.0) / effdsp);
    265 
    266     return true;
    267 }
    268 
    269 void AudioOutputDX::SetTimecode(long long timecode)
    270 {
    271     audbuf_timecode = timecode;
    272 }
    273 
    274 void AudioOutputDX::SetEffDsp(int dsprate)
    275 {
    276     VERBOSE(VB_IMPORTANT, "setting dsprate = " << dsprate);
    277    
    278     HRESULT dsresult;
    279 
    280     dsresult = IDirectSoundBuffer_SetFrequency(dsbuffer, dsprate / 100);
    281 
    282     if (dsresult != DS_OK)
    283     {
    284         VERBOSE(VB_IMPORTANT, "cannot set frequency");
    285     }
    286 
    287     effdsp = dsprate / 100;
    288 }
    289 
    290 bool AudioOutputDX::GetPause(void)
    291 {
    292     return paused;
    293 }
    294 
    295 void AudioOutputDX::Pause(bool pause)
    296 {
    297     HRESULT dsresult;
    298 
    299     VERBOSE(VB_IMPORTANT, "pause: " << pause);
    300 
    301     if (pause == paused)
    302         return;
    303        
    304     if (paused)
    305     {
    306         VERBOSE(VB_IMPORTANT, "unpausing");
    307    
    308         dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
    309         if (dsresult == DSERR_BUFFERLOST)
    310         {
    311             IDirectSoundBuffer_Restore(dsbuffer);
    312             dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
    313         }
    314         if (dsresult != DS_OK)
    315         {
    316             VERBOSE(VB_IMPORTANT, "cannot start playing buffer" );
    317         }
    318     }
    319     else
    320     {
    321         VERBOSE(VB_IMPORTANT, "pausing");
    322    
    323         IDirectSoundBuffer_Stop(dsbuffer);
    324     }
    325 
    326     paused = pause;
    327 }
    328 
    329 int AudioOutputDX::GetAudiotime(void)
    330 {
    331     DWORD play_pos;
    332     HRESULT dsresult;
    333 
    334     dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, NULL);
    335 
    336     if (dsresult != DS_OK)
    337     {
    338         VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    339         return -1;
    340     }
    341 
    342     int frames = (write_cursor - play_pos) / audio_bytes_per_sample;
    343    
    344     if (frames < 0)
    345         frames += buffer_size;
    346 
    347     return audbuf_timecode - (int)((frames*1000.0) / effdsp);
    348 }
    349 
    350 
    351117typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
    352118
    353 /*****************************************************************************
    354  * InitDirectSound: handle all the gory details of DirectSound initialisation
    355  *****************************************************************************/
    356 int AudioOutputDX::InitDirectSound()
     119int AudioOutputDXPrivate::InitDirectSound(void)
    357120{
    358 //    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
     121
    359122    LPFNDSC OurDirectSoundCreate;
    360123
    361     VERBOSE(VB_IMPORTANT, "initialising DirectSound");
     124    VERBOSE(VB_AUDIO, LOC + "initialising DirectSound");
    362125   
    363126    dsound_dll = LoadLibrary("DSOUND.DLL");
    364127    if (dsound_dll == NULL )
    365128    {
    366         VERBOSE(VB_IMPORTANT, "cannot open DSOUND.DLL" );
     129        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot open DSOUND.DLL" );
    367130        goto error;
    368131    }
    369132
    370     OurDirectSoundCreate = (LPFNDSC)
    371                                 GetProcAddress(dsound_dll, "DirectSoundCreate");
     133    OurDirectSoundCreate =
     134        (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate");
    372135    if (OurDirectSoundCreate == NULL)
    373136    {
    374         VERBOSE(VB_IMPORTANT, "GetProcAddress FAILED" );
     137        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProcAddress FAILED" );
    375138        goto error;
    376139    }
    377140
    378     VERBOSE(VB_IMPORTANT, "create DS object");
     141    // VERBOSE(VB_IMPORTANT, "create DS object");
    379142
    380143    /* Create the direct sound object */
    381144    if FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL))
    382145    {
    383         VERBOSE(VB_IMPORTANT, "cannot create a direct sound device" );
     146        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" );
    384147        goto error;
    385148    }
    386149
    387     VERBOSE(VB_IMPORTANT, "setting cooperative level");
     150    // VERBOSE(VB_IMPORTANT, "setting cooperative level");
    388151
    389152    /* Set DirectSound Cooperative level, ie what control we want over Windows
    390153     * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
     
    396159     * sound without any video, and so what window handle should we use ???
    397160     * The hack for now is to use the Desktop window handle - it seems to be
    398161     * working */
    399     if (IDirectSound_SetCooperativeLevel(dsobject,
     162    if FAILED(IDirectSound_SetCooperativeLevel(dsobject,
    400163                                         GetDesktopWindow(),
    401164                                         DSSCL_EXCLUSIVE))
    402165    {
    403         VERBOSE(VB_IMPORTANT, "cannot set direct sound cooperative level" );
     166        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot set DS cooperative level" );
    404167    }
    405168
    406     VERBOSE(VB_IMPORTANT, "creating notificatoin events");
     169    VERBOSE(VB_AUDIO, LOC + "initialised DirectSound");
    407170
    408     /* Then create the notification events */
    409     for (int i = 0; i < 4; i++)
    410         notif[i].hEventNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
    411 
    412     VERBOSE(VB_IMPORTANT, "initialised DirectSound");
    413 
    414171    return 0;
    415172
    416173 error:
     
    421178        dsound_dll = NULL;
    422179    }
    423180    return -1;
     181}
    424182
     183void AudioOutputDXPrivate::DestroyDSBuffer(void)
     184{
     185    if (dsbuffer)
     186    {
     187        VERBOSE(VB_AUDIO, LOC + "destroying DirectSound buffer");
     188        IDirectSoundBuffer_Stop(dsbuffer);
     189        IDirectSoundBuffer_Release(dsbuffer);
     190        dsbuffer = NULL;
     191    }
    425192}
    426193
    427 
    428 /*****************************************************************************
    429  * CreateDSBuffer: Creates a direct sound buffer of the required format.
    430  *****************************************************************************
    431  * This function creates the buffer we'll use to play audio.
    432  * In DirectSound there are two kinds of buffers:
    433  * - the primary buffer: which is the actual buffer that the soundcard plays
    434  * - the secondary buffer(s): these buffers are the one actually used by
    435  *    applications and DirectSound takes care of mixing them into the primary.
    436  *
    437  * Once you create a secondary buffer, you cannot change its format anymore so
    438  * you have to release the current one and create another.
    439  *****************************************************************************/
    440 int AudioOutputDX::CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe)
     194bool AudioOutputDXPrivate::StartPlayback(void)
    441195{
    442     WAVEFORMATEXTENSIBLE waveformat;
    443     DSBUFFERDESC         dsbdesc;
    444     unsigned int         i;
     196    HRESULT dsresult;
    445197
    446     /* First set the sound buffer format */
    447 /*    waveformat.dwChannelMask = 0;
    448     for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ )
     198    dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
     199    if (dsresult == DSERR_BUFFERLOST)
    449200    {
    450         if ( i_channels & pi_channels_in[i] )
    451             waveformat.dwChannelMask |= pi_channels_out[i];
    452     }*/
    453 
    454 /*    switch( i_format )
     201        IDirectSoundBuffer_Restore(dsbuffer);
     202        dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
     203    }
     204    if (dsresult != DS_OK)
    455205    {
    456     case VLC_FOURCC('s','p','d','i'):
    457         i_nb_channels = 2;
    458         / * To prevent channel re-ordering * /
    459         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
    460         waveformat.Format.wBitsPerSample = 16;
    461         waveformat.Samples.wValidBitsPerSample =
    462             waveformat.Format.wBitsPerSample;
    463         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
    464         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
    465         break;
     206        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot start playing buffer" );
     207        return false;
     208    }
     209    else
     210        return true;
     211}
    466212
    467     case VLC_FOURCC('f','l','3','2'):
    468         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
    469         waveformat.Samples.wValidBitsPerSample =
    470             waveformat.Format.wBitsPerSample;
    471         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
    472         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
    473         break;
     213bool AudioOutputDX::OpenDevice(void)
     214{
     215    WAVEFORMATEXTENSIBLE wf;
     216    DSBUFFERDESC         dsbdesc;
    474217
    475     case VLC_FOURCC('s','1','6','l'):*/
    476         waveformat.Format.wBitsPerSample = audio_bits;
    477         waveformat.Samples.wValidBitsPerSample =
    478             waveformat.Format.wBitsPerSample;
    479         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
    480         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
    481 /*        break;
    482     }*/
     218    if (!m_priv->dsobject || !m_priv->dsound_dll)
     219    {
     220        Error("DirectSound initialization failed");
     221        return false;
     222    }
    483223
    484     waveformat.Format.nChannels = audio_channels;
    485     waveformat.Format.nSamplesPerSec = audio_samplerate;
    486     waveformat.Format.nBlockAlign =
    487                      waveformat.Format.wBitsPerSample / 8 * audio_channels;
    488     waveformat.Format.nAvgBytesPerSec =
    489                waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
     224    CloseDevice();
    490225
    491     audio_bytes_per_sample = waveformat.Format.wBitsPerSample / 8 * audio_channels;
     226    SetBlocking(true);
     227    fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144;
     228    if (audio_channels > 2)
     229        fragment_size *= 2;
     230    soundcard_buffer_size = kFramesNum * fragment_size;
     231    audio_bytes_per_sample = audio_bits / 8 * audio_channels;
     232    if (m_UseSPDIF && (audio_channels != 2))
     233    {
     234        Error("SPDIF passthru requires 2 channel data");
     235        return false;
     236    }
    492237
    493     VERBOSE(VB_IMPORTANT, "New format: " << audio_bits << "bits, " << audio_channels << "ch, " << audio_samplerate << "Hz");
     238    /* First set the sound buffer format */
     239    wf.Format.wFormatTag =
     240        (m_UseSPDIF) ? WAVE_FORMAT_DOLBY_AC3_SPDIF : WAVE_FORMAT_PCM;
     241    wf.Format.nChannels = audio_channels;
     242    wf.Format.nSamplesPerSec = audio_samplerate;
     243    wf.Format.nBlockAlign = audio_bytes_per_sample;
     244    wf.Format.nAvgBytesPerSec =
     245        wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
     246    wf.Format.wBitsPerSample = audio_bits;
     247    wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
     248    wf.SubFormat =
     249        (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF : _KSDATAFORMAT_SUBTYPE_PCM;
    494250
     251    VERBOSE(VB_AUDIO, LOC + "New format: " << audio_bits << "bits, "
     252            << audio_channels << "ch, " << audio_samplerate << "Hz");
     253
    495254    /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
    496255    if (audio_channels <= 2)
    497256    {
    498         waveformat.Format.cbSize = 0;
     257        wf.Format.cbSize = 0;
    499258    }
    500259    else
    501260    {
    502         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
    503         waveformat.Format.cbSize =
     261        wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
     262        wf.dwChannelMask = 0x003F;          // 0x003F = 5.1 channels
     263        wf.Format.cbSize =
    504264            sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    505265    }
    506266
    507 
    508267    /* Then fill in the direct sound descriptor */
    509268    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    510269    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    511270    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
    512                     | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
    513271                    | DSBCAPS_GLOBALFOCUS       /* Allows background playing */
    514272                    | DSBCAPS_LOCHARDWARE;      /* Needed for 5.1 on emu101k */
    515     dsbdesc.dwBufferBytes = FRAMES_NUM * audio_bits/8 * audio_channels;   /* buffer size */
    516     dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;
     273    if (!m_UseSPDIF)
     274        dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME;  /* Allow volume control */
     275    dsbdesc.dwBufferBytes = soundcard_buffer_size;   /* buffer size */
     276    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
    517277
    518     if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     278    if FAILED(IDirectSound_CreateSoundBuffer(
     279                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL))
    519280    {
     281        /* Vista does not support hardware mixing */
    520282        /* Try without DSBCAPS_LOCHARDWARE */
    521283        dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
    522         if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     284        HRESULT dsresult = IDirectSound_CreateSoundBuffer(
     285                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL);
     286        if FAILED(dsresult)
    523287        {
    524             return -1;
     288           Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult));
     289           return false;
    525290        }
    526         if ( !b_probe ) VERBOSE(VB_IMPORTANT, "couldn't use hardware sound buffer" );
     291        VERBOSE(VB_AUDIO, LOC + "Using software mixer" );
    527292    }
     293    VERBOSE(VB_AUDIO, LOC + "created DirectSound buffer");
    528294
    529     write_cursor = 0;
    530     buffer_size = FRAMES_NUM * audio_bits/8 * audio_channels;
    531 
    532     /* Stop here if we were just probing */
    533     if ( b_probe )
    534     {
    535         IDirectSoundBuffer_Release(dsbuffer);
    536         dsbuffer = NULL;
    537         return 0;
    538     }
    539 
    540     /* Now the secondary buffer is created, we need to setup its position
    541      * notification */
    542     for (i = 0; i < 4; i++)
    543     {
    544         notif[i].dwOffset = buffer_size / 4 * i;
    545     }
    546 
    547     /* Get the IDirectSoundNotify interface */
    548     if FAILED(IDirectSoundBuffer_QueryInterface(dsbuffer, IID_IDirectSoundNotify, (LPVOID*) &dsnotify))
    549     {
    550         VERBOSE(VB_IMPORTANT, "cannot get IDirectSoundNotify interface" );
    551         goto error;
    552     }
    553 
    554     if FAILED(IDirectSoundNotify_SetNotificationPositions(dsnotify, 4, notif))
    555     {
    556         VERBOSE(VB_IMPORTANT, "cannot set position notification" );
    557         goto error;
    558     }
    559 
    560 //    p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;
    561 //    CheckReordering( p_aout, i_nb_channels );
    562 
    563     VERBOSE(VB_IMPORTANT, "created DirectSound buffer");
    564 
    565     return 0;
    566 
    567  error:
    568     DestroyDSBuffer();
    569     return -1;
     295    return true;
    570296}
    571297
    572 
    573 /*****************************************************************************
    574  * DestroyDSBuffer
    575  *****************************************************************************
    576  * This function destroys the secondary buffer.
    577  *****************************************************************************/
    578 void AudioOutputDX::DestroyDSBuffer()
     298void AudioOutputDX::CloseDevice(void)
    579299{
    580     if (dsnotify)
    581     {
    582         IDirectSoundNotify_Release(dsnotify);
    583         dsnotify = NULL;
    584     }
    585 
    586     VERBOSE(VB_IMPORTANT, "destroying DirectSound buffer");
    587 
    588     if (dsbuffer)
    589     {
    590         IDirectSoundBuffer_Stop(dsbuffer);
    591         IDirectSoundBuffer_Release(dsbuffer);
    592         dsbuffer = NULL;
    593     }
     300    if (m_priv->dsbuffer)
     301        m_priv->DestroyDSBuffer();
     302    m_WriteCursor = 0;
     303    m_PlayStarted = false;
    594304}
    595305
    596 /*****************************************************************************
    597  * FillBuffer: Fill in one of the direct sound frame buffers.
    598  *****************************************************************************
    599  * Returns VLC_SUCCESS on success.
    600  *****************************************************************************/
    601 int AudioOutputDX::FillBuffer(int frames, char *buffer)
     306void AudioOutputDX::WriteAudio(unsigned char * buffer, int size)
    602307{
    603     DWORD play_pos, write_pos, end_write;
    604     void *p_write_position, *p_wrap_around;
    605     DWORD l_bytes1, l_bytes2;
    606     HRESULT dsresult;
     308        if (size == 0)
     309        return;
    607310
    608     if (!awaiting_data && !paused)
     311    if (audio_channels == 6)
    609312    {
    610    
    611 //        VERBOSE(VB_IMPORTANT, "checking buffer positions");
    612    
    613         dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
    614 
    615         if (dsresult != DS_OK)
     313        // Linux and Windows have different 5.1 channel order conventions
     314        const uint kReorder[6] = {0,1,4,5,2,3};
     315        int abytes = audio_bits / 8;
     316        unsigned char p_tmp[24];
     317        unsigned char *obuf = buffer;
     318        for(int i = 0; i < size / audio_channels / abytes; i++)
    616319        {
    617             VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    618             return -1;
    619         }
    620 
    621         end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;
    622 
    623         while (!(((play_pos < write_pos) && (write_cursor >= write_pos || write_cursor < play_pos) &&
    624                                         (end_write >= write_pos || end_write < play_pos)) ||
    625             ((play_pos < write_pos) && (write_cursor >= write_pos && write_cursor < play_pos) &&
    626                                         (end_write >= write_pos && end_write < play_pos))))
    627         {
    628 //            VERBOSE(VB_IMPORTANT, "cannot write audio data: " << write_cursor << " " << write_pos << " " << play_pos << " sleeping");
    629 
    630             HANDLE  notification_events[4];
    631 
    632             for(int i = 0; i < 4; i++)
    633                 notification_events[i] = notif[i].hEventNotify;
    634 
    635                 WaitForMultipleObjects(4, notification_events, 0, INFINITE );
    636                
    637 //                VERBOSE(VB_IMPORTANT, "woken");
    638                
    639             dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
    640 
    641             if (dsresult != DS_OK)
     320            for(int j = 0; j < audio_channels; j++)
    642321            {
    643                 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    644                 return -1;
     322                for(int k = 0; k < abytes; k++)
     323                {
     324                    p_tmp[abytes * kReorder[j] + k] = buffer[abytes * j + k];
     325                }
    645326            }
    646 
    647             end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;
     327            memcpy(buffer, p_tmp, abytes * audio_channels);
     328            buffer += abytes * audio_channels;
    648329        }
     330        buffer = obuf;
    649331    }
    650                                    
    651332
    652 //    VERBOSE(VB_IMPORTANT, "Locking buffer");
     333    void *p_write_position, *p_wrap_around;
     334    DWORD l_bytes1, l_bytes2;
     335    HRESULT dsresult;
    653336
    654337    /* Before copying anything, we have to lock the buffer */
    655338    dsresult = IDirectSoundBuffer_Lock(
    656                 dsbuffer,                                       /* DS buffer */
    657                 write_cursor,                                   /* Start offset */
    658                 frames * audio_bytes_per_sample,          /* Number of bytes */
     339                m_priv->dsbuffer,        /* DS buffer */
     340                m_WriteCursor,           /* Start offset */
     341                size,                    /* Number of bytes */
    659342                &p_write_position,                  /* Address of lock start */
    660343                &l_bytes1,       /* Count of bytes locked before wrap around */
    661344                &p_wrap_around,            /* Buffer adress (if wrap around) */
    662345                &l_bytes2,               /* Count of bytes after wrap around */
    663                 0);                                                   /* Flags */
     346                0);                                                 /* Flags */
    664347    if (dsresult == DSERR_BUFFERLOST)
    665348    {
    666         IDirectSoundBuffer_Restore(dsbuffer);
     349        IDirectSoundBuffer_Restore(m_priv->dsbuffer);
    667350        dsresult = IDirectSoundBuffer_Lock(
    668                                dsbuffer,
    669                                write_cursor,
    670                                frames * audio_bytes_per_sample,
     351                               m_priv->dsbuffer,
     352                               m_WriteCursor,
     353                               size,
    671354                               &p_write_position,
    672355                               &l_bytes1,
    673356                               &p_wrap_around,
     
    676359    }
    677360    if (dsresult != DS_OK)
    678361    {
    679         VERBOSE(VB_IMPORTANT, "cannot lock buffer");
    680         return -1;
     362        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot lock buffer, audio dropped");
     363        return;
    681364    }
    682365
    683366    if (buffer == NULL)
    684367    {
    685         VERBOSE(VB_IMPORTANT, "Writing null bytes");
     368        VERBOSE(VB_AUDIO, LOC + "Writing null bytes");
    686369   
    687370        memset(p_write_position, 0, l_bytes1);
    688371        if (p_wrap_around)
    689372            memset(p_wrap_around, 0, l_bytes2);
    690373           
    691            write_cursor += l_bytes1 + l_bytes2;
     374        m_WriteCursor += l_bytes1 + l_bytes2;
    692375           
    693            while (write_cursor >= buffer_size)
    694                write_cursor -= buffer_size;
     376        while (m_WriteCursor >= (DWORD)soundcard_buffer_size)
     377            m_WriteCursor -= soundcard_buffer_size;
    695378    }
    696 /*    else if ( p_aout->output.p_sys->b_chan_reorder )
    697     {
    698         /* Do the channel reordering here * /
    699 
    700         if ( p_aout->output.output.i_format ==  VLC_FOURCC('s','1','6','l') )
    701           InterleaveS16( (int16_t *)p_buffer->p_buffer,
    702                          (int16_t *)p_write_position,
    703                          p_aout->output.p_sys->pi_chan_table,
    704                          aout_FormatNbChannels( &p_aout->output.output ) );
    705         else
    706           InterleaveFloat32( (float *)p_buffer->p_buffer,
    707                              (float *)p_write_position,
    708                              p_aout->output.p_sys->pi_chan_table,
    709                              aout_FormatNbChannels( &p_aout->output.output ) );
    710 
    711         aout_BufferFree( p_buffer );
    712     }*/
    713379    else   
    714380    {
    715 //        VERBOSE(VB_IMPORTANT, "filling buffer");
    716    
    717381        memcpy(p_write_position, buffer, l_bytes1);
    718 //        VERBOSE(VB_IMPORTANT, "buf_fill: " << l_bytes1 << " bytes, " << p_write_position << "-" << ((int)p_write_position + l_bytes1));
    719382        if (p_wrap_around) {
    720383            memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2);
    721 //        VERBOSE(VB_IMPORTANT, "buf_fill2: " << l_bytes2 << " bytes, " << p_wrap_around << "-" << ((int)p_wrap_around + l_bytes2));
    722384        }
    723385           
    724            write_cursor += l_bytes1 + l_bytes2;
     386        m_WriteCursor += l_bytes1 + l_bytes2;
    725387           
    726            while (write_cursor >= buffer_size)
    727                write_cursor -= buffer_size;
     388        while (m_WriteCursor >= (DWORD)soundcard_buffer_size)
     389            m_WriteCursor -= soundcard_buffer_size;
    728390    }
    729391
    730 //    VERBOSE(VB_IMPORTANT, "unlocking buffer");
    731 
    732392    /* Now the data has been copied, unlock the buffer */
    733     IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1,
     393    IDirectSoundBuffer_Unlock(m_priv->dsbuffer, p_write_position, l_bytes1,
    734394                              p_wrap_around, l_bytes2 );
    735395
     396    m_PlayStarted = m_priv->StartPlayback();
     397}
    736398
    737 //    VERBOSE(VB_IMPORTANT, "finished fillbuffer");
     399void AudioOutputDX::Pause(bool pause)
     400{
     401    if (m_priv->dsbuffer)
     402    {
     403        if (pause)
     404        {
     405            IDirectSoundBuffer_Stop(m_priv->dsbuffer);
     406            VERBOSE(VB_AUDIO, LOC + "buffer paused");
     407        }
     408        else
     409        {
     410            if (! m_priv->StartPlayback())
     411                VERBOSE(VB_IMPORTANT, LOC_ERR + "unpause failed" );
     412            VERBOSE(VB_AUDIO, LOC + "buffer unpaused");
     413        }
     414    }
    738415
    739     return 0;
     416    AudioOutputBase::Pause(pause);
    740417}
    741418
    742 // Wait for all data to finish playing
    743 void AudioOutputDX::Drain()
     419inline int AudioOutputDX::getSpaceOnSoundcard(void)
    744420{
    745     // TODO: Wait until all data has been played...
     421    HRESULT dsresult;
     422    DWORD play_pos, write_pos;
    746423
     424    dsresult = IDirectSoundBuffer_GetCurrentPosition(
     425            m_priv->dsbuffer, &play_pos, &write_pos);
     426    if (dsresult != DS_OK)
     427    {
     428        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     429            return 0;
     430    }
     431
     432    if (!m_PlayStarted)
     433        return soundcard_buffer_size;
     434    else
     435    {
     436        int buffer_free = (int)play_pos - (int)m_WriteCursor;
     437        if ( buffer_free < 0 )
     438            buffer_free += soundcard_buffer_size;
     439
     440        if (((write_pos > play_pos) && (m_WriteCursor <= write_pos)
     441                    && (m_WriteCursor > play_pos))
     442            || ((write_pos < play_pos) && ((m_WriteCursor <= write_pos)
     443                    || (play_pos < m_WriteCursor))))
     444        {
     445            VERBOSE (VB_AUDIO, LOC + "buffer underrun "
     446                   << play_pos << " " << write_pos << " " << m_WriteCursor);
     447            // WriteCursor is in unsafe zone - stop playback for now
     448            // Next call to WriteAudio will restart the buffer
     449            IDirectSoundBuffer_Stop(m_priv->dsbuffer);
     450        }
     451        return buffer_free;
     452    }
    747453}
    748454
     455inline int AudioOutputDX::getBufferedOnSoundcard(void)
     456{
     457    HRESULT dsresult;
     458    DWORD play_pos;
     459
     460    dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->dsbuffer, &play_pos, NULL);
     461    if (dsresult != DS_OK)
     462    {
     463        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     464            return 0;
     465    }
     466
     467    int buffered = (int)m_WriteCursor - (int)play_pos;
     468    if ( buffered < 0 )
     469        buffered += soundcard_buffer_size;
     470    return buffered;
     471}
     472
    749473int AudioOutputDX::GetVolumeChannel(int channel)
    750474{
    751     // Do nothing
    752     return 100;
     475    HRESULT dsresult;
     476    long dxVolume = 0;
     477    int volume;
     478
     479    if (m_UseSPDIF)
     480        return 100;
     481
     482    dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);
     483    if (dsresult != DS_OK)
     484        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get volume " << dxVolume );
     485
     486    volume = (int)(pow(10,(float)dxVolume/20)*100);
     487    VERBOSE(VB_AUDIO, LOC + "got volume " << volume );
     488
     489    return volume;
    753490}
     491
    754492void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    755493{
    756     // Do nothing
     494    HRESULT dsresult;
     495    float dbAtten = 20 * log10((float)volume/100);
     496    long dxVolume = (volume == 0) ? DSBVOLUME_MIN : 100 * dbAtten;
     497
     498    if (m_UseSPDIF)
     499        return;
     500
     501    // dxVolume is attenuation in 100ths of a decibel
     502    dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);
     503
     504    if (dsresult != DS_OK)
     505        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set volume " << dxVolume );
     506   
     507    VERBOSE(VB_AUDIO, LOC + "set volume " << dxVolume );
    757508}
    758509
     510/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    41944194        if (audioOutput)
    41954195        {
    41964196            audioOutput->SetStretchFactor(play_speed);
    4197 #ifdef USING_DIRECTX
    4198             audioOutput->Reset();
    4199 #endif
    42004197        }
    42014198    }
    42024199