MythTV  0.26-pre
audiooutputwin.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 
00003 using namespace std;
00004 
00005 #include "mythlogging.h"
00006 #include "audiooutputwin.h"
00007 
00008 #include <windows.h>
00009 #include <mmsystem.h>
00010 #include <objbase.h> // For DEFINE_GUID
00011 
00012 #define LOC QString("AOWin: ")
00013 
00014 #ifndef WAVE_FORMAT_IEEE_FLOAT
00015 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
00016 #endif
00017 
00018 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
00019 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
00020 #endif
00021 
00022 #ifndef WAVE_FORMAT_EXTENSIBLE
00023 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
00024 #endif
00025 
00026 #ifndef _WAVEFORMATEXTENSIBLE_
00027 typedef struct {
00028     WAVEFORMATEX    Format;
00029     union {
00030         WORD wValidBitsPerSample;       // bits of precision
00031         WORD wSamplesPerBlock;          // valid if wBitsPerSample==0
00032         WORD wReserved;                 // If neither applies, set to zero
00033     } Samples;
00034     DWORD           dwChannelMask;      // which channels are present in stream
00035     GUID            SubFormat;
00036 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
00037 #endif
00038 
00039 const uint AudioOutputWin::kPacketCnt = 4;
00040 
00041 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT,
00042             0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00043 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM,
00044             0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00045 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF,
00046             0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00047 
00048 class AudioOutputWinPrivate
00049 {
00050   public:
00051     AudioOutputWinPrivate() :
00052         m_hWaveOut(NULL), m_WaveHdrs(NULL), m_hEvent(NULL)
00053     {
00054         m_WaveHdrs = new WAVEHDR[AudioOutputWin::kPacketCnt];
00055         memset(m_WaveHdrs, 0, sizeof(WAVEHDR) * AudioOutputWin::kPacketCnt);
00056         m_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
00057     }
00058 
00059     ~AudioOutputWinPrivate()
00060     {
00061         if (m_WaveHdrs)
00062         {
00063             delete[] m_WaveHdrs;
00064             m_WaveHdrs = NULL;
00065         }
00066         if (m_hEvent)
00067         {
00068             CloseHandle(m_hEvent);
00069             m_hEvent = NULL;
00070         }
00071     }
00072 
00073     void Close(void)
00074     {
00075         if (m_hWaveOut)
00076         {
00077             waveOutReset(m_hWaveOut);
00078             waveOutClose(m_hWaveOut);
00079             m_hWaveOut = NULL;
00080         }
00081     }
00082 
00083     static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
00084                                      DWORD dwParam1, DWORD dwParam2);
00085 
00086   public:
00087     HWAVEOUT  m_hWaveOut;
00088     WAVEHDR  *m_WaveHdrs;
00089     HANDLE    m_hEvent;
00090 };
00091 
00092 void CALLBACK AudioOutputWinPrivate::waveOutProc(HWAVEOUT hwo, UINT uMsg,
00093                                                  DWORD dwInstance,
00094                                                  DWORD dwParam1, DWORD dwParam2)
00095 {
00096     if (uMsg != WOM_DONE)
00097         return;
00098 
00099     AudioOutputWin *instance = reinterpret_cast<AudioOutputWin*>(dwInstance);
00100     InterlockedDecrement(&instance->m_nPkts);
00101     if (instance->m_nPkts < (int)AudioOutputWin::kPacketCnt)
00102     {
00103         SetEvent(instance->m_priv->m_hEvent);
00104     }
00105 }
00106 
00107 AudioOutputWin::AudioOutputWin(const AudioSettings &settings) :
00108     AudioOutputBase(settings),
00109     m_priv(new AudioOutputWinPrivate()),
00110     m_nPkts(0),
00111     m_CurrentPkt(0),
00112     m_OutPkts(NULL),
00113     m_UseSPDIF(settings.use_passthru)
00114 {
00115     InitSettings(settings);
00116     if (settings.init)
00117         Reconfigure(settings);
00118     m_OutPkts = (unsigned char**) calloc(kPacketCnt, sizeof(unsigned char*));
00119 }
00120 
00121 AudioOutputWin::~AudioOutputWin()
00122 {
00123     KillAudio();
00124 
00125     if (m_priv)
00126     {
00127         delete m_priv;
00128         m_priv = NULL;
00129     }
00130 
00131     if (m_OutPkts)
00132     {
00133         for (uint i = 0; i < kPacketCnt; i++)
00134             if (m_OutPkts[i])
00135                 free(m_OutPkts[i]);
00136 
00137         free(m_OutPkts);
00138         m_OutPkts = NULL;
00139     }
00140 }
00141 
00142 AudioOutputSettings* AudioOutputWin::GetOutputSettings(bool /*digital*/)
00143 {
00144     AudioOutputSettings *settings = new AudioOutputSettings();
00145 
00146     // We use WAVE_MAPPER to find a compatible device, so just claim support
00147     // for all of the standard rates
00148     while (DWORD rate = (DWORD)settings->GetNextRate())
00149         settings->AddSupportedRate(rate);
00150 
00151     // Support all standard formats
00152     settings->AddSupportedFormat(FORMAT_U8);
00153     settings->AddSupportedFormat(FORMAT_S16);
00154     settings->AddSupportedFormat(FORMAT_S24);
00155     settings->AddSupportedFormat(FORMAT_S32);
00156     settings->AddSupportedFormat(FORMAT_FLT);
00157 
00158     // Guess that we can do up to 5.1
00159     for (uint i = 2; i < 7; i++)
00160         settings->AddSupportedChannels(i);
00161 
00162     settings->setPassthrough(0); //Maybe passthrough
00163 
00164     return settings;
00165 }
00166 
00167 bool AudioOutputWin::OpenDevice(void)
00168 {
00169     CloseDevice();
00170     // fragments are 50ms worth of samples
00171     fragment_size = 50 * output_bytes_per_frame * samplerate / 1000;
00172     // DirectSound buffer holds 4 fragments = 200ms worth of samples
00173     soundcard_buffer_size = kPacketCnt * fragment_size;
00174 
00175     VBAUDIO(QString("Buffering %1 fragments of %2 bytes each, total: %3 bytes")
00176             .arg(kPacketCnt).arg(fragment_size).arg(soundcard_buffer_size));
00177 
00178     m_UseSPDIF = passthru || enc;
00179 
00180     WAVEFORMATEXTENSIBLE wf;
00181     wf.Format.nChannels            = channels;
00182     wf.Format.nSamplesPerSec       = samplerate;
00183     wf.Format.nBlockAlign          = output_bytes_per_frame;
00184     wf.Format.nAvgBytesPerSec      = samplerate * output_bytes_per_frame;
00185     wf.Format.wBitsPerSample       = (output_bytes_per_frame << 3) / channels;
00186     wf.Samples.wValidBitsPerSample =
00187         AudioOutputSettings::FormatToBits(output_format);
00188 
00189     if (m_UseSPDIF)
00190     {
00191         wf.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
00192         wf.SubFormat         = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
00193     }
00194     else if (output_format == FORMAT_FLT)
00195     {
00196         wf.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
00197         wf.SubFormat         = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
00198     }
00199     else
00200     {
00201         wf.Format.wFormatTag = WAVE_FORMAT_PCM;
00202         wf.SubFormat         = _KSDATAFORMAT_SUBTYPE_PCM;
00203     }
00204 
00205     VBAUDIO(QString("New format: %1bits %2ch %3Hz %4")
00206             .arg(wf.Samples.wValidBitsPerSample).arg(channels)
00207             .arg(samplerate).arg(m_UseSPDIF ? "data" : "PCM"));
00208 
00209     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
00210     if (channels <= 2)
00211         wf.Format.cbSize = 0;
00212     else
00213     {
00214         wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
00215         wf.dwChannelMask = 0x003F; // 0x003F = 5.1 channels
00216         wf.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
00217     }
00218 
00219     MMRESULT mmr = waveOutOpen(&m_priv->m_hWaveOut, WAVE_MAPPER,
00220                                (WAVEFORMATEX *)&wf,
00221                                (DWORD)AudioOutputWinPrivate::waveOutProc,
00222                                (DWORD)this, CALLBACK_FUNCTION);
00223 
00224     if (mmr == WAVERR_BADFORMAT)
00225     {
00226         Error(QString("Unable to set audio output parameters %1")
00227               .arg(wf.Format.nSamplesPerSec));
00228         return false;
00229     }
00230 
00231     return true;
00232 }
00233 
00234 void AudioOutputWin::CloseDevice(void)
00235 {
00236     m_priv->Close();
00237 }
00238 
00239 void AudioOutputWin::WriteAudio(unsigned char * buffer, int size)
00240 {
00241     if (!size)
00242         return;
00243 
00244     if (InterlockedIncrement(&m_nPkts) > (int)kPacketCnt)
00245     {
00246         while (m_nPkts > (int)kPacketCnt)
00247             WaitForSingleObject(m_priv->m_hEvent, INFINITE);
00248     }
00249 
00250     if (m_CurrentPkt >= kPacketCnt)
00251         m_CurrentPkt = 0;
00252 
00253     WAVEHDR *wh = &m_priv->m_WaveHdrs[m_CurrentPkt];
00254     if (wh->dwFlags & WHDR_PREPARED)
00255         waveOutUnprepareHeader(m_priv->m_hWaveOut, wh, sizeof(WAVEHDR));
00256 
00257     m_OutPkts[m_CurrentPkt] =
00258         (unsigned char*)realloc(m_OutPkts[m_CurrentPkt], size);
00259 
00260     memcpy(m_OutPkts[m_CurrentPkt], buffer, size);
00261 
00262     memset(wh, 0, sizeof(WAVEHDR));
00263     wh->lpData = (LPSTR)m_OutPkts[m_CurrentPkt];
00264     wh->dwBufferLength = size;
00265 
00266     if (MMSYSERR_NOERROR != waveOutPrepareHeader(m_priv->m_hWaveOut, wh,
00267                                                  sizeof(WAVEHDR)))
00268         VBERROR("WriteAudio: failed to prepare header");
00269     else if (MMSYSERR_NOERROR != waveOutWrite(m_priv->m_hWaveOut, wh,
00270                                               sizeof(WAVEHDR)))
00271         VBERROR("WriteAudio: failed to write packet");
00272 
00273     m_CurrentPkt++;
00274 }
00275 
00276 int AudioOutputWin::GetBufferedOnSoundcard(void) const
00277 {
00278     return m_nPkts * fragment_size;
00279 }
00280 
00281 int AudioOutputWin::GetVolumeChannel(int channel) const
00282 {
00283     DWORD dwVolume = 0xffffffff;
00284     int Volume = 100;
00285     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
00286     {
00287         Volume = (channel == 0) ?
00288             (LOWORD(dwVolume) / (0xffff / 100)) :
00289             (HIWORD(dwVolume) / (0xffff / 100));
00290     }
00291 
00292     LOG(VB_AUDIO, LOG_INFO, QString("GetVolume(%1) %2 (%3)")
00293                                 .arg(channel).arg(Volume).arg(dwVolume));
00294 
00295     return Volume;
00296 }
00297 
00298 void AudioOutputWin::SetVolumeChannel(int channel, int volume)
00299 {
00300     if (channel > 1)
00301         VBERROR("Windows volume only supports stereo!");
00302 
00303     DWORD dwVolume = 0xffffffff;
00304     if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
00305     {
00306         if (channel == 0)
00307             dwVolume = (dwVolume & 0xffff0000) | (volume * (0xffff / 100));
00308         else
00309             dwVolume = (dwVolume & 0xffff) | ((volume * (0xffff / 100)) << 16);
00310     }
00311     else
00312     {
00313         dwVolume = volume * (0xffff / 100);
00314         dwVolume |= (dwVolume << 16);
00315     }
00316 
00317     VBAUDIO(QString("SetVolume(%1) %2(%3)")
00318             .arg(channel).arg(volume).arg(dwVolume));
00319 
00320     waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);
00321 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends