bool AudioOutputDSound::write(const QByteArray &data)
{
    DPTR_D(AudioOutputDSound);
    LPVOID dst1= NULL, dst2 = NULL;
    DWORD size1 = 0, size2 = 0;
    if (d.write_offset >= d.bufferSizeTotal()) ///!!!>=
        d.write_offset = 0;
    HRESULT res = d.stream_buf->Lock(d.write_offset, data.size(), &dst1, &size1, &dst2, &size2, 0); //DSBLOCK_ENTIREBUFFER
    if (res == DSERR_BUFFERLOST) {
        d.stream_buf->Restore();
        res = d.stream_buf->Lock(d.write_offset, data.size(), &dst1, &size1, &dst2, &size2, 0);
    }
    if (res != DS_OK) {
        qWarning("Can not lock secondary buffer (%s)", dserr2str(res));
        return false;
    }
    memcpy(dst1, data.constData(), size1);
    if (dst2)
        memcpy(dst2, data.constData() + size1, size2);
    d.write_offset += size1 + size2;
    if (d.write_offset >= d.bufferSizeTotal())
        d.write_offset = size2;
    res = d.stream_buf->Unlock(dst1, size1, dst2, size2);
    if (res != DS_OK) {
        qWarning("Unloack error (%s)",dserr2str(res));
        //return false;
    }
    return true;
}
Exemple #2
0
void CAESinkDirectSound::CheckPlayStatus()
{
    DWORD status = 0;
    m_pBuffer->GetStatus(&status);

    if (!(status & DSBSTATUS_PLAYING) && m_CacheLen != 0) // If we have some data, see if we can start playback
    {
        HRESULT hr = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
        dserr2str(hr);
        CLog::Log(LOGDEBUG,__FUNCTION__ ": Resuming Playback");
    }
}
void CAESinkDirectSound::CheckPlayStatus()
{
  DWORD status = 0;
  if (m_pBuffer->GetStatus(&status) != DS_OK)
  {
    CLog::Log(LOGERROR, "%s: GetStatus() failed", __FUNCTION__);
    return;
  }

  if (!(status & DSBSTATUS_PLAYING) && m_CacheLen != 0) // If we have some data, see if we can start playback
  {
    HRESULT hr = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
    CLog::Log(LOGDEBUG,__FUNCTION__ ": Resuming Playback");
    if (FAILED(hr))
      CLog::Log(LOGERROR, __FUNCTION__": Failed to play the DirectSound buffer: %s", dserr2str(hr));
  }
}
bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device)
{
  if (m_initialized)
    return false;

  LPGUID deviceGUID = NULL;
  RPC_CSTR wszUuid  = NULL;
  HRESULT hr = E_FAIL;
  std::string strDeviceGUID = device;
  std::list<DSDevice> DSDeviceList;
  std::string deviceFriendlyName;
  DirectSoundEnumerate(DSEnumCallback, &DSDeviceList);

  if(StringUtils::EndsWithNoCase(device, std::string("default")))
    strDeviceGUID = GetDefaultDevice();

  for (std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); ++itt)
  {
    if ((*itt).lpGuid)
    {
      hr = (UuidToString((*itt).lpGuid, &wszUuid));
      std::string sztmp = (char*)wszUuid;
      std::string szGUID = "{" + std::string(sztmp.begin(), sztmp.end()) + "}";
      if (strcasecmp(szGUID.c_str(), strDeviceGUID.c_str()) == 0)
      {
        deviceGUID = (*itt).lpGuid;
        deviceFriendlyName = (*itt).name.c_str();
        break;
      }
    }
    if (hr == RPC_S_OK) RpcStringFree(&wszUuid);
  }

  hr = DirectSoundCreate(deviceGUID, &m_pDSound, NULL);

  if (FAILED(hr))
  {
    CLog::Log(LOGERROR, __FUNCTION__": Failed to create the DirectSound device %s with error %s, trying the default device.", deviceFriendlyName.c_str(), dserr2str(hr));
    hr = DirectSoundCreate(NULL, &m_pDSound, NULL);
    if (FAILED(hr))
    {
      CLog::Log(LOGERROR, __FUNCTION__": Failed to create the default DirectSound device with error %s.", dserr2str(hr));
      return false;
    }
  }

  HWND tmp_hWnd;

  /* Dodge the null handle on first init by using desktop handle */
  if (g_hWnd == NULL)
    tmp_hWnd = GetDesktopWindow();
  else
    tmp_hWnd = g_hWnd;

  CLog::Log(LOGDEBUG, __FUNCTION__": Using Window handle: %d", tmp_hWnd);

  hr = m_pDSound->SetCooperativeLevel(tmp_hWnd, DSSCL_PRIORITY);

  if (FAILED(hr))
  {
    CLog::Log(LOGERROR, __FUNCTION__": Failed to create the DirectSound device cooperative level.");
    CLog::Log(LOGERROR, __FUNCTION__": DSErr: %s", dserr2str(hr));
    m_pDSound->Release();
    return false;
  }

  WAVEFORMATEXTENSIBLE wfxex = {0};

  //fill waveformatex
  ZeroMemory(&wfxex, sizeof(WAVEFORMATEXTENSIBLE));
  wfxex.Format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
  wfxex.Format.nChannels       = format.m_channelLayout.Count();
  wfxex.Format.nSamplesPerSec  = format.m_sampleRate;
  if (AE_IS_RAW(format.m_dataFormat))
  {
    wfxex.dwChannelMask          = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
    wfxex.Format.wFormatTag      = WAVE_FORMAT_DOLBY_AC3_SPDIF;
    wfxex.SubFormat              = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
    wfxex.Format.wBitsPerSample  = 16;
    wfxex.Format.nChannels       = 2;
  }
  else
  {
    wfxex.dwChannelMask          = SpeakerMaskFromAEChannels(format.m_channelLayout);
    wfxex.Format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
    wfxex.SubFormat              = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
    wfxex.Format.wBitsPerSample  = 32;
  }

  wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
  wfxex.Format.nBlockAlign          = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
  wfxex.Format.nAvgBytesPerSec      = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;

  m_AvgBytesPerSec = wfxex.Format.nAvgBytesPerSec;

  unsigned int uiFrameCount = (int)(format.m_sampleRate * 0.01); //default to 10ms chunks
  m_dwFrameSize = wfxex.Format.nBlockAlign;
  m_dwChunkSize = m_dwFrameSize * uiFrameCount;
  m_dwBufferLen = m_dwChunkSize * 12; //120ms total buffer

  // fill in the secondary sound buffer descriptor
  DSBUFFERDESC dsbdesc;
  memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */
                  | DSBCAPS_GLOBALFOCUS;         /** Allows background playing */

  dsbdesc.dwBufferBytes = m_dwBufferLen;
  dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wfxex;

  // now create the stream buffer
  HRESULT res = IDirectSound_CreateSoundBuffer(m_pDSound, &dsbdesc, &m_pBuffer, NULL);
  if (res != DS_OK)
  {
    if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE)
    {
      SAFE_RELEASE(m_pBuffer);
      CLog::Log(LOGDEBUG, __FUNCTION__": Couldn't create secondary buffer (%s). Trying without LOCHARDWARE.", dserr2str(res));
      // Try without DSBCAPS_LOCHARDWARE
      dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
      res = IDirectSound_CreateSoundBuffer(m_pDSound, &dsbdesc, &m_pBuffer, NULL);
    }
    if (res != DS_OK)
    {
      SAFE_RELEASE(m_pBuffer);
      CLog::Log(LOGERROR, __FUNCTION__": cannot create secondary buffer (%s)", dserr2str(res));
      return false;
    }
  }
  CLog::Log(LOGDEBUG, __FUNCTION__": secondary buffer created");

  m_pBuffer->Stop();

  AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
  format.m_channelLayout = m_channelLayout;
  m_encodedFormat = format.m_dataFormat;
  format.m_frames = uiFrameCount;
  format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
  format.m_frameSize = (AE_IS_RAW(format.m_dataFormat) ? wfxex.Format.wBitsPerSample >> 3 : sizeof(float)) * format.m_channelLayout.Count();
  format.m_dataFormat = AE_IS_RAW(format.m_dataFormat) ? AE_FMT_S16NE : AE_FMT_FLOAT;

  m_format = format;
  m_device = device;

  m_BufferOffset = 0;
  m_CacheLen = 0;
  m_LastCacheCheck = XbmcThreads::SystemClockMillis();
  m_initialized = true;
  m_isDirtyDS = false;

  CLog::Log(LOGDEBUG, __FUNCTION__": Initializing DirectSound with the following parameters:");
  CLog::Log(LOGDEBUG, "  Audio Device    : %s", ((std::string)deviceFriendlyName).c_str());
  CLog::Log(LOGDEBUG, "  Sample Rate     : %d", wfxex.Format.nSamplesPerSec);
  CLog::Log(LOGDEBUG, "  Sample Format   : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
  CLog::Log(LOGDEBUG, "  Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
  CLog::Log(LOGDEBUG, "  Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
  CLog::Log(LOGDEBUG, "  Channel Count   : %d", wfxex.Format.nChannels);
  CLog::Log(LOGDEBUG, "  Block Align     : %d", wfxex.Format.nBlockAlign);
  CLog::Log(LOGDEBUG, "  Avg. Bytes Sec  : %d", wfxex.Format.nAvgBytesPerSec);
  CLog::Log(LOGDEBUG, "  Samples/Block   : %d", wfxex.Samples.wSamplesPerBlock);
  CLog::Log(LOGDEBUG, "  Format cBSize   : %d", wfxex.Format.cbSize);
  CLog::Log(LOGDEBUG, "  Channel Layout  : %s", ((std::string)format.m_channelLayout).c_str());
  CLog::Log(LOGDEBUG, "  Channel Mask    : %d", wfxex.dwChannelMask);
  CLog::Log(LOGDEBUG, "  Frames          : %d", format.m_frames);
  CLog::Log(LOGDEBUG, "  Frame Samples   : %d", format.m_frameSamples);
  CLog::Log(LOGDEBUG, "  Frame Size      : %d", format.m_frameSize);

  return true;
}
Exemple #5
0
/**
\brief setup sound device
\param rate samplerate
\param channels number of channels
\param format format
\param flags unused
\return 0=success -1=fail
*/
static int init(struct ao *ao)
{
    struct priv *p = ao->priv;
    int res;

    if (!InitDirectSound(ao))
        return -1;

    ao->no_persistent_volume = true;
    p->audio_volume = 100;

    // ok, now create the buffers
    WAVEFORMATEXTENSIBLE wformat;
    DSBUFFERDESC dsbpridesc;
    DSBUFFERDESC dsbdesc;
    int format = af_fmt_from_planar(ao->format);
    int rate = ao->samplerate;

    if (AF_FORMAT_IS_AC3(format))
        format = AF_FORMAT_AC3;
    else {
        struct mp_chmap_sel sel = {0};
        mp_chmap_sel_add_waveext(&sel);
        if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
            return -1;
    }
    switch (format) {
    case AF_FORMAT_AC3:
    case AF_FORMAT_S24_LE:
    case AF_FORMAT_S16_LE:
    case AF_FORMAT_U8:
        break;
    default:
        MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n",
                   af_fmt_to_str(format));
        format = AF_FORMAT_S16_LE;
    }
    //set our audio parameters
    ao->samplerate = rate;
    ao->format = format;
    ao->bps = ao->channels.num * rate * (af_fmt2bits(format) >> 3);
    int buffersize = ao->bps; // space for 1 sec
    MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate,
               ao->channels.num, af_fmt_to_str(format));
    MP_VERBOSE(ao, "Buffersize:%d bytes (%d msec)\n",
               buffersize, buffersize / ao->bps * 1000);

    //fill waveformatex
    ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
    wformat.Format.cbSize = (ao->channels.num > 2)
                    ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0;
    wformat.Format.nChannels = ao->channels.num;
    wformat.Format.nSamplesPerSec = rate;
    if (AF_FORMAT_IS_AC3(format)) {
        wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
        wformat.Format.wBitsPerSample = 16;
        wformat.Format.nBlockAlign = 4;
    } else {
        wformat.Format.wFormatTag = (ao->channels.num > 2)
                                    ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
        wformat.Format.wBitsPerSample = af_fmt2bits(format);
        wformat.Format.nBlockAlign = wformat.Format.nChannels *
                                     (wformat.Format.wBitsPerSample >> 3);
    }

    // fill in primary sound buffer descriptor
    memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC));
    dsbpridesc.dwSize = sizeof(DSBUFFERDESC);
    dsbpridesc.dwFlags       = DSBCAPS_PRIMARYBUFFER;
    dsbpridesc.dwBufferBytes = 0;
    dsbpridesc.lpwfxFormat   = NULL;

    // fill in the secondary sound buffer (=stream buffer) descriptor
    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */
                      | DSBCAPS_GLOBALFOCUS       /** Allows background playing */
                      | DSBCAPS_CTRLVOLUME;       /** volume control enabled */

    if (ao->channels.num > 2) {
        wformat.dwChannelMask = mp_chmap_to_waveext(&ao->channels);
        wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
        wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample;
        // Needed for 5.1 on emu101k - shit soundblaster
        dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
    }
    wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec *
                                     wformat.Format.nBlockAlign;

    dsbdesc.dwBufferBytes = buffersize;
    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat;
    p->buffer_size = dsbdesc.dwBufferBytes;
    p->write_offset = 0;
    p->min_free_space = wformat.Format.nBlockAlign;
    p->outburst = wformat.Format.nBlockAlign * 512;

    // create primary buffer and set its format

    res = IDirectSound_CreateSoundBuffer(p->hds, &dsbpridesc, &p->hdspribuf, NULL);
    if (res != DS_OK) {
        UninitDirectSound(ao);
        MP_ERR(ao, "cannot create primary buffer (%s)\n", dserr2str(res));
        return -1;
    }
    res = IDirectSoundBuffer_SetFormat(p->hdspribuf, (WAVEFORMATEX *)&wformat);
    if (res != DS_OK) {
        MP_WARN(ao, "cannot set primary buffer format (%s), using "
                "standard setting (bad quality)", dserr2str(res));
    }

    MP_VERBOSE(ao, "primary buffer created\n");

    // now create the stream buffer

    res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL);
    if (res != DS_OK) {
        if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) {
            // Try without DSBCAPS_LOCHARDWARE
            dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
            res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL);
        }
        if (res != DS_OK) {
            UninitDirectSound(ao);
            MP_ERR(ao, "cannot create secondary (stream)buffer (%s)\n",
                   dserr2str(res));
            return -1;
        }
    }
    MP_VERBOSE(ao, "secondary (stream)buffer created\n");
    return 0;
}
Exemple #6
0
bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, bool bIsMusic, EEncoded bAudioPassthrough)
{
  m_uiDataChannels = iChannels;

  if(!bAudioPassthrough)
  {
    //If no channel map is specified, use the default.
    if(!channelMap)
      channelMap = (PCMChannels *)dsound_default_channel_layout[iChannels - 1];

    PCMChannels *outLayout = m_remap.SetInputFormat(iChannels, channelMap, uiBitsPerSample / 8, uiSamplesPerSec);

    for(iChannels = 0; outLayout[iChannels] != PCM_INVALID;) ++iChannels;

    BuildChannelMapping(iChannels, outLayout);
    m_remap.SetOutputFormat(iChannels, m_SpeakerOrder, false);
  }

  bool bAudioOnAllSpeakers(false);
  g_audioContext.SetupSpeakerConfig(iChannels, bAudioOnAllSpeakers, bIsMusic);
  if(bAudioPassthrough)
    g_audioContext.SetActiveDevice(CAudioContext::DIRECTSOUND_DEVICE_DIGITAL);
  else
    g_audioContext.SetActiveDevice(CAudioContext::DIRECTSOUND_DEVICE);
  m_pDSound=g_audioContext.GetDirectSoundDevice();

  m_bPause = false;
  m_bIsAllocated = false;
  m_pBuffer = NULL;
  m_uiChannels = iChannels;
  m_uiSamplesPerSec = uiSamplesPerSec;
  m_uiBitsPerSample = uiBitsPerSample;
  m_Passthrough = bAudioPassthrough;

  m_nCurrentVolume = g_settings.m_nVolumeLevel;
  m_drc = 0;

  WAVEFORMATEXTENSIBLE wfxex = {0};

  //fill waveformatex
  ZeroMemory(&wfxex, sizeof(WAVEFORMATEXTENSIBLE));
  wfxex.Format.cbSize          =  sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
  wfxex.Format.nChannels       = iChannels;
  wfxex.Format.nSamplesPerSec  = uiSamplesPerSec;
  if (bAudioPassthrough == true)
  {
    wfxex.dwChannelMask          = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
    wfxex.Format.wFormatTag      = WAVE_FORMAT_DOLBY_AC3_SPDIF;
    wfxex.SubFormat              = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
    wfxex.Format.wBitsPerSample  = 16;
    wfxex.Format.nChannels       = 2;
  }
  else
  {
    wfxex.dwChannelMask          = m_uiSpeakerMask;

    if (iChannels > 2)
      wfxex.Format.wFormatTag    = WAVE_FORMAT_EXTENSIBLE;
    else
      wfxex.Format.wFormatTag    = WAVE_FORMAT_PCM;

    wfxex.SubFormat              = _KSDATAFORMAT_SUBTYPE_PCM;
    wfxex.Format.wBitsPerSample  = uiBitsPerSample;
  }

  wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
  wfxex.Format.nBlockAlign       = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
  wfxex.Format.nAvgBytesPerSec   = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;

  m_AvgBytesPerSec = wfxex.Format.nAvgBytesPerSec;

  m_uiBytesPerFrame     = wfxex.Format.nBlockAlign;
  m_uiDataBytesPerFrame = (wfxex.Format.nBlockAlign / iChannels) * m_uiDataChannels;

  // unsure if these are the right values
  m_dwChunkSize = wfxex.Format.nBlockAlign * 3096;
  m_dwDataChunkSize = (m_dwChunkSize / iChannels) * m_uiDataChannels;
  m_dwBufferLen = m_dwChunkSize * 16;
  m_PreCacheSize = m_dwBufferLen - 2*m_dwChunkSize;

  CLog::Log(LOGDEBUG, __FUNCTION__": Packet Size = %d. Avg Bytes Per Second = %d.", m_dwChunkSize, m_AvgBytesPerSec);

  // fill in the secondary sound buffer descriptor
  DSBUFFERDESC dsbdesc;
  memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */
                  | DSBCAPS_GLOBALFOCUS         /** Allows background playing */
                  | DSBCAPS_CTRLVOLUME;         /** volume control enabled */

  if (!g_sysinfo.IsVistaOrHigher())
    dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;     /** Needed for 5.1 on emu101k, always fails on Vista, by design  */

  dsbdesc.dwBufferBytes = m_dwBufferLen;
  dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wfxex;

  // now create the stream buffer
  HRESULT res = IDirectSound_CreateSoundBuffer(m_pDSound, &dsbdesc, &m_pBuffer, NULL);
  if (res != DS_OK)
  {
    if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE)
    {
      SAFE_RELEASE(m_pBuffer);
      CLog::Log(LOGDEBUG, __FUNCTION__": Couldn't create secondary buffer (%s). Trying without LOCHARDWARE.", dserr2str(res));
      // Try without DSBCAPS_LOCHARDWARE
      dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
      res = IDirectSound_CreateSoundBuffer(m_pDSound, &dsbdesc, &m_pBuffer, NULL);
    }
    if (res != DS_OK && dsbdesc.dwFlags & DSBCAPS_CTRLVOLUME)
    {
      SAFE_RELEASE(m_pBuffer);
      CLog::Log(LOGDEBUG, __FUNCTION__": Couldn't create secondary buffer (%s). Trying without CTRLVOLUME.", dserr2str(res));
      // Try without DSBCAPS_CTRLVOLUME
      dsbdesc.dwFlags &= ~DSBCAPS_CTRLVOLUME;
      res = IDirectSound_CreateSoundBuffer(m_pDSound, &dsbdesc, &m_pBuffer, NULL);
    }
    if (res != DS_OK)
    {
      SAFE_RELEASE(m_pBuffer);
      CLog::Log(LOGERROR, __FUNCTION__": cannot create secondary buffer (%s)", dserr2str(res));
      return false;
    }
  }
  CLog::Log(LOGDEBUG, __FUNCTION__": secondary buffer created");

  m_pBuffer->Stop();

  if (DSERR_CONTROLUNAVAIL == m_pBuffer->SetVolume(g_settings.m_nVolumeLevel))
    CLog::Log(LOGINFO, __FUNCTION__": Volume control is unavailable in the current configuration");

  m_bIsAllocated = true;
  m_BufferOffset = 0;
  m_CacheLen = 0;
  m_LastCacheCheck = XbmcThreads::SystemClockMillis();

  return m_bIsAllocated;
}
/**
 * Creates a DirectSound buffer of the required format.
 *
 * This function creates the buffer we'll use to play audio.
 * In DirectSound there are two kinds of buffers:
 * - the primary buffer: which is the actual buffer that the soundcard plays
 * - the secondary buffer(s): these buffers are the one actually used by
 *    applications and DirectSound takes care of mixing them into the primary.
 *
 * Once you create a secondary buffer, you cannot change its format anymore so
 * you have to release the current one and create another.
 */
