Ticket #6538: aodx_trunk.2.patch

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

Disregard the first patch. This revision adds a check for the rare case that Pause gets called before the device is open.

  • 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 *aubuf, 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_PlayStarted;
     31    DWORD                    m_WriteCursor;
     32    bool                     m_UseSPDIF;
     33    static const uint        kFramesNum;
    7734};
    7835
    7936#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
    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)
     55class AudioOutputDXPrivate
    11456{
    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++)
     57    public:
     58        AudioOutputDXPrivate() :
     59            dsound_dll(NULL),
     60            dsobject(NULL),
     61            dsbuffer(NULL)
    23062        {
    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;
     63            InitDirectSound();
    23664        }
    237     }
    23865
    239     err = arts_write(pcm_handle, audiobuffer, frames*4);
    240     free(audiobuffer);
     66        ~AudioOutputDXPrivate()
     67        {
     68            DestroyDSBuffer();
    24169
    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*/
     70            if (dsobject)
     71                IDirectSound_Release(dsobject);
    25072   
    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);
     73            if (dsound_dll)
     74               FreeLibrary(dsound_dll);
     75        }
    25476
    255     return true;
    256 }
     77        int InitDirectSound(void);
     78        void DestroyDSBuffer(void);
     79        bool StartPlayback(void);
    25780
    258 void AudioOutputDX::SetTimecode(long long timecode)
    259 {
    260     audbuf_timecode = timecode;
    261 }
     81    public:
     82        HINSTANCE dsound_dll;
     83        LPDIRECTSOUND dsobject;
     84        LPDIRECTSOUNDBUFFER dsbuffer;
     85};
    26286
    263 void AudioOutputDX::SetEffDsp(int dsprate)
    264 {
    265     VERBOSE(VB_IMPORTANT, "setting dsprate = " << dsprate);
    266    
    267     HRESULT dsresult;
    26887
    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)
     88AudioOutputDX::AudioOutputDX(const AudioSettings &settings) :
     89    AudioOutputBase(settings),
     90    m_priv(new AudioOutputDXPrivate()),
     91    m_PlayStarted(false),
     92    m_WriteCursor(0),
     93    m_UseSPDIF(settings.use_passthru)
    28094{
    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;
     95    Reconfigure(settings);
    31196}
    31297
    313 int AudioOutputDX::GetAudiotime(void)
     98AudioOutputDX::~AudioOutputDX()
    31499{
    315     DWORD play_pos;
    316     HRESULT dsresult;
     100    KillAudio();
    317101
    318     dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, NULL);
    319 
    320     if (dsresult != DS_OK)
     102    if (m_priv)
    321103    {
    322         VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    323         return -1;
     104        delete m_priv;
     105        m_priv = NULL;
    324106    }
    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);
    332107}
    333108
    334 
    335109typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
    336110
    337 /*****************************************************************************
    338  * InitDirectSound: handle all the gory details of DirectSound initialisation
    339  *****************************************************************************/
    340 int AudioOutputDX::InitDirectSound()
     111int AudioOutputDXPrivate::InitDirectSound(void)
    341112{
    342 //    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
     113
    343114    LPFNDSC OurDirectSoundCreate;
    344115
    345     VERBOSE(VB_IMPORTANT, "initialising DirectSound");
     116    VERBOSE(VB_AUDIO, LOC + "initialising DirectSound");
    346117   
    347118    dsound_dll = LoadLibrary("DSOUND.DLL");
    348119    if (dsound_dll == NULL )
    349120    {
    350         VERBOSE(VB_IMPORTANT, "cannot open DSOUND.DLL" );
     121        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot open DSOUND.DLL" );
    351122        goto error;
    352123    }
    353124
    354     OurDirectSoundCreate = (LPFNDSC)
    355                                 GetProcAddress(dsound_dll, "DirectSoundCreate");
     125    OurDirectSoundCreate =
     126        (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate");
    356127    if (OurDirectSoundCreate == NULL)
    357128    {
    358         VERBOSE(VB_IMPORTANT, "GetProcAddress FAILED" );
     129        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProcAddress FAILED" );
    359130        goto error;
    360131    }
    361132
    362     VERBOSE(VB_IMPORTANT, "create DS object");
     133    // VERBOSE(VB_IMPORTANT, "create DS object");
    363134
    364135    /* Create the direct sound object */
    365136    if FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL))
    366137    {
    367         VERBOSE(VB_IMPORTANT, "cannot create a direct sound device" );
     138        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" );
    368139        goto error;
    369140    }
    370141
    371     VERBOSE(VB_IMPORTANT, "setting cooperative level");
     142    // VERBOSE(VB_IMPORTANT, "setting cooperative level");
    372143
    373144    /* Set DirectSound Cooperative level, ie what control we want over Windows
    374145     * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
     
    380151     * sound without any video, and so what window handle should we use ???
    381152     * The hack for now is to use the Desktop window handle - it seems to be
    382153     * working */
    383     if (IDirectSound_SetCooperativeLevel(dsobject,
     154    if FAILED(IDirectSound_SetCooperativeLevel(dsobject,
    384155                                         GetDesktopWindow(),
    385156                                         DSSCL_EXCLUSIVE))
    386157    {
    387         VERBOSE(VB_IMPORTANT, "cannot set direct sound cooperative level" );
     158        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot set DS cooperative level" );
    388159    }
    389160
    390     VERBOSE(VB_IMPORTANT, "creating notificatoin events");
     161    VERBOSE(VB_AUDIO, LOC + "initialised DirectSound");
    391162
    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 
    398163    return 0;
    399164
    400165 error:
     
    405170        dsound_dll = NULL;
    406171    }
    407172    return -1;
     173}
    408174
     175void AudioOutputDXPrivate::DestroyDSBuffer(void)
     176{
     177    if (dsbuffer)
     178    {
     179        VERBOSE(VB_AUDIO, LOC + "destroying DirectSound buffer");
     180        IDirectSoundBuffer_Stop(dsbuffer);
     181        IDirectSoundBuffer_Release(dsbuffer);
     182        dsbuffer = NULL;
     183    }
    409184}
    410185
    411 
    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)
     186bool AudioOutputDXPrivate::StartPlayback(void)
    425187{
    426     WAVEFORMATEXTENSIBLE waveformat;
    427     DSBUFFERDESC         dsbdesc;
    428     unsigned int         i;
     188    HRESULT dsresult;
    429189
    430     /* First set the sound buffer format */
    431 /*    waveformat.dwChannelMask = 0;
    432     for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ )
     190    dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING);
     191    if (dsresult == DSERR_BUFFERLOST)
    433192    {
    434         if ( i_channels & pi_channels_in[i] )
    435             waveformat.dwChannelMask |= pi_channels_out[i];
    436     }*/
    437 
    438 /*    switch( i_format )
     193        IDirectSoundBuffer_Restore(dsbuffer);
     194        dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING );
     195    }
     196    if (dsresult != DS_OK)
    439197    {
    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;
     198        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot start playing buffer" );
     199        return false;
     200    }
     201    else
     202        return true;
     203}
    450204
    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;
     205bool AudioOutputDX::OpenDevice(void)
     206{
     207    WAVEFORMATEXTENSIBLE wf;
     208    DSBUFFERDESC         dsbdesc;
    458209
    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     }*/
     210    if (!m_priv->dsobject || !m_priv->dsound_dll)
     211    {
     212        Error("DirectSound initialization failed");
     213        return false;
     214    }
    467215
    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;
     216    CloseDevice();
    474217
    475     audio_bytes_per_sample = waveformat.Format.wBitsPerSample / 8 * audio_channels;
     218    SetBlocking(true);
     219    fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144;
     220    if (audio_channels > 2)
     221        fragment_size *= 2;
     222    soundcard_buffer_size = kFramesNum * fragment_size;
     223    audio_bytes_per_sample = audio_bits / 8 * audio_channels;
     224    if (m_UseSPDIF && (audio_channels != 2))
     225    {
     226        Error("SPDIF passthru requires 2 channel data");
     227        return false;
     228    }
    476229
    477     VERBOSE(VB_IMPORTANT, "New format: " << audio_bits << "bits, " << audio_channels << "ch, " << audio_samplerate << "Hz");
     230    /* First set the sound buffer format */
     231    wf.Format.wFormatTag =
     232        (m_UseSPDIF) ? WAVE_FORMAT_DOLBY_AC3_SPDIF : WAVE_FORMAT_PCM;
     233    wf.Format.nChannels = audio_channels;
     234    wf.Format.nSamplesPerSec = audio_samplerate;
     235    wf.Format.nBlockAlign = audio_bytes_per_sample;
     236    wf.Format.nAvgBytesPerSec =
     237        wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
     238    wf.Format.wBitsPerSample = audio_bits;
     239    wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
     240    wf.SubFormat =
     241        (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF : _KSDATAFORMAT_SUBTYPE_PCM;
    478242
     243    VERBOSE(VB_AUDIO, LOC + "New format: " << audio_bits << "bits, "
     244            << audio_channels << "ch, " << audio_samplerate << "Hz");
     245
    479246    /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
    480247    if (audio_channels <= 2)
    481248    {
    482         waveformat.Format.cbSize = 0;
     249        wf.Format.cbSize = 0;
    483250    }
    484251    else
    485252    {
    486         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
    487         waveformat.Format.cbSize =
     253        wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
     254        wf.dwChannelMask = 0x003F;          // 0x003F = 5.1 channels
     255        wf.Format.cbSize =
    488256            sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    489257    }
    490258
    491 
    492259    /* Then fill in the direct sound descriptor */
    493260    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    494261    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    495262    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
    496                     | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
    497263                    | DSBCAPS_GLOBALFOCUS       /* Allows background playing */
    498264                    | 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;
     265    if (!m_UseSPDIF)
     266        dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME;  /* Allow volume control */
     267    dsbdesc.dwBufferBytes = soundcard_buffer_size;   /* buffer size */
     268    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
    501269
    502     if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     270    if FAILED(IDirectSound_CreateSoundBuffer(
     271                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL))
    503272    {
     273        /* Vista does not support hardware mixing */
    504274        /* Try without DSBCAPS_LOCHARDWARE */
    505275        dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
    506         if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL))
     276        HRESULT dsresult = IDirectSound_CreateSoundBuffer(
     277                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL);
     278        if FAILED(dsresult)
    507279        {
    508             return -1;
     280           Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult));
     281           return false;
    509282        }
    510         if ( !b_probe ) VERBOSE(VB_IMPORTANT, "couldn't use hardware sound buffer" );
     283        VERBOSE(VB_AUDIO, LOC + "Using software mixer" );
    511284    }
     285    VERBOSE(VB_AUDIO, LOC + "created DirectSound buffer");
    512286
    513     write_cursor = 0;
    514     buffer_size = FRAMES_NUM * audio_bits/8 * audio_channels;
    515 
    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;
     287    return true;
    554288}
    555289
    556 
    557 /*****************************************************************************
    558  * DestroyDSBuffer
    559  *****************************************************************************
    560  * This function destroys the secondary buffer.
    561  *****************************************************************************/
    562 void AudioOutputDX::DestroyDSBuffer()
     290void AudioOutputDX::CloseDevice(void)
    563291{
    564     if (dsnotify)
    565     {
    566         IDirectSoundNotify_Release(dsnotify);
    567         dsnotify = NULL;
    568     }
    569 
    570     VERBOSE(VB_IMPORTANT, "destroying DirectSound buffer");
    571 
    572     if (dsbuffer)
    573     {
    574         IDirectSoundBuffer_Stop(dsbuffer);
    575         IDirectSoundBuffer_Release(dsbuffer);
    576         dsbuffer = NULL;
    577     }
     292    if (m_priv->dsbuffer)
     293        m_priv->DestroyDSBuffer();
     294    m_WriteCursor = 0;
     295    m_PlayStarted = false;
    578296}
    579297
    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)
     298void AudioOutputDX::WriteAudio(unsigned char * buffer, int size)
    586299{
    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;
     300        if (size == 0)
     301        return;
    591302
    592     if (!awaiting_data && !paused)
     303    if (audio_channels == 6)
    593304    {
    594    
    595 //        VERBOSE(VB_IMPORTANT, "checking buffer positions");
    596    
    597         dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
    598 
    599         if (dsresult != DS_OK)
     305        // Linux and Windows have different 5.1 channel order conventions
     306        const uint kReorder[6] = {0,1,4,5,2,3};
     307        int abytes = audio_bits / 8;
     308        unsigned char p_tmp[24];
     309        unsigned char *obuf = buffer;
     310        for(int i = 0; i < size / audio_channels / abytes; i++)
    600311        {
    601             VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    602             return -1;
    603         }
    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))))
    611         {
    612 //            VERBOSE(VB_IMPORTANT, "cannot write audio data: " << write_cursor << " " << write_pos << " " << play_pos << " sleeping");
    613 
    614             HANDLE  notification_events[4];
    615 
    616             for(int i = 0; i < 4; i++)
    617                 notification_events[i] = notif[i].hEventNotify;
    618 
    619                 WaitForMultipleObjects(4, notification_events, 0, INFINITE );
    620                
    621 //                VERBOSE(VB_IMPORTANT, "woken");
    622                
    623             dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);
    624 
    625             if (dsresult != DS_OK)
     312            for(int j = 0; j < audio_channels; j++)
    626313            {
    627                 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");
    628                 return -1;
     314                for(int k = 0; k < abytes; k++)
     315                {
     316                    p_tmp[abytes * kReorder[j] + k] = buffer[abytes * j + k];
     317                }
    629318            }
    630 
    631             end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;
     319            memcpy(buffer, p_tmp, abytes * audio_channels);
     320            buffer += abytes * audio_channels;
    632321        }
     322        buffer = obuf;
    633323    }
    634                                    
    635324
    636 //    VERBOSE(VB_IMPORTANT, "Locking buffer");
     325    void *p_write_position, *p_wrap_around;
     326    DWORD l_bytes1, l_bytes2;
     327    HRESULT dsresult;
    637328
    638329    /* Before copying anything, we have to lock the buffer */
    639330    dsresult = IDirectSoundBuffer_Lock(
    640                 dsbuffer,                                       /* DS buffer */
    641                 write_cursor,                                   /* Start offset */
    642                 frames * audio_bytes_per_sample,          /* Number of bytes */
     331                m_priv->dsbuffer,        /* DS buffer */
     332                m_WriteCursor,           /* Start offset */
     333                size,                    /* Number of bytes */
    643334                &p_write_position,                  /* Address of lock start */
    644335                &l_bytes1,       /* Count of bytes locked before wrap around */
    645336                &p_wrap_around,            /* Buffer adress (if wrap around) */
    646337                &l_bytes2,               /* Count of bytes after wrap around */
    647                 0);                                                   /* Flags */
     338                0);                                                 /* Flags */
    648339    if (dsresult == DSERR_BUFFERLOST)
    649340    {
    650         IDirectSoundBuffer_Restore(dsbuffer);
     341        IDirectSoundBuffer_Restore(m_priv->dsbuffer);
    651342        dsresult = IDirectSoundBuffer_Lock(
    652                                dsbuffer,
    653                                write_cursor,
    654                                frames * audio_bytes_per_sample,
     343                               m_priv->dsbuffer,
     344                               m_WriteCursor,
     345                               size,
    655346                               &p_write_position,
    656347                               &l_bytes1,
    657348                               &p_wrap_around,
     
    660351    }
    661352    if (dsresult != DS_OK)
    662353    {
    663         VERBOSE(VB_IMPORTANT, "cannot lock buffer");
    664         return -1;
     354        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot lock buffer, audio dropped");
     355        return;
    665356    }
    666357
    667358    if (buffer == NULL)
    668359    {
    669         VERBOSE(VB_IMPORTANT, "Writing null bytes");
     360        VERBOSE(VB_AUDIO, LOC + "Writing null bytes");
    670361   
    671362        memset(p_write_position, 0, l_bytes1);
    672363        if (p_wrap_around)
    673364            memset(p_wrap_around, 0, l_bytes2);
    674365           
    675            write_cursor += l_bytes1 + l_bytes2;
     366        m_WriteCursor += l_bytes1 + l_bytes2;
    676367           
    677            while (write_cursor >= buffer_size)
    678                write_cursor -= buffer_size;
     368        while (m_WriteCursor >= (DWORD)soundcard_buffer_size)
     369            m_WriteCursor -= soundcard_buffer_size;
    679370    }
    680 /*    else if ( p_aout->output.p_sys->b_chan_reorder )
    681     {
    682         /* Do the channel reordering here * /
    683 
    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 ) );
    694 
    695         aout_BufferFree( p_buffer );
    696     }*/
    697371    else   
    698372    {
    699 //        VERBOSE(VB_IMPORTANT, "filling buffer");
    700    
    701373        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));
    703374        if (p_wrap_around) {
    704375            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));
    706376        }
    707377           
    708            write_cursor += l_bytes1 + l_bytes2;
     378        m_WriteCursor += l_bytes1 + l_bytes2;
    709379           
    710            while (write_cursor >= buffer_size)
    711                write_cursor -= buffer_size;
     380        while (m_WriteCursor >= (DWORD)soundcard_buffer_size)
     381            m_WriteCursor -= soundcard_buffer_size;
    712382    }
    713383
    714 //    VERBOSE(VB_IMPORTANT, "unlocking buffer");
    715 
    716384    /* Now the data has been copied, unlock the buffer */
    717     IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1,
     385    IDirectSoundBuffer_Unlock(m_priv->dsbuffer, p_write_position, l_bytes1,
    718386                              p_wrap_around, l_bytes2 );
    719387
     388    m_PlayStarted = m_priv->StartPlayback();
     389}
    720390
    721 //    VERBOSE(VB_IMPORTANT, "finished fillbuffer");
     391void AudioOutputDX::Pause(bool pause)
     392{
     393    if (m_priv->dsbuffer)
     394    {
     395        if (pause)
     396        {
     397            IDirectSoundBuffer_Stop(m_priv->dsbuffer);
     398            VERBOSE(VB_AUDIO, LOC + "buffer paused");
     399        }
     400        else
     401        {
     402            if (! m_priv->StartPlayback())
     403                VERBOSE(VB_IMPORTANT, LOC_ERR + "unpause failed" );
     404            VERBOSE(VB_AUDIO, LOC + "buffer unpaused");
     405        }
     406    }
    722407
    723     return 0;
     408    AudioOutputBase::Pause(pause);
    724409}
    725410
    726 // Wait for all data to finish playing
    727 void AudioOutputDX::Drain()
     411int AudioOutputDX::GetSpaceOnSoundcard(void) const
    728412{
    729     // TODO: Wait until all data has been played...
     413    HRESULT dsresult;
     414    DWORD play_pos, write_pos;
    730415
     416    dsresult = IDirectSoundBuffer_GetCurrentPosition(
     417            m_priv->dsbuffer, &play_pos, &write_pos);
     418    if (dsresult != DS_OK)
     419    {
     420        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     421            return 0;
     422    }
     423
     424    if (!m_PlayStarted)
     425        return soundcard_buffer_size;
     426    else
     427    {
     428        int buffer_free = (int)play_pos - (int)m_WriteCursor;
     429        if ( buffer_free < 0 )
     430            buffer_free += soundcard_buffer_size;
     431
     432        if (((write_pos > play_pos) && (m_WriteCursor <= write_pos)
     433                    && (m_WriteCursor > play_pos))
     434            || ((write_pos < play_pos) && ((m_WriteCursor <= write_pos)
     435                    || (play_pos < m_WriteCursor))))
     436        {
     437            VERBOSE (VB_AUDIO, LOC + "buffer underrun "
     438                   << play_pos << " " << write_pos << " " << m_WriteCursor);
     439            // WriteCursor is in unsafe zone - stop playback for now
     440            // Next call to WriteAudio will restart the buffer
     441            IDirectSoundBuffer_Stop(m_priv->dsbuffer);
     442        }
     443        return buffer_free;
     444    }
    731445}
    732446
     447int AudioOutputDX::GetBufferedOnSoundcard(void) const
     448{
     449    HRESULT dsresult;
     450    DWORD play_pos;
     451
     452    dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->dsbuffer, &play_pos, NULL);
     453    if (dsresult != DS_OK)
     454    {
     455        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position");
     456            return 0;
     457    }
     458
     459    int buffered = (int)m_WriteCursor - (int)play_pos;
     460    if ( buffered < 0 )
     461        buffered += soundcard_buffer_size;
     462    return buffered;
     463}
     464
    733465int AudioOutputDX::GetVolumeChannel(int channel) const
    734466{
    735     // Do nothing
    736     return 100;
     467    HRESULT dsresult;
     468    long dxVolume = 0;
     469    int volume;
     470
     471    if (m_UseSPDIF)
     472        return 100;
     473
     474    dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume);
     475    if (dsresult != DS_OK)
     476        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get volume " << dxVolume );
     477
     478    volume = (int)(pow(10,(float)dxVolume/20)*100);
     479    VERBOSE(VB_AUDIO, LOC + "got volume " << volume );
     480
     481    return volume;
    737482}
     483
    738484void AudioOutputDX::SetVolumeChannel(int channel, int volume)
    739485{
    740     // Do nothing
     486    HRESULT dsresult;
     487    float dbAtten = 20 * log10((float)volume/100);
     488    long dxVolume = (volume == 0) ? DSBVOLUME_MIN : 100 * dbAtten;
     489
     490    if (m_UseSPDIF)
     491        return;
     492
     493    // dxVolume is attenuation in 100ths of a decibel
     494    dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume);
     495
     496    if (dsresult != DS_OK)
     497        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set volume " << dxVolume );
     498   
     499    VERBOSE(VB_AUDIO, LOC + "set volume " << dxVolume );
    741500}
    742501
     502/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    44754475        if (audioOutput)
    44764476        {
    44774477            audioOutput->SetStretchFactor(play_speed);
    4478 #ifdef USING_DIRECTX
    4479             audioOutput->Reset();
    4480 #endif
    44814478        }
    44824479    }
    44834480