153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2009 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci/* Shared between pacat/parec/paplay and the server */ 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2753a5a1b3Sopenharmony_ci#include <pulse/utf8.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include "sndfile-util.h" 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ciint pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) { 3453a5a1b3Sopenharmony_ci SF_INFO sfi; 3553a5a1b3Sopenharmony_ci int sf_errno; 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci pa_assert(sf); 3853a5a1b3Sopenharmony_ci pa_assert(ss); 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_ci pa_zero(sfi); 4153a5a1b3Sopenharmony_ci if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) { 4253a5a1b3Sopenharmony_ci pa_log_error("sndfile: %s", sf_error_number(sf_errno)); 4353a5a1b3Sopenharmony_ci return -1; 4453a5a1b3Sopenharmony_ci } 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci switch (sfi.format & SF_FORMAT_SUBMASK) { 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci case SF_FORMAT_PCM_16: 4953a5a1b3Sopenharmony_ci case SF_FORMAT_PCM_U8: 5053a5a1b3Sopenharmony_ci case SF_FORMAT_PCM_S8: 5153a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S16NE; 5253a5a1b3Sopenharmony_ci break; 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci case SF_FORMAT_PCM_24: 5553a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S24NE; 5653a5a1b3Sopenharmony_ci break; 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_ci case SF_FORMAT_PCM_32: 5953a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S32NE; 6053a5a1b3Sopenharmony_ci break; 6153a5a1b3Sopenharmony_ci 6253a5a1b3Sopenharmony_ci case SF_FORMAT_ULAW: 6353a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_ULAW; 6453a5a1b3Sopenharmony_ci break; 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci case SF_FORMAT_ALAW: 6753a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_ALAW; 6853a5a1b3Sopenharmony_ci break; 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci case SF_FORMAT_FLOAT: 7153a5a1b3Sopenharmony_ci case SF_FORMAT_DOUBLE: 7253a5a1b3Sopenharmony_ci default: 7353a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_FLOAT32NE; 7453a5a1b3Sopenharmony_ci break; 7553a5a1b3Sopenharmony_ci } 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_ci ss->rate = (uint32_t) sfi.samplerate; 7853a5a1b3Sopenharmony_ci ss->channels = (uint8_t) sfi.channels; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci if (!pa_sample_spec_valid(ss)) 8153a5a1b3Sopenharmony_ci return -1; 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci return 0; 8453a5a1b3Sopenharmony_ci} 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ciint pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) { 8753a5a1b3Sopenharmony_ci pa_assert(sfi); 8853a5a1b3Sopenharmony_ci pa_assert(ss); 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_ci sfi->samplerate = (int) ss->rate; 9153a5a1b3Sopenharmony_ci sfi->channels = (int) ss->channels; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci if (pa_sample_format_is_le(ss->format) > 0) 9453a5a1b3Sopenharmony_ci sfi->format = SF_ENDIAN_LITTLE; 9553a5a1b3Sopenharmony_ci else if (pa_sample_format_is_be(ss->format) > 0) 9653a5a1b3Sopenharmony_ci sfi->format = SF_ENDIAN_BIG; 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci switch (ss->format) { 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci case PA_SAMPLE_U8: 10153a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S16NE; 10253a5a1b3Sopenharmony_ci sfi->format = SF_FORMAT_PCM_U8; 10353a5a1b3Sopenharmony_ci break; 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci case PA_SAMPLE_S16LE: 10653a5a1b3Sopenharmony_ci case PA_SAMPLE_S16BE: 10753a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S16NE; 10853a5a1b3Sopenharmony_ci sfi->format |= SF_FORMAT_PCM_16; 10953a5a1b3Sopenharmony_ci break; 11053a5a1b3Sopenharmony_ci 11153a5a1b3Sopenharmony_ci case PA_SAMPLE_S24LE: 11253a5a1b3Sopenharmony_ci case PA_SAMPLE_S24BE: 11353a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S24NE; 11453a5a1b3Sopenharmony_ci sfi->format |= SF_FORMAT_PCM_24; 11553a5a1b3Sopenharmony_ci break; 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci case PA_SAMPLE_S24_32LE: 11853a5a1b3Sopenharmony_ci case PA_SAMPLE_S24_32BE: 11953a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S24_32NE; 12053a5a1b3Sopenharmony_ci sfi->format |= SF_FORMAT_PCM_32; 12153a5a1b3Sopenharmony_ci break; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci case PA_SAMPLE_S32LE: 12453a5a1b3Sopenharmony_ci case PA_SAMPLE_S32BE: 12553a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S32NE; 12653a5a1b3Sopenharmony_ci sfi->format |= SF_FORMAT_PCM_32; 12753a5a1b3Sopenharmony_ci break; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci case PA_SAMPLE_ULAW: 13053a5a1b3Sopenharmony_ci sfi->format = SF_FORMAT_ULAW; 13153a5a1b3Sopenharmony_ci break; 13253a5a1b3Sopenharmony_ci 13353a5a1b3Sopenharmony_ci case PA_SAMPLE_ALAW: 13453a5a1b3Sopenharmony_ci sfi->format = SF_FORMAT_ALAW; 13553a5a1b3Sopenharmony_ci break; 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_ci case PA_SAMPLE_FLOAT32LE: 13853a5a1b3Sopenharmony_ci case PA_SAMPLE_FLOAT32BE: 13953a5a1b3Sopenharmony_ci default: 14053a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_FLOAT32NE; 14153a5a1b3Sopenharmony_ci sfi->format |= SF_FORMAT_FLOAT; 14253a5a1b3Sopenharmony_ci break; 14353a5a1b3Sopenharmony_ci } 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci if (!pa_sample_spec_valid(ss)) 14653a5a1b3Sopenharmony_ci return -1; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci return 0; 14953a5a1b3Sopenharmony_ci} 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ciint pa_sndfile_read_channel_map(SNDFILE *sf, pa_channel_map *cm) { 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci static const pa_channel_position_t table[] = { 15453a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_MONO] = PA_CHANNEL_POSITION_MONO, 15553a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, /* libsndfile distinguishes left and front-left, which we don't */ 15653a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT, 15753a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER, 15853a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, 15953a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT, 16053a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER, 16153a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER, 16253a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT, 16353a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT, 16453a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_LFE] = PA_CHANNEL_POSITION_LFE, 16553a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, 16653a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, 16753a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT, 16853a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT, 16953a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTER, 17053a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT, 17153a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, 17253a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER, 17353a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_TOP_REAR_LEFT, 17453a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT, 17553a5a1b3Sopenharmony_ci [SF_CHANNEL_MAP_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTER 17653a5a1b3Sopenharmony_ci }; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci SF_INFO sfi; 17953a5a1b3Sopenharmony_ci int sf_errno; 18053a5a1b3Sopenharmony_ci int *channels; 18153a5a1b3Sopenharmony_ci unsigned c; 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci pa_assert(sf); 18453a5a1b3Sopenharmony_ci pa_assert(cm); 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci pa_zero(sfi); 18753a5a1b3Sopenharmony_ci if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) { 18853a5a1b3Sopenharmony_ci pa_log_error("sndfile: %s", sf_error_number(sf_errno)); 18953a5a1b3Sopenharmony_ci return -1; 19053a5a1b3Sopenharmony_ci } 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci channels = pa_xnew(int, sfi.channels); 19353a5a1b3Sopenharmony_ci if (!sf_command(sf, SFC_GET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * sfi.channels)) { 19453a5a1b3Sopenharmony_ci pa_xfree(channels); 19553a5a1b3Sopenharmony_ci return -1; 19653a5a1b3Sopenharmony_ci } 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci cm->channels = (uint8_t) sfi.channels; 19953a5a1b3Sopenharmony_ci for (c = 0; c < cm->channels; c++) { 20053a5a1b3Sopenharmony_ci if (channels[c] <= SF_CHANNEL_MAP_INVALID || 20153a5a1b3Sopenharmony_ci (unsigned) channels[c] >= PA_ELEMENTSOF(table)) { 20253a5a1b3Sopenharmony_ci pa_xfree(channels); 20353a5a1b3Sopenharmony_ci return -1; 20453a5a1b3Sopenharmony_ci } 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci cm->map[c] = table[channels[c]]; 20753a5a1b3Sopenharmony_ci } 20853a5a1b3Sopenharmony_ci 20953a5a1b3Sopenharmony_ci pa_xfree(channels); 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci if (!pa_channel_map_valid(cm)) 21253a5a1b3Sopenharmony_ci return -1; 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci return 0; 21553a5a1b3Sopenharmony_ci} 21653a5a1b3Sopenharmony_ci 21753a5a1b3Sopenharmony_ciint pa_sndfile_write_channel_map(SNDFILE *sf, pa_channel_map *cm) { 21853a5a1b3Sopenharmony_ci static const int table[PA_CHANNEL_POSITION_MAX] = { 21953a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_MONO] = SF_CHANNEL_MAP_MONO, 22053a5a1b3Sopenharmony_ci 22153a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_FRONT_LEFT] = SF_CHANNEL_MAP_FRONT_LEFT, 22253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_FRONT_RIGHT] = SF_CHANNEL_MAP_FRONT_RIGHT, 22353a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_FRONT_CENTER] = SF_CHANNEL_MAP_FRONT_CENTER, 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_REAR_CENTER] = SF_CHANNEL_MAP_REAR_CENTER, 22653a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_REAR_LEFT] = SF_CHANNEL_MAP_REAR_LEFT, 22753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_REAR_RIGHT] = SF_CHANNEL_MAP_REAR_RIGHT, 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_LFE] = SF_CHANNEL_MAP_LFE, 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, 23253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_SIDE_LEFT] = SF_CHANNEL_MAP_SIDE_LEFT, 23553a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_SIDE_RIGHT] = SF_CHANNEL_MAP_SIDE_RIGHT, 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX0] = -1, 23853a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX1] = -1, 23953a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX2] = -1, 24053a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX3] = -1, 24153a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX4] = -1, 24253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX5] = -1, 24353a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX6] = -1, 24453a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX7] = -1, 24553a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX8] = -1, 24653a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX9] = -1, 24753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX10] = -1, 24853a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX11] = -1, 24953a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX12] = -1, 25053a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX13] = -1, 25153a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX14] = -1, 25253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX15] = -1, 25353a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX16] = -1, 25453a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX17] = -1, 25553a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX18] = -1, 25653a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX19] = -1, 25753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX20] = -1, 25853a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX21] = -1, 25953a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX22] = -1, 26053a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX23] = -1, 26153a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX24] = -1, 26253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX25] = -1, 26353a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX26] = -1, 26453a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX27] = -1, 26553a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX28] = -1, 26653a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX29] = -1, 26753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX30] = -1, 26853a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_AUX31] = -1, 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_CENTER] = SF_CHANNEL_MAP_TOP_CENTER, 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SF_CHANNEL_MAP_TOP_FRONT_LEFT, 27353a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SF_CHANNEL_MAP_TOP_FRONT_RIGHT, 27453a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SF_CHANNEL_MAP_TOP_FRONT_CENTER , 27553a5a1b3Sopenharmony_ci 27653a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SF_CHANNEL_MAP_TOP_REAR_LEFT, 27753a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SF_CHANNEL_MAP_TOP_REAR_RIGHT, 27853a5a1b3Sopenharmony_ci [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SF_CHANNEL_MAP_TOP_REAR_CENTER, 27953a5a1b3Sopenharmony_ci }; 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci int *channels; 28253a5a1b3Sopenharmony_ci unsigned c; 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci pa_assert(sf); 28553a5a1b3Sopenharmony_ci pa_assert(cm); 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci /* Suppress channel mapping for the obvious cases */ 28853a5a1b3Sopenharmony_ci if (cm->channels == 1 && cm->map[0] == PA_CHANNEL_POSITION_MONO) 28953a5a1b3Sopenharmony_ci return 0; 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_ci if (cm->channels == 2 && 29253a5a1b3Sopenharmony_ci cm->map[0] == PA_CHANNEL_POSITION_FRONT_LEFT && 29353a5a1b3Sopenharmony_ci cm->map[1] == PA_CHANNEL_POSITION_FRONT_RIGHT) 29453a5a1b3Sopenharmony_ci return 0; 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci channels = pa_xnew(int, cm->channels); 29753a5a1b3Sopenharmony_ci for (c = 0; c < cm->channels; c++) { 29853a5a1b3Sopenharmony_ci 29953a5a1b3Sopenharmony_ci if (cm->map[c] < 0 || 30053a5a1b3Sopenharmony_ci cm->map[c] >= PA_CHANNEL_POSITION_MAX || 30153a5a1b3Sopenharmony_ci table[cm->map[c]] < 0) { 30253a5a1b3Sopenharmony_ci pa_xfree(channels); 30353a5a1b3Sopenharmony_ci return -1; 30453a5a1b3Sopenharmony_ci } 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci channels[c] = table[cm->map[c]]; 30753a5a1b3Sopenharmony_ci } 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * cm->channels)) { 31053a5a1b3Sopenharmony_ci pa_xfree(channels); 31153a5a1b3Sopenharmony_ci return -1; 31253a5a1b3Sopenharmony_ci } 31353a5a1b3Sopenharmony_ci 31453a5a1b3Sopenharmony_ci pa_xfree(channels); 31553a5a1b3Sopenharmony_ci return 0; 31653a5a1b3Sopenharmony_ci} 31753a5a1b3Sopenharmony_ci 31853a5a1b3Sopenharmony_civoid pa_sndfile_init_proplist(SNDFILE *sf, pa_proplist *p) { 31953a5a1b3Sopenharmony_ci 32053a5a1b3Sopenharmony_ci static const char* table[] = { 32153a5a1b3Sopenharmony_ci [SF_STR_TITLE] = PA_PROP_MEDIA_TITLE, 32253a5a1b3Sopenharmony_ci [SF_STR_COPYRIGHT] = PA_PROP_MEDIA_COPYRIGHT, 32353a5a1b3Sopenharmony_ci [SF_STR_SOFTWARE] = PA_PROP_MEDIA_SOFTWARE, 32453a5a1b3Sopenharmony_ci [SF_STR_ARTIST] = PA_PROP_MEDIA_ARTIST, 32553a5a1b3Sopenharmony_ci [SF_STR_COMMENT] = "media.comment", 32653a5a1b3Sopenharmony_ci [SF_STR_DATE] = "media.date" 32753a5a1b3Sopenharmony_ci }; 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci SF_INFO sfi; 33053a5a1b3Sopenharmony_ci SF_FORMAT_INFO fi; 33153a5a1b3Sopenharmony_ci int sf_errno; 33253a5a1b3Sopenharmony_ci unsigned c; 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_ci pa_assert(sf); 33553a5a1b3Sopenharmony_ci pa_assert(p); 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci for (c = 0; c < PA_ELEMENTSOF(table); c++) { 33853a5a1b3Sopenharmony_ci const char *s; 33953a5a1b3Sopenharmony_ci char *t; 34053a5a1b3Sopenharmony_ci 34153a5a1b3Sopenharmony_ci if (!table[c]) 34253a5a1b3Sopenharmony_ci continue; 34353a5a1b3Sopenharmony_ci 34453a5a1b3Sopenharmony_ci if (!(s = sf_get_string(sf, c))) 34553a5a1b3Sopenharmony_ci continue; 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci t = pa_utf8_filter(s); 34853a5a1b3Sopenharmony_ci pa_proplist_sets(p, table[c], t); 34953a5a1b3Sopenharmony_ci pa_xfree(t); 35053a5a1b3Sopenharmony_ci } 35153a5a1b3Sopenharmony_ci 35253a5a1b3Sopenharmony_ci pa_zero(sfi); 35353a5a1b3Sopenharmony_ci if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) { 35453a5a1b3Sopenharmony_ci pa_log_error("sndfile: %s", sf_error_number(sf_errno)); 35553a5a1b3Sopenharmony_ci return; 35653a5a1b3Sopenharmony_ci } 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_ci pa_zero(fi); 35953a5a1b3Sopenharmony_ci fi.format = sfi.format; 36053a5a1b3Sopenharmony_ci if (sf_command(sf, SFC_GET_FORMAT_INFO, &fi, sizeof(fi)) == 0 && fi.name) { 36153a5a1b3Sopenharmony_ci char *t; 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci t = pa_utf8_filter(fi.name); 36453a5a1b3Sopenharmony_ci pa_proplist_sets(p, "media.format", t); 36553a5a1b3Sopenharmony_ci pa_xfree(t); 36653a5a1b3Sopenharmony_ci } 36753a5a1b3Sopenharmony_ci} 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_cipa_sndfile_readf_t pa_sndfile_readf_function(const pa_sample_spec *ss) { 37053a5a1b3Sopenharmony_ci pa_assert(ss); 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci switch (ss->format) { 37353a5a1b3Sopenharmony_ci case PA_SAMPLE_S16NE: 37453a5a1b3Sopenharmony_ci return (pa_sndfile_readf_t) sf_readf_short; 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_ci case PA_SAMPLE_S32NE: 37753a5a1b3Sopenharmony_ci case PA_SAMPLE_S24_32NE: 37853a5a1b3Sopenharmony_ci return (pa_sndfile_readf_t) sf_readf_int; 37953a5a1b3Sopenharmony_ci 38053a5a1b3Sopenharmony_ci case PA_SAMPLE_FLOAT32NE: 38153a5a1b3Sopenharmony_ci return (pa_sndfile_readf_t) sf_readf_float; 38253a5a1b3Sopenharmony_ci 38353a5a1b3Sopenharmony_ci case PA_SAMPLE_ULAW: 38453a5a1b3Sopenharmony_ci case PA_SAMPLE_ALAW: 38553a5a1b3Sopenharmony_ci case PA_SAMPLE_S24NE: 38653a5a1b3Sopenharmony_ci return NULL; 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci default: 38953a5a1b3Sopenharmony_ci pa_assert_not_reached(); 39053a5a1b3Sopenharmony_ci } 39153a5a1b3Sopenharmony_ci} 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_cipa_sndfile_writef_t pa_sndfile_writef_function(const pa_sample_spec *ss) { 39453a5a1b3Sopenharmony_ci pa_assert(ss); 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci switch (ss->format) { 39753a5a1b3Sopenharmony_ci case PA_SAMPLE_S16NE: 39853a5a1b3Sopenharmony_ci return (pa_sndfile_writef_t) sf_writef_short; 39953a5a1b3Sopenharmony_ci 40053a5a1b3Sopenharmony_ci case PA_SAMPLE_S32NE: 40153a5a1b3Sopenharmony_ci case PA_SAMPLE_S24_32NE: 40253a5a1b3Sopenharmony_ci return (pa_sndfile_writef_t) sf_writef_int; 40353a5a1b3Sopenharmony_ci 40453a5a1b3Sopenharmony_ci case PA_SAMPLE_FLOAT32NE: 40553a5a1b3Sopenharmony_ci return (pa_sndfile_writef_t) sf_writef_float; 40653a5a1b3Sopenharmony_ci 40753a5a1b3Sopenharmony_ci case PA_SAMPLE_ULAW: 40853a5a1b3Sopenharmony_ci case PA_SAMPLE_ALAW: 40953a5a1b3Sopenharmony_ci case PA_SAMPLE_S24NE: 41053a5a1b3Sopenharmony_ci return NULL; 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci default: 41353a5a1b3Sopenharmony_ci pa_assert_not_reached(); 41453a5a1b3Sopenharmony_ci } 41553a5a1b3Sopenharmony_ci} 41653a5a1b3Sopenharmony_ci 41753a5a1b3Sopenharmony_ciint pa_sndfile_format_from_string(const char *name) { 41853a5a1b3Sopenharmony_ci int i, count = 0; 41953a5a1b3Sopenharmony_ci 42053a5a1b3Sopenharmony_ci if (!name[0]) 42153a5a1b3Sopenharmony_ci return -1; 42253a5a1b3Sopenharmony_ci 42353a5a1b3Sopenharmony_ci pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0); 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci for (i = 0; i < count; i++) { 42653a5a1b3Sopenharmony_ci SF_FORMAT_INFO fi; 42753a5a1b3Sopenharmony_ci pa_zero(fi); 42853a5a1b3Sopenharmony_ci fi.format = i; 42953a5a1b3Sopenharmony_ci 43053a5a1b3Sopenharmony_ci pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0); 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci /* First try to match via full type string */ 43353a5a1b3Sopenharmony_ci if (strcasecmp(name, fi.name) == 0) 43453a5a1b3Sopenharmony_ci return fi.format; 43553a5a1b3Sopenharmony_ci 43653a5a1b3Sopenharmony_ci /* Then, try to match via the full extension */ 43753a5a1b3Sopenharmony_ci if (strcasecmp(name, fi.extension) == 0) 43853a5a1b3Sopenharmony_ci return fi.format; 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci /* Then, try to match via the start of the type string */ 44153a5a1b3Sopenharmony_ci if (strncasecmp(name, fi.name, strlen(name)) == 0) 44253a5a1b3Sopenharmony_ci return fi.format; 44353a5a1b3Sopenharmony_ci } 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci return -1; 44653a5a1b3Sopenharmony_ci} 44753a5a1b3Sopenharmony_ci 44853a5a1b3Sopenharmony_civoid pa_sndfile_dump_formats(void) { 44953a5a1b3Sopenharmony_ci int i, count = 0; 45053a5a1b3Sopenharmony_ci 45153a5a1b3Sopenharmony_ci pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0); 45253a5a1b3Sopenharmony_ci 45353a5a1b3Sopenharmony_ci for (i = 0; i < count; i++) { 45453a5a1b3Sopenharmony_ci SF_FORMAT_INFO fi; 45553a5a1b3Sopenharmony_ci pa_zero(fi); 45653a5a1b3Sopenharmony_ci fi.format = i; 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0); 45953a5a1b3Sopenharmony_ci printf("%s\t%s\n", fi.extension, fi.name); 46053a5a1b3Sopenharmony_ci } 46153a5a1b3Sopenharmony_ci} 462