⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 4 页
字号:
    switch (wMsg) {    case WOM_OPEN:    case WOM_CLOSE:    case WOM_DONE:      if (wwo->wFlags != DCB_NULL &&        !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,          (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,          dwParam1, dwParam2))      {        WARN("can't notify client !\n");        return MMSYSERR_ERROR;      }    break;    default:      FIXME("Unknown callback message %u\n", wMsg);        return MMSYSERR_INVALPARAM;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodHelper_BeginWaveHdr          [internal] * * Makes the specified lpWaveHdr the currently playing wave header. * If the specified wave header is a begin loop and we're not already in * a loop, setup the loop. */static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr){    EnterCriticalSection(&wwo->access_crst);    wwo->lpPlayPtr = lpWaveHdr;    if (!lpWaveHdr)    {       LeaveCriticalSection(&wwo->access_crst);       return;    }    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)    {      if (wwo->lpLoopPtr)      {        WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);        TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);      } else      {        TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);        wwo->lpLoopPtr = lpWaveHdr;        /* Windows does not touch WAVEHDR.dwLoops,         * so we need to make an internal copy */        wwo->dwLoops = lpWaveHdr->dwLoops;      }    }    wwo->dwPartialOffset = 0;    LeaveCriticalSection(&wwo->access_crst);}/************************************************************************** * 				wodHelper_PlayPtrNext	        [internal] * * Advance the play pointer to the next waveheader, looping if required. */static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo){  LPWAVEHDR lpWaveHdr;  EnterCriticalSection(&wwo->access_crst);  lpWaveHdr = wwo->lpPlayPtr;  wwo->dwPartialOffset = 0;  if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)  {    /* We're at the end of a loop, loop if required */    if (--wwo->dwLoops > 0)    {      wwo->lpPlayPtr = wwo->lpLoopPtr;    } else    {      /* Handle overlapping loops correctly */      if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {        FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");        /* shall we consider the END flag for the closing loop or for         * the opening one or for both ???         * code assumes for closing loop only         */      } else      {        lpWaveHdr = lpWaveHdr->lpNext;      }      wwo->lpLoopPtr = NULL;      wodHelper_BeginWaveHdr(wwo, lpWaveHdr);    }  } else  {     /* We're not in a loop.  Advance to the next wave header */    TRACE("not inside of a loop, advancing to next wave header\n");    wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);  }  LeaveCriticalSection(&wwo->access_crst);  return lpWaveHdr;}/* if force is TRUE then notify the client that all the headers were completed */static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force){  LPWAVEHDR		lpWaveHdr;  DWORD retval;  TRACE("called\n");  EnterCriticalSection(&wwo->access_crst);  /* Start from lpQueuePtr and keep notifying until:   * - we hit an unwritten wavehdr   * - we hit the beginning of a running loop   * - we hit a wavehdr which hasn't finished playing   */  while ((lpWaveHdr = wwo->lpQueuePtr) &&           (force ||             (lpWaveHdr != wwo->lpPlayPtr &&             lpWaveHdr != wwo->lpLoopPtr)))  {    wwo->lpQueuePtr = lpWaveHdr->lpNext;    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;    lpWaveHdr->dwFlags |= WHDR_DONE;    TRACE("calling notify client\n");    wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);  }  retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr !=               wwo->lpLoopPtr) ? 0 : INFINITE;  LeaveCriticalSection(&wwo->access_crst);  return retval;}/************************************************************************** * 				wodHelper_Reset			[internal] * * Resets current output stream. */static  void  wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset){    EnterCriticalSection(&wwo->access_crst);     /* updates current notify list */    wodHelper_NotifyCompletions(wwo, FALSE);    if (reset)    {        /* remove all wave headers and notify client that all headers were completed */        wodHelper_NotifyCompletions(wwo, TRUE);        wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;        wwo->state = WINE_WS_STOPPED;        wwo->dwPlayedTotal = wwo->dwWrittenTotal = wwo->bytesInJack = 0;        wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */    } else    {        if (wwo->lpLoopPtr)        {            /* complicated case, not handled yet (could imply modifying the loop counter) */            FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");            wwo->lpPlayPtr = wwo->lpLoopPtr;            wwo->dwPartialOffset = 0;            wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */        } else        {            LPWAVEHDR   ptr;            DWORD       sz = wwo->dwPartialOffset;            /* reset all the data as if we had written only up to lpPlayedTotal bytes */            /* compute the max size playable from lpQueuePtr */            for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)            {                sz += ptr->dwBufferLength;            }            /* because the reset lpPlayPtr will be lpQueuePtr */            if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");            wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);            wwo->dwWrittenTotal = wwo->dwPlayedTotal;            wwo->lpPlayPtr = wwo->lpQueuePtr;        }        wwo->state = WINE_WS_PAUSED;    }     LeaveCriticalSection(&wwo->access_crst);}/************************************************************************** * 			wodGetDevCaps				[internal] */static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize){    TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);        if (lpCaps == NULL) return MMSYSERR_NOTENABLED;        if (wDevID >= MAX_WAVEOUTDRV)    {      TRACE("MAX_WAVOUTDRV reached !\n");      return MMSYSERR_BADDEVICEID;    }    memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodOpen				[internal] */static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags){    WINE_WAVEOUT*	wwo;    DWORD retval;    TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);    if (lpDesc == NULL)    {      WARN("Invalid Parameter !\n");      return MMSYSERR_INVALPARAM;    }    if (wDevID >= MAX_WAVEOUTDRV) {      TRACE("MAX_WAVOUTDRV reached !\n");      return MMSYSERR_BADDEVICEID;    }#if JACK_CLOSE_HACK    if(WOutDev[wDevID].client && WOutDev[wDevID].in_use)#else    if(WOutDev[wDevID].client)#endif    {      TRACE("device %d already allocated\n", wDevID);      return MMSYSERR_ALLOCATED;    }    /* make sure we aren't being opened in 8 bit mode */    if(lpDesc->lpFormat->wBitsPerSample == 8)    {      TRACE("8bits per sample unsupported, returning WAVERR_BADFORMAT\n");      return WAVERR_BADFORMAT;    }    wwo = &WOutDev[wDevID];    wwo->wDevID = wDevID;    /* Set things up before we call JACK_OpenDevice because */    /* we will start getting callbacks before JACK_OpenDevice */    /* even returns and we want to be initialized before then */    wwo->state = WINE_WS_STOPPED; /* start in a stopped state */    wwo->dwPlayedTotal = 0; /* zero out these totals */    wwo->dwWrittenTotal = 0;    wwo->bytesInJack = 0;    wwo->tickCountMS = 0;    InitializeCriticalSection(&wwo->access_crst); /* initialize the critical section */    /* open up jack ports for this device */    if (!JACK_OpenDevice(&WOutDev[wDevID]))    {      ERR("JACK_OpenDevice(%d) failed\n", wDevID);      return MMSYSERR_ERROR;		/* return unspecified error */    }    /* only PCM format is supported so far... */    if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||      lpDesc->lpFormat->nChannels == 0 ||      lpDesc->lpFormat->nSamplesPerSec == 0)    {      WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",       lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,       lpDesc->lpFormat->nSamplesPerSec);      return WAVERR_BADFORMAT;    }    if (dwFlags & WAVE_FORMAT_QUERY)    {      TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",       lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,       lpDesc->lpFormat->nSamplesPerSec);      return MMSYSERR_NOERROR;    }    dwFlags &= ~WAVE_DIRECTSOUND;  /* direct sound not supported, ignore the flag */    EnterCriticalSection(&wwo->access_crst);    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);        memcpy(&wwo->waveDesc, lpDesc, 	     sizeof(WAVEOPENDESC));    memcpy(&wwo->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));    LeaveCriticalSection(&wwo->access_crst);    /* display the current wave format */    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",     wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,    wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,    wwo->format.wf.nBlockAlign);    /* make sure that we have the same sample rate in our audio stream */    /* as we do in the jack server */    if(wwo->format.wf.nSamplesPerSec != wwo->sample_rate)    {      TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",         wwo->sample_rate, wwo->format.wf.nSamplesPerSec);#if JACK_CLOSE_HACK      JACK_CloseDevice(wwo, FALSE); /* close this device, don't force the client to close */#else      JACK_CloseDevice(wwo); /* close this device */#endif      return WAVERR_BADFORMAT;    }    /* check for an invalid number of bits per sample */    if (wwo->format.wBitsPerSample == 0)    {      WARN("Resetting zeroed wBitsPerSample to 16\n");      wwo->format.wBitsPerSample = 16 *      (wwo->format.wf.nAvgBytesPerSec /       wwo->format.wf.nSamplesPerSec) /       wwo->format.wf.nChannels;    }    EnterCriticalSection(&wwo->access_crst);    retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);    LeaveCriticalSection(&wwo->access_crst);    return retval;}/************************************************************************** * 				wodClose			[internal] */static DWORD wodClose(WORD wDevID){    DWORD		ret = MMSYSERR_NOERROR;    WINE_WAVEOUT*	wwo;    TRACE("(%u);\n", wDevID);    if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)    {      WARN("bad device ID !\n");      return MMSYSERR_BADDEVICEID;    }        wwo = &WOutDev[wDevID];    if (wwo->lpQueuePtr)    {      WARN("buffers still playing !\n");      ret = WAVERR_STILLPLAYING;    } else    {      /* sanity check: this should not happen since the device must have been reset before */      if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");      wwo->state = WINE_WS_CLOSED; /* mark the device as closed */#if JACK_CLOSE_HACK      JACK_CloseDevice(wwo, FALSE); /* close the jack device, DO NOT force the client to close */#else      JACK_CloseDevice(wwo); /* close the jack device */      DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */#endif      ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);    }    return ret;}/************************************************************************** * 				wodWrite			[internal] *  */static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){    LPWAVEHDR*wh;    WINE_WAVEOUT *wwo;    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);        /* first, do the sanity checks... */    if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)    {      WARN("bad dev ID !\n");      return MMSYSERR_BADDEVICEID;    }    wwo = &WOutDev[wDevID];    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))    {      TRACE("unprepared\n");      return WAVERR_UNPREPARED;    }        if (lpWaveHdr->dwFlags & WHDR_INQUEUE)     {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -