📄 usbspeakerlib.c
字号:
pSeqDev->nextStartFrame = (currentFrame + FRAME_SKIP) % pSeqDev->frameWindow; } /* Use the next IRP to transmit a block of data. Each IRP always * transfers half of the data buffer or the entire block of * remaining data if the stream has been closed. */ extLen = pSeqDev->audioBfrCount - pSeqDev->audioBfrPending; extLen = min (extLen, pSeqDev->audioBfrHalf); if (extLen < pSeqDev->audioBfrHalf && pSeqDev->open) break; frameCount = ((extLen * MSEC_PER_SEC) + pSeqDev->bytesPerSec - 1) / pSeqDev->bytesPerSec; if (frameCount == 0) break; /* Initialize the IRP. */ pIrp = &pSeqDev->irp [pSeqDev->nextIrp]; pSeqDev->irpsInUse++; if (++pSeqDev->nextIrp == IRP_COUNT) pSeqDev->nextIrp = 0; memset (pIrp, 0, sizeof (*pIrp)); pIrp->userPtr = pSeqDev; pIrp->irpLen = sizeof (*pIrp); pIrp->userCallback = usbSpkrIrpCallback; pIrp->timeout = USB_TIMEOUT_NONE; pIrp->startFrame = pSeqDev->nextStartFrame; pIrp->dataBlockSize = pSeqDev->sampleSize; pIrp->transferLen = extLen; pIrp->bfrCount = 1; pIrp->bfrList [0].pid = USB_PID_OUT; pIrp->bfrList [0].pBfr = &pSeqDev->pAudioBfr [pSeqDev->audioBfrOut]; pIrp->bfrList [0].bfrLen = extLen; pSeqDev->audioBfrPending += extLen; if ((pSeqDev->audioBfrOut += extLen) == pSeqDev->audioBfrLen) pSeqDev->audioBfrOut = 0; pSeqDev->nextStartFrame = (pSeqDev->nextStartFrame + frameCount) % pSeqDev->frameWindow; pSeqDev->blocksSent++; /* Send the data */ if (usbdTransfer (usbdHandle, pSeqDev->isochPipeHandle, pIrp) != OK) { pSeqDev->streamFault = TRUE; status = ERROR; } } return status; }/***************************************************************************** usbSpkrIrpCallback - invoked when IRPs complete** Examines the result of each IRP. Attempts to initiate new transmission.** NOTE: By convention, the userPtr field in each IRP is a pointer to the* corresponding USB_SPKR_SEQ_DEV structure.** RETURNS: N/A** ERRNO: none** \NOMANUAL*/LOCAL VOID usbSpkrIrpCallback ( pVOID p ) { pUSB_IRP pIrp = (pUSB_IRP) p; pUSB_SPKR_SEQ_DEV pSeqDev = (pUSB_SPKR_SEQ_DEV) pIrp->userPtr; OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); /* Look for out-of-order IRP completion */ if (pIrp != &pSeqDev->irp [pSeqDev->nextDoneIrp]) { pSeqDev->streamFault = TRUE; } else { /* Indicate an IRP has completed and update buffer pointers */ pSeqDev->irpsInUse--; if (++pSeqDev->nextDoneIrp == IRP_COUNT) pSeqDev->nextDoneIrp = 0; pSeqDev->audioBfrPending -= pIrp->transferLen; pSeqDev->audioBfrCount -= pIrp->transferLen; /* Examine the IRP result */ if (pIrp->result != S_usbHcdLib_IRP_CANCELED) updateTransmitter (pSeqDev); else pSeqDev->streamFault = TRUE; } /* The completion of any IRP, successfully or otherwise, unblocks * the foreground thread. */ if (pSeqDev->foregroundWaiting) { pSeqDev->foregroundWaiting = FALSE; OSS_SEM_GIVE (pSeqDev->bfrNotFullSem); } /* The following call to destroyAudioStream() doesn't do anything * unless the audio play is complete or there has been an error. */ if(pSeqDev->stopFlag == FALSE) destroyAudioStream (pSeqDev, FALSE); OSS_MUTEX_RELEASE (speakerMutex); }/***************************************************************************** usbSpkrSeqRd - SEQ_DEV sequential read routine** This function reads the SEQ_DEV seqential read routine. * * RETURNS: not supported, always returns ERROR.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrSeqRd ( pUSB_SPKR_SEQ_DEV pSeqDev, /* pointer to device descriptor */ int numBytes, /* number of bytes to read */ char *buffer, /* pointer to buffer to receive data */ BOOL fixed /* TRUE => fixed block size */ ) { return ERROR; }/***************************************************************************** usbSpkrSeqWt - SEQ_DEV sequential write routine** This writes into the audio buffer* * RETURNS: OK if transfer successful, else ERROR.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrSeqWrt ( pUSB_SPKR_SEQ_DEV pSeqDev, /* pointer to device descriptor */ int numBytes, /* number of bytes or blocks to be written */ char *buffer, /* ptr to input data buffer */ BOOL fixed /* TRUE => fixed block size */ ) { UINT32 extLen; /* If the audio stream isn't open, we don't accept input */ if (!pSeqDev->open) return EIO; /* Copy audio data to our internal buffer. */ OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); while (numBytes > 0 && !pSeqDev->streamFault) { /* If our internal buffer is full, wait for space to become avail. */ if (pSeqDev->audioBfrCount == pSeqDev->audioBfrLen) { pSeqDev->foregroundWaiting = TRUE; OSS_MUTEX_RELEASE (speakerMutex); OSS_SEM_TAKE (pSeqDev->bfrNotFullSem, OSS_BLOCK); OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); if (pSeqDev->streamFault) break; } /* Calculate length of next contiguous extent in buffer */ if (pSeqDev->audioBfrIn < pSeqDev->audioBfrOut) extLen = pSeqDev->audioBfrOut - pSeqDev->audioBfrIn; else extLen = pSeqDev->audioBfrLen - pSeqDev->audioBfrIn; extLen = min (extLen, pSeqDev->audioBfrLen - pSeqDev->audioBfrCount); /* Copy data to buffer */ extLen = min (extLen, (unsigned)numBytes); memcpy (&pSeqDev->pAudioBfr [pSeqDev->audioBfrIn], buffer, extLen); buffer += extLen; numBytes -= extLen; pSeqDev->audioBfrCount += extLen; pSeqDev->audioBfrTotal += extLen; if ((pSeqDev->audioBfrIn += extLen) == pSeqDev->audioBfrLen) pSeqDev->audioBfrIn = 0; /* Update transmitter. */ if (updateTransmitter (pSeqDev) != OK) { OSS_MUTEX_RELEASE (speakerMutex); return EIO; } } OSS_MUTEX_RELEASE (speakerMutex); if (numBytes == 0) return OK; else return EIO; }/***************************************************************************** usbSpkrIoctl - SEQ_DEV IOCTL routine** This function handles the various ioctl functions** RETURNS: OK if IOCTL handled successfully, ENOSYS if unsupported* request, or EIO for other errors.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrIoctl ( pUSB_SPKR_SEQ_DEV pSeqDev, /* pointer to device descriptor */ int funcCode, /* ioctl() function code */ int arg /* function-specific argument */ ) { STATUS status = OK; /* Handle IOCTL */ switch (funcCode) { case USB_SPKR_IOCTL_GET_FORMAT_COUNT: /* Return could of supported audio formats */ *((pUINT16) arg) = pSeqDev->fmtCount; break; case USB_SPKR_IOCTL_GET_FORMAT_LIST: /* Return pointer to array of audio formats */ *((pUSB_SPKR_AUDIO_FORMAT *) arg) = pSeqDev->pFmt; break; case USB_SPKR_IOCTL_GET_CHANNEL_COUNT: /* Return count of audio channels + 1 for master channel */ *((pUINT16) arg) = pSeqDev->channels; break; case USB_SPKR_IOCTL_GET_CHANNEL_CONFIG: /* Return configuration of channels */ *((pUINT16) arg) = pSeqDev->channelConfig; break; case USB_SPKR_IOCTL_GET_CHANNEL_CAPS: /* Return pointer to capabilities array for all channels */ *((pUSB_SPKR_CHANNEL_CAPS *) arg) = pSeqDev->pCaps; break; case USB_SPKR_IOCTL_SET_AUDIO_FORMAT: /* Find a format matching the one indicated by the caller */ if (selectFormat (pSeqDev, (pUSB_SPKR_AUDIO_FORMAT) arg) != OK) status = ENOSYS; break; case USB_SPKR_IOCTL_OPEN_AUDIO_STREAM: /* Begin an audio stream. */ status = openAudioStream (pSeqDev); break; case USB_SPKR_IOCTL_CLOSE_AUDIO_STREAM: /* mark the end of an audio stream */ if (arg) pSeqDev->stopFlag = TRUE; status = closeAudioStream (pSeqDev); break; case USB_SPKR_IOCTL_AUDIO_STREAM_STATUS: /* report whether the audio device is still busy. */ *((pUINT16) arg) = 0; if (pSeqDev->open) *((pUINT16) arg) |= USB_SPKR_STATUS_OPEN; if (pSeqDev->audioBfrCount) *((pUINT16) arg) |= USB_SPKR_STATUS_DATA_IN_BFR; break; case USB_SPKR_IOCTL_SET_MUTE: case USB_SPKR_IOCTL_SET_VOLUME: case USB_SPKR_IOCTL_SET_BASS: case USB_SPKR_IOCTL_SET_MID: case USB_SPKR_IOCTL_SET_TREBLE: /* Set indicated channel control. MSW(arg) = channel, * LSW(arg) = value. */ status = setChannelControl (pSeqDev, funcCode, MSW (arg), LSW (arg)); break; default: status = ENOSYS; break; } return status; } /***************************************************************************** usbSpkrSeqWrtFileMarks - SEQ_DEV sequential write file marks routine** SEQ_DEV sequential write file marks routine** RETURNS: not implemented. Always returns OK for compatibility.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrSeqWrtFileMarks ( pUSB_SPKR_SEQ_DEV pSeqDev, /* pointer to device descriptor */ int numMarks, /* number of file marks to write */ BOOL shortMark /* short or long file marks */ ) { return OK; }/***************************************************************************** usbSpkrRewind - SEQ_DEV rewind routine** This function is not implemented** RETURNS: not implemented. Always returns OK for compatibility.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrRewind ( pUSB_SPKR_SEQ_DEV pSeqDev /* pointer to device descriptor */ ) { return OK; }/***************************************************************************** usbSpkrReserve - SEQ_DEV reserve routine** This function makes SEQ_DEV descriptor reserved** RETURNS: OK if device can be reserved, else ERROR.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrReserve ( pUSB_SPKR_SEQ_DEV pSeqDev /* pointer to device descriptor */ ) { STATUS status; OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); if (!pSeqDev->reserved) { pSeqDev->reserved = TRUE; status = OK; } else { status = ERROR; } OSS_MUTEX_RELEASE (speakerMutex); return status; }/***************************************************************************** usbSpkrRelease - SEQ_DEV release routine** This function releases the SEQ_DEV descriptor structure** RETURNS: OK if device can be released, else ERROR.** ERRNO: none** \NOMANUAL*/LOCAL STATUS usbSpkrRelease ( pUSB_SPKR_SEQ_DEV pSeqDev /* pointer to device descriptor */ ) { STATUS status; OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); if (pSeqDev->reserved) { pSeqDev->reserved = FALSE; status = OK; } else { status = ERROR; } OSS_MUTEX_RELEASE (speakerMutex); return status; }/***************************************************************************** usbSpkrReadBlkLim - SEQ_DEV read block limit routine** This function blocks the read block ** RETURNS: always returns OK.** ERRNO: none
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -