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

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Sample Wine Driver for Advanced Linux Sound System (ALSA) *      Based on version <final> of the ALSA API * * Copyright    2002 Eric Pouech *              2002 Marco Pietrobono * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "config.h"#include "wine/port.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <errno.h>#include <limits.h>#include <fcntl.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#ifdef HAVE_SYS_MMAN_H# include <sys/mman.h>#endif#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winerror.h"#include "winuser.h"#include "mmddk.h"#include "dsound.h"#include "dsdriver.h"#include "alsa.h"#include "wine/library.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(wave);#define FAKE_CHARPTR(s)	((char *)(unsigned long)(s))#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1)/* internal ALSALIB functions */snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm);#define MAX_WAVEOUTDRV 	(1)#define MAX_WAVEINDRV 	(1)/* state diagram for waveOut writing: * * +---------+-------------+---------------+---------------------------------+ * |  state  |  function   |     event     |            new state	     | * +---------+-------------+---------------+---------------------------------+ * |	     | open()	   |		   | STOPPED		       	     | * | PAUSED  | write()	   | 		   | PAUSED		       	     | * | STOPPED | write()	   | <thrd create> | PLAYING		  	     | * | PLAYING | write()	   | HEADER        | PLAYING		  	     | * | (other) | write()	   | <error>       |		       		     | * | (any)   | pause()	   | PAUSING	   | PAUSED		       	     | * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) | * | (any)   | reset()	   | RESETTING     | STOPPED		      	     | * | (any)   | close()	   | CLOSING	   | CLOSED		      	     | * +---------+-------------+---------------+---------------------------------+ *//* states of the playing device */#define	WINE_WS_PLAYING		0#define	WINE_WS_PAUSED		1#define	WINE_WS_STOPPED		2#define WINE_WS_CLOSED		3/* events to be send to device */enum win_wm_message {    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING};typedef struct {    enum win_wm_message 	msg;	/* message identifier */    DWORD	                param;  /* parameter for this message */    HANDLE	                hEvent;	/* if message is synchronous, handle of event for synchro */} ALSA_MSG;/* implement an in-process message ring for better performance * (compared to passing thru the server) * this ring will be used by the input (resp output) record (resp playback) routine */#define ALSA_RING_BUFFER_INCREMENT      64typedef struct {    ALSA_MSG			* messages;    int                         ring_buffer_size;    int				msg_tosave;    int				msg_toget;    HANDLE			msg_event;    CRITICAL_SECTION		msg_crst;} ALSA_MSG_RING;typedef struct {    /* Windows information */    volatile int		state;			/* one of the WINE_WS_ manifest constants */    WAVEOPENDESC		waveDesc;    WORD			wFlags;    PCMWAVEFORMAT		format;    WAVEOUTCAPSA		caps;    /* ALSA information (ALSA 0.9/1.x uses two different devices for playback/capture) */    char *			device;    snd_pcm_t*                  p_handle;                 /* handle to ALSA playback device */    snd_pcm_t*                  c_handle;                 /* handle to ALSA capture device */    snd_pcm_hw_params_t *	hw_params;		/* ALSA Hw params */    snd_ctl_t *                 ctl;                    /* control handle for the playback volume */    snd_ctl_elem_id_t *         playback_eid;		/* element id of the playback volume control */    snd_ctl_elem_value_t *      playback_evalue;	/* element value of the playback volume control */    snd_ctl_elem_info_t *       playback_einfo;         /* element info of the playback volume control */    snd_pcm_sframes_t           (*write)(snd_pcm_t *, const void *, snd_pcm_uframes_t );    struct pollfd		*ufds;    int				count;    DWORD                       dwBufferSize;           /* size of whole ALSA buffer in bytes */    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */    DWORD			dwLoops;		/* private copy of loop counter */    DWORD			dwPlayedTotal;    /* synchronization stuff */    HANDLE			hStartUpEvent;    HANDLE			hThread;    DWORD			dwThreadID;    ALSA_MSG_RING		msgRing;    /* DirectSound stuff */    DSDRIVERDESC                ds_desc;    GUID                        ds_guid;} WINE_WAVEOUT;static WINE_WAVEOUT	WOutDev   [MAX_WAVEOUTDRV];static DWORD            ALSA_WodNumDevs;static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);/* These strings used only for tracing */#if 0static const char *wodPlayerCmdString[] = {    "WINE_WM_PAUSING",    "WINE_WM_RESTARTING",    "WINE_WM_RESETTING",    "WINE_WM_HEADER",    "WINE_WM_UPDATE",    "WINE_WM_BREAKLOOP",    "WINE_WM_CLOSING",};#endif/*======================================================================* *                  Low level WAVE implementation			* *======================================================================*//************************************************************************** * 			ALSA_InitializeVolumeCtl		[internal] * * used to initialize the PCM Volume Control */static int ALSA_InitializeVolumeCtl(WINE_WAVEOUT * wwo){    snd_ctl_t *                 ctl = NULL;    snd_ctl_card_info_t *	cardinfo;    snd_ctl_elem_list_t *       elemlist;    snd_ctl_elem_id_t *         e_id;    snd_ctl_elem_info_t *       einfo;    snd_hctl_t *                hctl = NULL;    snd_hctl_elem_t *           elem;    int                         nCtrls;    int                         i;    snd_ctl_card_info_alloca(&cardinfo);    memset(cardinfo,0,snd_ctl_card_info_sizeof());    snd_ctl_elem_list_alloca(&elemlist);    memset(elemlist,0,snd_ctl_elem_list_sizeof());    snd_ctl_elem_id_alloca(&e_id);    memset(e_id,0,snd_ctl_elem_id_sizeof());    snd_ctl_elem_info_alloca(&einfo);    memset(einfo,0,snd_ctl_elem_info_sizeof());#define EXIT_ON_ERROR(f,txt) do \{ \    int err; \    if ( (err = (f) ) < 0) \    { \	ERR(txt ": %s\n", snd_strerror(err)); \	if (hctl) \	    snd_hctl_close(hctl); \	if (ctl) \	    snd_ctl_close(ctl); \	return -1; \    } \} while(0)    EXIT_ON_ERROR( snd_ctl_open(&ctl,"hw",0) , "ctl open failed" );    EXIT_ON_ERROR( snd_ctl_card_info(ctl, cardinfo), "card info failed");    EXIT_ON_ERROR( snd_ctl_elem_list(ctl, elemlist), "elem list failed");    nCtrls = snd_ctl_elem_list_get_count(elemlist);    EXIT_ON_ERROR( snd_hctl_open(&hctl,"hw",0), "hctl open failed");    EXIT_ON_ERROR( snd_hctl_load(hctl), "hctl load failed" );    elem=snd_hctl_first_elem(hctl);    for ( i= 0; i<nCtrls; i++) {	memset(e_id,0,snd_ctl_elem_id_sizeof());	snd_hctl_elem_get_id(elem,e_id);/*	TRACE("ctl: #%d '%s'%d\n",				   snd_ctl_elem_id_get_numid(e_id),				   snd_ctl_elem_id_get_name(e_id),				   snd_ctl_elem_id_get_index(e_id));*/	if ( !strcmp("PCM Playback Volume", snd_ctl_elem_id_get_name(e_id)) )	{	    EXIT_ON_ERROR( snd_hctl_elem_info(elem,einfo), "hctl elem info failed" );	    /* few sanity checks... you'll never know... */	    if ( snd_ctl_elem_info_get_type(einfo) != SND_CTL_ELEM_TYPE_INTEGER )	    	WARN("playback volume control is not an integer\n");	    if ( !snd_ctl_elem_info_is_readable(einfo) )	    	WARN("playback volume control is readable\n");	    if ( !snd_ctl_elem_info_is_writable(einfo) )	    	WARN("playback volume control is readable\n");	    TRACE("   ctrl range: min=%ld  max=%ld  step=%ld\n",	         snd_ctl_elem_info_get_min(einfo),	         snd_ctl_elem_info_get_max(einfo),	         snd_ctl_elem_info_get_step(einfo));	    EXIT_ON_ERROR( snd_ctl_elem_id_malloc(&wwo->playback_eid), "elem id malloc failed" );	    EXIT_ON_ERROR( snd_ctl_elem_info_malloc(&wwo->playback_einfo), "elem info malloc failed" );	    EXIT_ON_ERROR( snd_ctl_elem_value_malloc(&wwo->playback_evalue), "elem value malloc failed" );	    /* ok, now we can safely save these objects for later */	    snd_ctl_elem_id_copy(wwo->playback_eid, e_id);	    snd_ctl_elem_info_copy(wwo->playback_einfo, einfo);	    snd_ctl_elem_value_set_id(wwo->playback_evalue, wwo->playback_eid);	    wwo->ctl = ctl;	}	elem=snd_hctl_elem_next(elem);    }    snd_hctl_close(hctl);#undef EXIT_ON_ERROR    return 0;}/************************************************************************** * 			ALSA_XRUNRecovery		[internal] * * used to recovery from XRUN errors (buffer underflow/overflow) */static int ALSA_XRUNRecovery(WINE_WAVEOUT * wwo, int err){    if (err == -EPIPE) {    /* under-run */        err = snd_pcm_prepare(wwo->p_handle);        if (err < 0)             ERR( "underrun recovery failed. prepare failed: %s\n", snd_strerror(err));        return 0;    } else if (err == -ESTRPIPE) {        while ((err = snd_pcm_resume(wwo->p_handle)) == -EAGAIN)            sleep(1);       /* wait until the suspend flag is released */            if (err < 0) {                err = snd_pcm_prepare(wwo->p_handle);                if (err < 0)                    ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err));            }            return 0;    }    return err;}/************************************************************************** * 			ALSA_TraceParameters		[internal] * * used to trace format changes, hw and sw parameters */static void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full){    snd_pcm_format_t   format = snd_pcm_hw_params_get_format(hw_params);    snd_pcm_access_t   access = snd_pcm_hw_params_get_access(hw_params);#define X(x) ((x)? "true" : "false")    if (full)	TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s "    	      "halfd=%s joint=%s \n",	      X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params)),	      X(snd_pcm_hw_params_can_overrange(hw_params)),	      X(snd_pcm_hw_params_can_pause(hw_params)),	      X(snd_pcm_hw_params_can_resume(hw_params)),	      X(snd_pcm_hw_params_can_sync_start(hw_params)),	      X(snd_pcm_hw_params_is_batch(hw_params)),	      X(snd_pcm_hw_params_is_block_transfer(hw_params)),	      X(snd_pcm_hw_params_is_double(hw_params)),	      X(snd_pcm_hw_params_is_half_duplex(hw_params)),	      X(snd_pcm_hw_params_is_joint_duplex(hw_params)));#undef X    if (access >= 0)	TRACE("access=%s\n", snd_pcm_access_name(access));    else    {	snd_pcm_access_mask_t * acmask;	snd_pcm_access_mask_alloca(&acmask);	snd_pcm_hw_params_get_access_mask(hw_params, acmask);	for ( access = SND_PCM_ACCESS_MMAP_INTERLEAVED; access <= SND_PCM_ACCESS_LAST; access++)	    if (snd_pcm_access_mask_test(acmask, access))		TRACE("access=%s\n", snd_pcm_access_name(access));    }    if (format >= 0)    {	TRACE("format=%s\n", snd_pcm_format_name(format));    }    else    {	snd_pcm_format_mask_t *     fmask;	snd_pcm_format_mask_alloca(&fmask);	snd_pcm_hw_params_get_format_mask(hw_params, fmask);	for ( format = SND_PCM_FORMAT_S8; format <= SND_PCM_FORMAT_LAST ; format++)	    if ( snd_pcm_format_mask_test(fmask, format) )		TRACE("format=%s\n", snd_pcm_format_name(format));    }#define X(x) do { \int n = snd_pcm_hw_params_get_##x(hw_params); \if (n<0) \    TRACE(#x "_min=%ld " #x "_max=%ld\n", \        (long int)snd_pcm_hw_params_get_##x##_min(hw_params), \	(long int)snd_pcm_hw_params_get_##x##_max(hw_params)); \else \    TRACE(#x "=%d\n", n); \} while(0)    X(channels);    X(buffer_size);#undef X#define X(x) do { \int n = snd_pcm_hw_params_get_##x(hw_params,0); \if (n<0) \    TRACE(#x "_min=%ld " #x "_max=%ld\n", \        (long int)snd_pcm_hw_params_get_##x##_min(hw_params,0), \	(long int)snd_pcm_hw_params_get_##x##_max(hw_params,0)); \else \    TRACE(#x "=%d\n", n); \} while(0)    X(rate);    X(buffer_time);    X(periods);    X(period_size);    X(period_time);    X(tick_time);#undef X    if (!sw)	return;}

⌨️ 快捷键说明

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