ALSA:PCM ハードウェア構成 (1)

PCM ハードウェア構成
PCM を開いたら、まずは、ハードウェアの構成をインストールする必要があります。

ハードウェア構成には、サンプルのフォーマットタイプや、サンプリングレートなどの、重要な情報が含まれています。
ハードウェア構成は、再生/録音中は変更できません。

PCM を開いた直後は、ハードウェア構成がインストールされていないので、常にセットする必要があります。
ハードウェア構成の扱い方
ハードウェア構成は、少し珍しいやり方でセットします。

まず、開いた PCM 上で利用可能な、ハードウェア構成の情報を、snd_pcm_hw_params_t にすべて取得します。

アプリケーション側が選択できるいくつかの項目は、snd_pcm_hw_params_t 内で、複数の値が格納できるような状態になっています。

snd_pcm_hw_params_any() を実行すると、PCM で利用できる複数の値がセットされます。

その中から、各項目ごとに、実際に使用したいものを選択し、一つの値、または複数の値に絞って、セットします。

設定が決まったら、snd_pcm_hw_params() でハードウェア構成をインストールします。

一つの項目で複数の値がある場合は、項目ごとに、最初の値や、最小の値などが選択されます。
確保
まずは、snd_pcm_hw_params_t を確保する必要があります。

//サイズ取得
size_t snd_pcm_hw_params_sizeof(void);

//確保
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr);

//解放
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj);
利用可能な情報を取得
int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);

PCM で利用可能な、すべてのハードウェア構成の情報を取得します。

すでにハードウェア構成がインストールされている場合は、先に snd_pcm_hw_free() で、ハードウェア構成を削除した方がいい。
各項目のマスクを取得
ハードウェア構成で設定できる項目はいくつかありますが、ここでは、複数のタイプから選択できる項目を紹介します。

  • アクセスタイプ
    サンプルを読み書きする時の操作方法です。
  • フォーマットタイプ
    サンプルのフォーマットタイプ。
  • サブフォーマット
    サンプルのフォーマットの補足タイプ。
    どのビットを使うか。

これらは、マスクの形で、複数の値を選択できます。

まずは、各項目のマスクを取得して、どのタイプが使用できるかをチェックしてみます。

//アクセスタイプのマスクを取得
int snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask);

//フォーマットタイプのマスクを取得
void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask);

//サブフォーマットのマスクを取得
void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask);

snd_pcm_access_mask_t などは、非公開の構造体になっているため、それぞれ、取得する前にメモリを確保する必要があります。

マスクを操作するための各関数などは、以下をご覧ください。

アクセスタイプ/マスク
フォーマット/マスク
サブフォーマット/マスク
プログラム
開いた PCM で利用可能な、アクセスタイプ・フォーマット・サブフォーマットを出力します。

$ cc -o 10-hwparam 10-hwparam.c -lasound

#include <stdio.h>
#include <alsa/asoundlib.h>

int main(int argc,char **argv)
{
    snd_pcm_t *pcm;
    snd_pcm_hw_params_t *hw;
    snd_pcm_access_mask_t *amask;
    snd_pcm_format_mask_t *format;
    snd_pcm_subformat_mask_t *subformat;
    int i;

    if(snd_pcm_open(&pcm,
        (argc >= 2)? argv[1]: "default", SND_PCM_STREAM_PLAYBACK, 0))
    {
        printf("open error\n");
        return 1;
    }

    snd_pcm_hw_params_malloc(&hw);

    snd_pcm_hw_params_any(pcm, hw);

    //アクセスタイプ

    snd_pcm_access_mask_malloc(&amask);

    snd_pcm_hw_params_get_access_mask(hw, amask);

    printf("-- access --\n");

    for(i = 0; i < SND_PCM_ACCESS_LAST; i++)
    {
        if(snd_pcm_access_mask_test(amask, i))
            printf("%s\n", snd_pcm_access_name(i));
    }

    snd_pcm_access_mask_free(amask);

    //フォーマット

    snd_pcm_format_mask_malloc(&format);

    snd_pcm_hw_params_get_format_mask(hw, format);

    printf("\n-- format --\n");

    for(i = 0; i < SND_PCM_FORMAT_LAST; i++)
    {
        if(snd_pcm_format_mask_test(format, i))
            printf("%s\n", snd_pcm_format_name(i));
    }

    snd_pcm_format_mask_free(format);

    //サブフォーマット

    snd_pcm_subformat_mask_malloc(&subformat);

    snd_pcm_hw_params_get_subformat_mask(hw, subformat);

    printf("\n-- subformat --\n");

    for(i = 0; i < SND_PCM_SUBFORMAT_LAST; i++)
    {
        if(snd_pcm_subformat_mask_test(subformat, i))
            printf("%s\n", snd_pcm_subformat_name(i));
    }

    snd_pcm_subformat_mask_free(subformat);

    //
    
    snd_pcm_hw_params_free(hw);
    
    snd_pcm_close(pcm);

    return 0;
}
実行結果
default
デフォルトの PCM の場合は、各フォーマットが利用可能になっています。

-- access --
MMAP_INTERLEAVED
MMAP_NONINTERLEAVED
MMAP_COMPLEX
RW_INTERLEAVED
RW_NONINTERLEAVED

-- format --
S8
U8
S16_LE
S16_BE
U16_LE
U16_BE
S24_LE
S24_BE
U24_LE
U24_BE
S32_LE
S32_BE
U32_LE
U32_BE
FLOAT_LE
FLOAT_BE
FLOAT64_LE
FLOAT64_BE
MU_LAW
A_LAW
IMA_ADPCM
S20_LE
S20_BE
U20_LE
U20_BE
S24_3LE
S24_3BE
U24_3LE
U24_3BE
S20_3LE
S20_3BE
U20_3LE
U20_3BE
S18_3LE
S18_3BE
U18_3LE
U18_3BE

-- subformat --
STD
MSBITS_MAX
MSBITS_20
MSBITS_24
front
"front" は、前面のスピーカーという意味ですが、ステレオのみの状態であれば、デフォルトのアナログ入出力とほぼ同じ意味になります。
ただし、変換などが有効になっていないので、使用できるタイプは制限されています。

$ ./10-hwparam front
-- access --
MMAP_INTERLEAVED
RW_INTERLEAVED

-- format --
S16_LE
S32_LE

-- subformat --
STD
HDMI
$ ./10-hwparam hdmi
-- access --
MMAP_INTERLEAVED
RW_INTERLEAVED

-- format --
S16_LE
S32_LE

-- subformat --
STD
MSBITS_MAX