0

我正在尝试使用 ALSA ( libasound.so.2) 播放具有 3 字节样本对齐的 24 位 wav 文件。并且 ALSA 在设置缓冲区大小时失败并Invalid argument出现错误(并且 ALSA 不会将任何内容传递给驱动程序)

这是wav文件头内容:

chunkId:       46464952                                         
chunkSize:     221417340                                        
format:        "WAVE"                                           
subchunk1Id:   "fmt "                                           
subchunk1Size: 40                                               
audioFormat:   fffe                                             
numChannels:   2                                                
sampleRate:    88200                                            
byteRate:      529200                                           
blockAlign:    6                                                
bitsPerSample: 24                                               
cbSize         16                                               
wValidBitsPerSample 18                                          
dwChannelMask  0                                                
SubFormat                                                       
subchunk2Id:   "data"                                           
subchunk2Size: 221417280

不幸的是无法提供适当的测试程序源,因为它是跨平台程序的一部分并且不会单独构建。缩短示例可能看起来像

#include <stdio.h>                                                          
#include <stdint.h>                                                         
#include <sys/ioctl.h>                                                      
#include <sys/types.h>                                                      
#include <sys/stat.h>                                                       
#include <unistd.h>                                                         
#include <fcntl.h>                                                          
#include <errno.h>                                                          
#include <string.h>                                                         
#include <semaphore.h>                                                      
#include "asoundlib.h"                                                      

int main(int argc, char *argv[])
{                               
   int err = -1;                           /**< ALSA & clib function return code */
   snd_pcm_t *p_handle = NULL;             /**< pointer to active pcm object */    
   static const char *const p_device = "default";   /**< const pointer to const device id string */
   unsigned int sampleRate = 0;                                                                    
   unsigned int rbuffertime = 0;    /**< real buffer time as granted by ALSA */                    

   err = snd_pcm_open(&p_handle, p_device, SND_PCM_STREAM_PLAYBACK, 0);
   if (0 > err)                                                        
   {                                                                   
      printf("Playback open error: %s\n", snd_strerror(err));          
      return err;                                                      
   }                                                                   

   /* Get full range of possible hw params */
   err =  snd_pcm_hw_params_any(p_handle, p_hwparams);
   if (0 > err)                                       
   {                                                  
      printf("Error fetching hw param ranges: %s\n", snd_strerror(err));
      return err;                                                       
   }                                                                    

   // Specify a specific config out of configuration space and set it
   err = snd_pcm_hw_params_set_rate_resample(p_handle, p_hwparams, 1);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_rate_resample for playback: %s\n", snd_strerror(err));
      return err;
   }

   err = snd_pcm_hw_params_set_access(p_handle, p_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_access for playback: %s\n", snd_strerror(err));
      return err;
   }

   err = snd_pcm_hw_params_set_format(p_handle, p_hwparams, SND_PCM_FORMAT_S24_3LE);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_format for playback: %s\n", snd_strerror(err));
      return err;
   }

   err = snd_pcm_hw_params_set_channels(p_handle, p_hwparams, 2);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_channels for playback: %s\n", snd_strerror(err));
      return err;
   }

   sampleRate = 88200;
   err = snd_pcm_hw_params_set_rate_near(p_handle, p_hwparams, &sampleRate, 0);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_rate for playback: %s\n", snd_strerror(err));
      return err;
   }

   rbuffertime = 500000;
   err = snd_pcm_hw_params_set_buffer_time_near(p_handle, p_hwparams, &rbuffertime, 0);
   if (0 > err)
   {
      printf("Unable to snd_pcm_hw_params_set_buffer_time_near for playback: %s\n", snd_strerror(err));
   }

   return err;
}

ALSAsnd_pcm_hw_params_set_buffer_time_near()呼叫失败并出现错误

ALSA ERROR hw_params: set_near (BUFFER_TIME)
           value = 500000 : Invalid argument
ACCESS:  RW_INTERLEAVED
FORMAT:  S24_3LE
SUBFORMAT:  STD
SAMPLE_BITS: 24
FRAME_BITS: 48
CHANNELS: 2
RATE: 88200
PERIOD_TIME: (476 247688)
PERIOD_SIZE: (42 21846)
PERIOD_BYTES: [256 131072]
PERIODS: [2 1024]
BUFFER_TIME: (495351 495352)
BUFFER_SIZE: 43690
BUFFER_BYTES: [262144 262140]
TICK_TIME: ALL

(ALSA 甚至不尝试将任何数据传递给驱动程序,只是在设置缓冲区失败)该程序适用于 16 位音频。

我尝试了不同的缓冲区值(0.001 .. 1 秒),但它们都不起作用。假设我错过了 24 位 3LE 所需的 ALSA 配置的任何部分,也许是对先前初始化步骤结果的一些检查?

不幸的是,我找不到任何 24 位 ALSA 用法的示例,如果您建议任何指向示例/推荐/文档的链接,我将不胜感激。

已编辑

该文件的结果aplay是:

aplay -v /export/target/24bit_88.2kHz.wav
Playing WAVE '/export/target/24bit_88.2kHz.wav' : Signed 24 bit Little Endian in 3bytes, Rate 88200 Hz, Stereo
aplay: set_params:979: Sample format non available
4

0 回答 0