bool AudioOutputDSoundPrivate::createDSoundBuffers()
{
    WAVEFORMATEXTENSIBLE wformat;
    // TODO:  Dolby Digital AC3
    ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
    wformat.Format.cbSize =  0;
    wformat.Format.nChannels = format.channels();
    wformat.Format.nSamplesPerSec = format.sampleRate();
    wformat.Format.wFormatTag = WAVE_FORMAT_PCM;
    wformat.Format.wBitsPerSample = format.bytesPerSample() * 8;
    wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; //
    wformat.Format.nBlockAlign = wformat.Format.nChannels * format.bytesPerSample();
    wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign;
    wformat.dwChannelMask = channelLayoutToMS(format.channelLayoutFFmpeg());
    if (format.channels() > 2) {
        wformat.Format.cbSize =  sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
        wformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
        wformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
        //wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample;
    }
    switch (format.sampleFormat()) {
    case AudioFormat::SampleFormat_Float:
        wformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
        wformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
        break;
    case AudioFormat::SampleFormat_Signed16:
        wformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
        break;
    default:
        break;
    }
    // fill in primary sound buffer descriptor
    DSBUFFERDESC dsbpridesc;
    memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC));
    dsbpridesc.dwSize = sizeof(DSBUFFERDESC);
    dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
    dsbpridesc.dwBufferBytes = 0;
    dsbpridesc.lpwfxFormat = NULL;
    // create primary buffer and set its format
    HRESULT res = dsound->CreateSoundBuffer(&dsbpridesc, &prim_buf, NULL);
    if (res != DS_OK) {
        destroy();
        qWarning("Cannot create primary buffer (%s)", dserr2str(res));
        return false;
    }
    res = prim_buf->SetFormat((WAVEFORMATEX *)&wformat);
    if (res != DS_OK) {
        qWarning("Cannot set primary buffer format (%s), using standard setting (bad quality)", dserr2str(res));
    }
    qDebug("primary buffer created");

    // fill in the secondary sound buffer (=stream buffer) descriptor
    DSBUFFERDESC dsbdesc;
    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */
                      | DSBCAPS_GLOBALFOCUS       /** Allows background playing */
                      | DSBCAPS_CTRLVOLUME;       /** volume control enabled */
    dsbdesc.dwBufferBytes = bufferSizeTotal();
    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat;
    // Needed for 5.1 on emu101k - shit soundblaster
    if (format.channels() > 2)
        dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
    // now create the stream buffer
    res = dsound->CreateSoundBuffer(&dsbdesc, &stream_buf, NULL);
    if (res != DS_OK) {
        if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) {
            // Try without DSBCAPS_LOCHARDWARE
            dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
            res = dsound->CreateSoundBuffer(&dsbdesc, &stream_buf, NULL);
        }
        if (res != DS_OK) {
            destroy();
            qWarning("Cannot create secondary (stream)buffer (%s)", dserr2str(res));
            return false;
        }
    }
    qDebug( "Secondary (stream)buffer created");
    return true;
}