📄 audio.c
字号:
if ((ret = OSS_RawOpenDevice(ossdev,strict_format)) != MMSYSERR_NOERROR) return ret; } else { /* check we really open with the same parameters */ if (ossdev->open_access != req_access) { ERR("FullDuplex: Mismatch in access. Your sound device is not full duplex capable.\n"); return WAVERR_BADFORMAT; } /* check if the audio parameters are the same */ if (ossdev->sample_rate != sample_rate || ossdev->stereo != stereo || ossdev->format != fmt) { /* This is not a fatal error because MSACM might do the remapping */ WARN("FullDuplex: mismatch in PCM parameters for input and output\n" "OSS doesn't allow us different parameters\n" "audio_frag(%x/%x) sample_rate(%d/%d) stereo(%d/%d) fmt(%d/%d)\n", ossdev->audio_fragment, frag ? *frag : 0, ossdev->sample_rate, sample_rate, ossdev->stereo, stereo, ossdev->format, fmt); return WAVERR_BADFORMAT; } /* check if the fragment sizes are the same */ if (ossdev->audio_fragment != (frag ? *frag : 0) ) { ERR("FullDuplex: Playback and Capture hardware acceleration levels are different.\n" "Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n"); return WAVERR_BADFORMAT; } if (GetCurrentThreadId() != ossdev->owner_tid) { WARN("Another thread is trying to access audio...\n"); return MMSYSERR_ERROR; } } ossdev->open_count++; return MMSYSERR_NOERROR;}/****************************************************************** * OSS_CloseDevice * * */static void OSS_CloseDevice(OSS_DEVICE* ossdev){ TRACE("(%p)\n",ossdev); if (ossdev->open_count>0) { ossdev->open_count--; } else { WARN("OSS_CloseDevice called too many times\n"); } if (ossdev->open_count == 0) { /* reset the device before we close it in case it is in a bad state */ ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0); close(ossdev->fd); }}/****************************************************************** * OSS_ResetDevice * * Resets the device. OSS Commercial requires the device to be closed * after a SNDCTL_DSP_RESET ioctl call... this function implements * this behavior... * FIXME: This causes problems when doing full duplex so we really * only reset when not doing full duplex. We need to do this better * someday. */static DWORD OSS_ResetDevice(OSS_DEVICE* ossdev){ DWORD ret = MMSYSERR_NOERROR; int old_fd = ossdev->fd; TRACE("(%p)\n", ossdev); if (ossdev->open_count == 1) { if (ioctl(ossdev->fd, SNDCTL_DSP_RESET, NULL) == -1) { perror("ioctl SNDCTL_DSP_RESET"); return -1; } close(ossdev->fd); ret = OSS_RawOpenDevice(ossdev, 1); TRACE("Changing fd from %d to %d\n", old_fd, ossdev->fd); } else WARN("Not resetting device because it is in full duplex mode!\n"); return ret;}const static int win_std_oss_fmts[2]={AFMT_U8,AFMT_S16_LE};const static int win_std_rates[5]={96000,48000,44100,22050,11025};const static int win_std_formats[2][2][5]= {{{WAVE_FORMAT_96M08, WAVE_FORMAT_48M08, WAVE_FORMAT_4M08, WAVE_FORMAT_2M08, WAVE_FORMAT_1M08}, {WAVE_FORMAT_96S08, WAVE_FORMAT_48S08, WAVE_FORMAT_4S08, WAVE_FORMAT_2S08, WAVE_FORMAT_1S08}}, {{WAVE_FORMAT_96M16, WAVE_FORMAT_48M16, WAVE_FORMAT_4M16, WAVE_FORMAT_2M16, WAVE_FORMAT_1M16}, {WAVE_FORMAT_96S16, WAVE_FORMAT_48S16, WAVE_FORMAT_4S16, WAVE_FORMAT_2S16, WAVE_FORMAT_1S16}}, };/****************************************************************** * OSS_WaveOutInit * * */static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev){ int rc,arg; int f,c,r; TRACE("(%p) %s\n", ossdev, ossdev->dev_name); if (OSS_OpenDevice(ossdev, O_WRONLY, NULL, 0,-1,-1,-1) != 0) return FALSE; ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);#ifdef SOUND_MIXER_INFO { int mixer; if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) { mixer_info info; if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) { close(mixer); strncpy(ossdev->ds_desc.szDesc, info.name, sizeof(info.name)); strcpy(ossdev->ds_desc.szDrvName, "wineoss.drv"); strncpy(ossdev->out_caps.szPname, info.name, sizeof(info.name)); TRACE("%s\n", ossdev->ds_desc.szDesc); } else { ERR("%s: can't read info!\n", ossdev->mixer_name); OSS_CloseDevice(ossdev); close(mixer); return FALSE; } } else { ERR("%s: %s\n", ossdev->mixer_name , strerror( errno )); OSS_CloseDevice(ossdev); return FALSE; } }#endif /* SOUND_MIXER_INFO */ /* FIXME: some programs compare this string against the content of the * registry for MM drivers. The names have to match in order for the * program to work (e.g. MS win9x mplayer.exe) */#ifdef EMULATE_SB16 ossdev->out_caps.wMid = 0x0002; ossdev->out_caps.wPid = 0x0104; strcpy(ossdev->out_caps.szPname, "SB16 Wave Out");#else ossdev->out_caps.wMid = 0x00FF; /* Manufac ID */ ossdev->out_caps.wPid = 0x0001; /* Product ID */#endif ossdev->out_caps.vDriverVersion = 0x0100; ossdev->out_caps.wChannels = 1; ossdev->out_caps.dwFormats = 0x00000000; ossdev->out_caps.wReserved1 = 0; ossdev->out_caps.dwSupport = WAVECAPS_VOLUME; /* direct sound caps */ ossdev->ds_caps.dwFlags = 0; ossdev->ds_caps.dwPrimaryBuffers = 1; ossdev->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; ossdev->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; if (WINE_TRACE_ON(wave)) { /* Note that this only reports the formats supported by the hardware. * The driver may support other formats and do the conversions in * software which is why we don't use this value */ int oss_mask; ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &oss_mask); TRACE("OSS dsp out mask=%08x\n", oss_mask); } /* We must first set the format and the stereo mode as some sound cards * may support 44kHz mono but not 44kHz stereo. Also we must * systematically check the return value of these ioctls as they will * always succeed (see OSS Linux) but will modify the parameter to match * whatever they support. The OSS specs also say we must first set the * sample size, then the stereo and then the sample rate. */ for (f=0;f<2;f++) { arg=win_std_oss_fmts[f]; rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); if (rc!=0 || arg!=win_std_oss_fmts[f]) { TRACE("DSP_SAMPLESIZE: rc=%d returned %d for %d\n", rc,arg,win_std_oss_fmts[f]); continue; } if (f == 0) ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY8BIT; else if (f == 1) ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY16BIT; for (c=0;c<2;c++) { arg=c; rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg); if (rc!=0 || arg!=c) { TRACE("DSP_STEREO: rc=%d returned %d for %d\n",rc,arg,c); continue; } if (c == 0) { ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO; } else if (c==1) { ossdev->out_caps.wChannels=2; ossdev->out_caps.dwSupport|=WAVECAPS_LRVOLUME; ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO; } for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) { arg=win_std_rates[r]; rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n", rc,arg,win_std_rates[r],win_std_oss_fmts[f],c+1); if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r])) ossdev->out_caps.dwFormats|=win_std_formats[f][c][r]; } } } if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) { TRACE("OSS dsp out caps=%08X\n", arg); if (arg & DSP_CAP_TRIGGER) ossdev->bTriggerSupport = TRUE; if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) { ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE; } /* well, might as well use the DirectSound cap flag for something */ if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) && !(arg & DSP_CAP_BATCH)) { ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND; } else { ossdev->ds_caps.dwFlags |= DSCAPS_EMULDRIVER; } } OSS_CloseDevice(ossdev); TRACE("out dwFormats = %08lX, dwSupport = %08lX\n", ossdev->out_caps.dwFormats, ossdev->out_caps.dwSupport); return TRUE;}/****************************************************************** * OSS_WaveInInit * * */static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev){ int rc,arg; int f,c,r; TRACE("(%p) %s\n", ossdev, ossdev->dev_name); if (OSS_OpenDevice(ossdev, O_RDONLY, NULL, 0,-1,-1,-1) != 0) return FALSE; ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);#ifdef SOUND_MIXER_INFO { int mixer; if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) { mixer_info info; if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) { close(mixer); strncpy(ossdev->in_caps.szPname, info.name, sizeof(info.name)); TRACE("%s\n", ossdev->ds_desc.szDesc); } else { ERR("%s: can't read info!\n", ossdev->mixer_name); OSS_CloseDevice(ossdev); close(mixer); return FALSE; } } else { ERR("%s: %s\n", ossdev->mixer_name, strerror(errno)); OSS_CloseDevice(ossdev); return FALSE; } }#endif /* SOUND_MIXER_INFO */ /* See comment in OSS_WaveOutInit */#ifdef EMULATE_SB16 ossdev->in_caps.wMid = 0x0002; ossdev->in_caps.wPid = 0x0004; strcpy(ossdev->in_caps.szPname, "SB16 Wave In");#else ossdev->in_caps.wMid = 0x00FF; /* Manufac ID */ ossdev->in_caps.wPid = 0x0001; /* Product ID */#endif ossdev->in_caps.dwFormats = 0x00000000; ossdev->in_caps.wChannels = 1; ossdev->in_caps.wReserved1 = 0; /* direct sound caps */ ossdev->dsc_caps.dwSize = sizeof(ossdev->dsc_caps); ossdev->dsc_caps.dwFlags = 0; ossdev->dsc_caps.dwFormats = 0x00000000; ossdev->dsc_caps.dwChannels = 1; if (WINE_TRACE_ON(wave)) { /* Note that this only reports the formats supported by the hardware. * The driver may support other formats and do the conversions in * software which is why we don't use this value */ int oss_mask; ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &oss_mask); TRACE("OSS dsp out mask=%08x\n", oss_mask); } /* See the comment in OSS_WaveOutInit */ for (f=0;f<2;f++) { arg=win_std_oss_fmts[f]; rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); if (rc!=0 || arg!=win_std_oss_fmts[f]) { TRACE("DSP_SAMPLESIZE: rc=%d returned 0x%x for 0x%x\n", rc,arg,win_std_oss_fmts[f]); continue; } for (c=0;c<2;c++) { arg=c; rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg); if (rc!=0 || arg!=c) { TRACE("DSP_STEREO: rc=%d returned %d for %d\n",rc,arg,c); continue; } if (c==1) { ossdev->in_caps.wChannels=2; ossdev->dsc_caps.dwChannels=2; } for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) { arg=win_std_rates[r]; rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",rc,arg,win_std_rates[r],win_std_oss_fmts[f],c+1); if (rc==0 && NEAR_MATCH(arg,win_std_rates[r])) ossdev->in_caps.dwFormats|=win_std_formats[f][c][r]; ossdev->dsc_caps.dwFormats|=win_std_formats[f][c][r]; } } } if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) { TRACE("OSS dsp in caps=%08X\n", arg); if (arg & DSP_CAP_TRIGGER) ossdev->bTriggerSupport = TRUE; if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) && !(arg & DSP_CAP_BATCH)) { /* FIXME: enable the next statement if you want to work on the driver */#if 0 ossdev->in_caps_support |= WAVECAPS_DIRECTSOUND;#endif } if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) ossdev->in_caps_support |= WAVECAPS_SAMPLEACCURATE; } OSS_CloseDevice(ossdev); TRACE("in dwFormats = %08lX\n", ossdev->in_caps.dwFormats); return TRUE;}/****************************************************************** * OSS_WaveFullDuplexInit * * */static void OSS_WaveFullDuplexInit(OSS_DEVICE* ossdev){ int caps; TRACE("(%p)\n",ossdev); if (OSS_OpenDevice(ossdev, O_RDWR, NULL, 0,-1,-1,-1) != 0) return; if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &caps) == 0) { ossdev->full_duplex = (caps & DSP_CAP_DUPLEX); } OSS_CloseDevice(ossdev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -