mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04:00 
			
		
		
		
	Implement the channel mapping API
Added new channel-mapping API functions. Not all plugins are covered, especially the route, multi and external plugins don't work yet. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									1ef1c5cdb4
								
							
						
					
					
						commit
						3c4a22ea49
					
				
					 27 changed files with 386 additions and 0 deletions
				
			
		|  | @ -182,6 +182,13 @@ typedef enum _snd_ctl_event_type { | |||
| /** Mute state */ | ||||
| #define SND_CTL_TLV_DB_GAIN_MUTE	-9999999 | ||||
| 
 | ||||
| /** TLV type - fixed channel map positions */ | ||||
| #define SND_CTL_TLVT_CHMAP_FIXED	0x00101 | ||||
| /** TLV type - freely swappable channel map positions */ | ||||
| #define SND_CTL_TLVT_CHMAP_VAR		0x00102 | ||||
| /** TLV type - pair-wise swappable channel map positions */ | ||||
| #define SND_CTL_TLVT_CHMAP_PAIRED	0x00103 | ||||
| 
 | ||||
| /** CTL type */ | ||||
| typedef enum _snd_ctl_type { | ||||
| 	/** Kernel level CTL */ | ||||
|  |  | |||
|  | @ -474,6 +474,18 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout); | |||
| int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2); | ||||
| int snd_pcm_unlink(snd_pcm_t *pcm); | ||||
| 
 | ||||
| enum { | ||||
| 	SND_CHMAP_NONE = 0,	/** unspecified channel position */ | ||||
| 	SND_CHMAP_FIXED,	/** fixed channel position */ | ||||
| 	SND_CHMAP_VAR,		/** freely swappable channel position */ | ||||
| 	SND_CHMAP_PAIRED,	/** pair-wise swappable channel position */ | ||||
| }; | ||||
| 
 | ||||
| int **snd_pcm_query_chmaps(snd_pcm_t *pcm); | ||||
| void snd_pcm_free_chmaps(int **maps); | ||||
| int *snd_pcm_get_chmap(snd_pcm_t *pcm); | ||||
| int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map); | ||||
| 
 | ||||
| //int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem);
 | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -477,6 +477,31 @@ enum { | |||
| 	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, | ||||
| }; | ||||
| 
 | ||||
| /* channel positions */ | ||||
| enum { | ||||
| 	SNDRV_CHMAP_UNKNOWN = 0, | ||||
| 	SNDRV_CHMAP_FL,		/* front left */ | ||||
| 	SNDRV_CHMAP_FC,		/* front center */ | ||||
| 	SNDRV_CHMAP_FR,		/* front right */ | ||||
| 	SNDRV_CHMAP_FLC,	/* front left center */ | ||||
| 	SNDRV_CHMAP_FRC,	/* front right center */ | ||||
| 	SNDRV_CHMAP_RL,		/* rear left */ | ||||
| 	SNDRV_CHMAP_RC,		/* rear center */ | ||||
| 	SNDRV_CHMAP_RR,		/* rear right */ | ||||
| 	SNDRV_CHMAP_RLC,	/* rear left center */ | ||||
| 	SNDRV_CHMAP_RRC,	/* rear right center */ | ||||
| 	SNDRV_CHMAP_SL,		/* side left */ | ||||
| 	SNDRV_CHMAP_SR,		/* side right */ | ||||
| 	SNDRV_CHMAP_LFE,	/* LFE */ | ||||
| 	SNDRV_CHMAP_FLW,	/* front left wide */ | ||||
| 	SNDRV_CHMAP_FRW,	/* front right wide */ | ||||
| 	SNDRV_CHMAP_FLH,	/* front left high */ | ||||
| 	SNDRV_CHMAP_FCH,	/* front center high */ | ||||
| 	SNDRV_CHMAP_FRH,	/* front right high */ | ||||
| 	SNDRV_CHMAP_TC,		/* top center */ | ||||
| 	SNDRV_CHMAP_LAST = SNDRV_CHMAP_TC, | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
| 	SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int), | ||||
| 	SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct sndrv_pcm_info), | ||||
|  |  | |||
|  | @ -7302,6 +7302,61 @@ OBSOLETE1(snd_pcm_sw_params_get_silence_size, ALSA_0.9, ALSA_0.9.0rc4); | |||
| 
 | ||||
| #endif /* DOC_HIDDEN */ | ||||
| 
 | ||||
| /**
 | ||||
|  * \!brief Query the available channel maps | ||||
|  * \param pcm PCM handle to query | ||||
|  * \return the NULL-terminated array of integer pointers, each of | ||||
|  * which contains the channel map. A channel map is represented by an | ||||
|  * integer array, beginning with the channel map type, followed by the | ||||
|  * number of channels, and the position of each channel. | ||||
|  */ | ||||
| int **snd_pcm_query_chmaps(snd_pcm_t *pcm) | ||||
| { | ||||
| 	if (!pcm->ops->query_chmaps) | ||||
| 		return NULL; | ||||
| 	return pcm->ops->query_chmaps(pcm); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * \!brief Release the channel map array allocated via #snd_pcm_query_chmaps | ||||
|  * \param maps the array pointer to release | ||||
|  */ | ||||
| void snd_pcm_free_chmaps(int **maps) | ||||
| { | ||||
| 	int **p; | ||||
| 	if (!maps) | ||||
| 		return; | ||||
| 	for (p = maps; *p; p++) | ||||
| 		free(*p); | ||||
| 	free(maps); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * \!brief Get the current channel map | ||||
|  * \param pcm PCM instance | ||||
|  * \return the current channel map, or NULL if error | ||||
|  */ | ||||
| int *snd_pcm_get_chmap(snd_pcm_t *pcm) | ||||
| { | ||||
| 	if (!pcm->ops->get_chmap) | ||||
| 		return NULL; | ||||
| 	return pcm->ops->get_chmap(pcm); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * \!brief Configure the current channel map | ||||
|  * \param pcm PCM instance | ||||
|  * \param map the channel map to write | ||||
|  * \return zero if succeeded, or a negative error code | ||||
|  */ | ||||
| int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map) | ||||
| { | ||||
| 	if (!pcm->ops->set_chmap) | ||||
| 		return -ENXIO; | ||||
| 	return pcm->ops->set_chmap(pcm, map); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * basic helpers | ||||
|  */ | ||||
|  |  | |||
|  | @ -531,6 +531,9 @@ static const snd_pcm_ops_t snd_pcm_adpcm_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -404,6 +404,9 @@ static const snd_pcm_ops_t snd_pcm_alaw_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -165,6 +165,9 @@ static const snd_pcm_ops_t snd_pcm_copy_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -789,6 +789,24 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||
| 	return snd_pcm_query_chmaps(dmix->spcm); | ||||
| } | ||||
| 
 | ||||
| int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||
| 	return snd_pcm_get_chmap(dmix->spcm); | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map) | ||||
| { | ||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||
| 	return snd_pcm_set_chmap(dmix->spcm, map); | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_direct_resume(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||
|  |  | |||
|  | @ -235,6 +235,12 @@ struct snd_pcm_direct { | |||
| 	snd1_pcm_direct_open_secondary_client | ||||
| #define snd_pcm_direct_parse_open_conf \ | ||||
| 	snd1_pcm_direct_parse_open_conf | ||||
| #define snd_pcm_direct_query_chmaps \ | ||||
| 	snd1_pcm_direct_query_chmaps | ||||
| #define snd_pcm_direct_get_chmap \ | ||||
| 	snd1_pcm_direct_get_chmap | ||||
| #define snd_pcm_direct_set_chmap \ | ||||
| 	snd1_pcm_direct_set_chmap | ||||
| 
 | ||||
| int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix); | ||||
| 
 | ||||
|  | @ -290,6 +296,10 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); | |||
| int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); | ||||
| int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); | ||||
| 
 | ||||
| int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm); | ||||
| int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm); | ||||
| int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map); | ||||
| 
 | ||||
| int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); | ||||
| struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); | ||||
| 
 | ||||
|  |  | |||
|  | @ -892,6 +892,9 @@ static const snd_pcm_ops_t snd_pcm_dmix_ops = { | |||
| 	.async = snd_pcm_direct_async, | ||||
| 	.mmap = snd_pcm_direct_mmap, | ||||
| 	.munmap = snd_pcm_direct_munmap, | ||||
| 	.query_chmaps = snd_pcm_direct_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_direct_get_chmap, | ||||
| 	.set_chmap = snd_pcm_direct_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { | ||||
|  |  | |||
|  | @ -573,6 +573,8 @@ static const snd_pcm_ops_t snd_pcm_dshare_ops = { | |||
| 	.async = snd_pcm_direct_async, | ||||
| 	.mmap = snd_pcm_direct_mmap, | ||||
| 	.munmap = snd_pcm_direct_munmap, | ||||
| 	.get_chmap = snd_pcm_direct_get_chmap, | ||||
| 	.set_chmap = snd_pcm_direct_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { | ||||
|  |  | |||
|  | @ -488,6 +488,9 @@ static const snd_pcm_ops_t snd_pcm_dsnoop_ops = { | |||
| 	.async = snd_pcm_direct_async, | ||||
| 	.mmap = snd_pcm_direct_mmap, | ||||
| 	.munmap = snd_pcm_direct_munmap, | ||||
| 	.query_chmaps = snd_pcm_direct_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_direct_get_chmap, | ||||
| 	.set_chmap = snd_pcm_direct_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { | ||||
|  |  | |||
|  | @ -669,6 +669,9 @@ static const snd_pcm_ops_t snd_pcm_file_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { | ||||
|  |  | |||
|  | @ -323,4 +323,22 @@ int snd_pcm_generic_munmap(snd_pcm_t *pcm) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_generic_t *generic = pcm->private_data; | ||||
| 	return snd_pcm_query_chmaps(generic->slave); | ||||
| } | ||||
| 
 | ||||
| int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_generic_t *generic = pcm->private_data; | ||||
| 	return snd_pcm_get_chmap(generic->slave); | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map) | ||||
| { | ||||
| 	snd_pcm_generic_t *generic = pcm->private_data; | ||||
| 	return snd_pcm_set_chmap(generic->slave, map); | ||||
| } | ||||
| 
 | ||||
| #endif /* DOC_HIDDEN */ | ||||
|  |  | |||
|  | @ -103,6 +103,12 @@ typedef struct { | |||
| 	snd1_pcm_generic_mmap | ||||
| #define snd_pcm_generic_munmap \ | ||||
| 	snd1_pcm_generic_munmap | ||||
| #define snd_pcm_generic_query_chmaps \ | ||||
| 	snd1_pcm_generic_query_chmaps | ||||
| #define snd_pcm_generic_get_chmap \ | ||||
| 	snd1_pcm_generic_get_chmap | ||||
| #define snd_pcm_generic_set_chmap \ | ||||
| 	snd1_pcm_generic_set_chmap | ||||
| 
 | ||||
| int snd_pcm_generic_close(snd_pcm_t *pcm); | ||||
| int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock); | ||||
|  | @ -149,3 +155,8 @@ int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, | |||
| 				    snd_htimestamp_t *tstamp); | ||||
| int snd_pcm_generic_mmap(snd_pcm_t *pcm); | ||||
| int snd_pcm_generic_munmap(snd_pcm_t *pcm); | ||||
| int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm); | ||||
| int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm); | ||||
| int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -165,6 +165,9 @@ static const snd_pcm_ops_t snd_pcm_hooks_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { | ||||
|  |  | |||
							
								
								
									
										178
									
								
								src/pcm/pcm_hw.c
									
										
									
									
									
								
							
							
						
						
									
										178
									
								
								src/pcm/pcm_hw.c
									
										
									
									
									
								
							|  | @ -1004,6 +1004,181 @@ static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id) | ||||
| { | ||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | ||||
| 	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); | ||||
| 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) | ||||
| 		snd_ctl_elem_id_set_name(id, "Playback Channel Map"); | ||||
| 	else | ||||
| 		snd_ctl_elem_id_set_name(id, "Capture Channel Map"); | ||||
| 	snd_ctl_elem_id_set_device(id, hw->device); | ||||
| 	snd_ctl_elem_id_set_index(id, hw->subdevice); | ||||
| } | ||||
| 
 | ||||
| static int is_chmap_type(int type) | ||||
| { | ||||
| 	return (type >= SND_CTL_TLVT_CHMAP_FIXED && | ||||
| 		type <= SND_CTL_TLVT_CHMAP_PAIRED); | ||||
| } | ||||
| 
 | ||||
| static int **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | ||||
| 	snd_ctl_t *ctl; | ||||
| 	snd_ctl_elem_id_t *id; | ||||
| 	unsigned int tlv[256], *start; | ||||
| 	int **map; | ||||
| 	int i, ret, nums; | ||||
| 
 | ||||
| 	ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); | ||||
| 	if (ret < 0) { | ||||
| 		SYSMSG("Cannot open the associated CTL\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	snd_ctl_elem_id_alloca(&id); | ||||
| 	fill_chmap_ctl_id(pcm, id); | ||||
| 	ret = snd_ctl_elem_tlv_read(ctl, id, tlv, sizeof(tlv)); | ||||
| 	snd_ctl_close(ctl); | ||||
| 	if (ret < 0) { | ||||
| 		SYSMSG("Cannot read Channel Map TLV\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| #if 0 | ||||
| 	for (i = 0; i < 32; i++) | ||||
| 		fprintf(stderr, "%02x: %08x\n", i, tlv[i]); | ||||
| #endif | ||||
| 	if (tlv[0] != SND_CTL_TLVT_CONTAINER) { | ||||
| 		if (!is_chmap_type(tlv[0])) { | ||||
| 			SYSMSG("Invalid TLV type %d\n", tlv[0]); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		start = tlv; | ||||
| 		nums = 1; | ||||
| 	} else { | ||||
| 		unsigned int *p; | ||||
| 		int size; | ||||
| 		start = tlv + 2; | ||||
| 		size = tlv[1]; | ||||
| 		nums = 0; | ||||
| 		for (p = start; size > 0; ) { | ||||
| 			if (!is_chmap_type(p[0])) { | ||||
| 				SYSMSG("Invalid TLV type %d\n", p[0]); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			nums++; | ||||
| 			size -= p[1] + 8; | ||||
| 			p += p[1] / 4 + 2; | ||||
| 		} | ||||
| 	} | ||||
| 	map = calloc(nums + 1, sizeof(int *)); | ||||
| 	if (!map) | ||||
| 		return NULL; | ||||
| 	for (i = 0; i < nums; i++) { | ||||
| 		map[i] = malloc(start[1] + 8); | ||||
| 		if (!map[i]) | ||||
| 			goto nomem; | ||||
| 		map[i][0] = start[0] - 0x100; | ||||
| 		map[i][1] = start[1] / 4; | ||||
| 		memcpy(map[i] + 2, start + 2, start[1]); | ||||
| 		start += start[1] / 4 + 2; | ||||
| 	} | ||||
| 	return map; | ||||
| 
 | ||||
|  nomem: | ||||
| 	for (; i >= 0; i--) | ||||
| 		free(map[i]); | ||||
| 	free(map); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int *snd_pcm_hw_get_chmap(snd_pcm_t *pcm) | ||||
| { | ||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | ||||
| 	int *map; | ||||
| 	snd_ctl_t *ctl; | ||||
| 	snd_ctl_elem_id_t *id; | ||||
| 	snd_ctl_elem_value_t *val; | ||||
| 	unsigned int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	switch (FAST_PCM_STATE(hw)) { | ||||
| 	case SNDRV_PCM_STATE_PREPARED: | ||||
| 	case SNDRV_PCM_STATE_RUNNING: | ||||
| 	case SNDRV_PCM_STATE_XRUN: | ||||
| 	case SNDRV_PCM_STATE_DRAINING: | ||||
| 	case SNDRV_PCM_STATE_PAUSED: | ||||
| 	case SNDRV_PCM_STATE_SUSPENDED: | ||||
| 		break; | ||||
| 	default: | ||||
| 		SYSMSG("Invalid PCM state for chmap_get: %s\n", | ||||
| 		       snd_pcm_state_name(FAST_PCM_STATE(hw))); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	map = malloc(pcm->channels + 1); | ||||
| 	if (!map) | ||||
| 		return NULL; | ||||
| 	*map = pcm->channels; | ||||
| 	ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); | ||||
| 	if (ret < 0) { | ||||
| 		free(map); | ||||
| 		SYSMSG("Cannot open the associated CTL\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	snd_ctl_elem_value_alloca(&val); | ||||
| 	snd_ctl_elem_id_alloca(&id); | ||||
| 	fill_chmap_ctl_id(pcm, id); | ||||
| 	snd_ctl_elem_value_set_id(val, id); | ||||
| 	ret = snd_ctl_elem_read(ctl, val); | ||||
| 	if (ret < 0) { | ||||
| 		snd_ctl_close(ctl); | ||||
| 		free(map); | ||||
| 		SYSMSG("Cannot read Channel Map ctl\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	for (i = 0; i < pcm->channels; i++) | ||||
| 		map[i + 1] = snd_ctl_elem_value_get_integer(val, i); | ||||
| 	snd_ctl_close(ctl); | ||||
| 	return map; | ||||
| } | ||||
| 
 | ||||
| static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const int *map) | ||||
| { | ||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | ||||
| 	snd_ctl_t *ctl; | ||||
| 	snd_ctl_elem_id_t *id; | ||||
| 	snd_ctl_elem_value_t *val; | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	if (*map < 0 || *map > 128) { | ||||
| 		SYSMSG("Invalid number of channels %d\n", *map); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) { | ||||
| 		SYSMSG("Invalid PCM state for chmap_set: %s\n", | ||||
| 		       snd_pcm_state_name(FAST_PCM_STATE(hw))); | ||||
| 		return -EBADFD; | ||||
| 	} | ||||
| 	ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); | ||||
| 	if (ret < 0) { | ||||
| 		SYSMSG("Cannot open the associated CTL\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	snd_ctl_elem_id_alloca(&id); | ||||
| 	snd_ctl_elem_value_alloca(&val); | ||||
| 	fill_chmap_ctl_id(pcm, id); | ||||
| 	snd_ctl_elem_value_set_id(val, id); | ||||
| 	for (i = 0; i < *map; i++) | ||||
| 		snd_ctl_elem_value_set_integer(val, i, map[i + 1]); | ||||
| 	ret = snd_ctl_elem_write(ctl, val); | ||||
| 	snd_ctl_close(ctl); | ||||
| 	if (ret < 0) | ||||
| 		SYSMSG("Cannot write Channel Map ctl\n"); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out) | ||||
| { | ||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | ||||
|  | @ -1037,6 +1212,9 @@ static const snd_pcm_ops_t snd_pcm_hw_ops = { | |||
| 	.async = snd_pcm_hw_async, | ||||
| 	.mmap = snd_pcm_hw_mmap, | ||||
| 	.munmap = snd_pcm_hw_munmap, | ||||
| 	.query_chmaps = snd_pcm_hw_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_hw_get_chmap, | ||||
| 	.set_chmap = snd_pcm_hw_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { | ||||
|  |  | |||
|  | @ -429,6 +429,9 @@ static const snd_pcm_ops_t snd_pcm_iec958_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -1084,6 +1084,9 @@ static const snd_pcm_ops_t snd_pcm_ladspa_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static int snd_pcm_ladspa_check_file(snd_pcm_ladspa_plugin_t * const plugin, | ||||
|  |  | |||
|  | @ -363,6 +363,9 @@ static const snd_pcm_ops_t snd_pcm_lfloat_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -435,6 +435,9 @@ static const snd_pcm_ops_t snd_pcm_linear_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -143,6 +143,9 @@ typedef struct { | |||
| 	void (*dump)(snd_pcm_t *pcm, snd_output_t *out); | ||||
| 	int (*mmap)(snd_pcm_t *pcm); | ||||
| 	int (*munmap)(snd_pcm_t *pcm); | ||||
| 	int **(*query_chmaps)(snd_pcm_t *pcm); | ||||
| 	int *(*get_chmap)(snd_pcm_t *pcm); | ||||
| 	int (*set_chmap)(snd_pcm_t *pcm, const int *map); | ||||
| } snd_pcm_ops_t; | ||||
| 
 | ||||
| typedef struct { | ||||
|  |  | |||
|  | @ -514,6 +514,9 @@ static const snd_pcm_ops_t snd_pcm_meter_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { | ||||
|  |  | |||
|  | @ -368,6 +368,9 @@ static const snd_pcm_ops_t snd_pcm_mmap_emul_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = { | ||||
|  |  | |||
|  | @ -419,6 +419,8 @@ static const snd_pcm_ops_t snd_pcm_mulaw_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -1249,6 +1249,9 @@ static const snd_pcm_ops_t snd_pcm_rate_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -818,6 +818,9 @@ static const snd_pcm_ops_t snd_pcm_softvol_ops = { | |||
| 	.async = snd_pcm_generic_async, | ||||
| 	.mmap = snd_pcm_generic_mmap, | ||||
| 	.munmap = snd_pcm_generic_munmap, | ||||
| 	.query_chmaps = snd_pcm_generic_query_chmaps, | ||||
| 	.get_chmap = snd_pcm_generic_get_chmap, | ||||
| 	.set_chmap = snd_pcm_generic_set_chmap, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Takashi Iwai
						Takashi Iwai