Problems with "snd_pcm_hw_params_set_rate_near" and "snd_pcm_hw_params_set_period_size_near" in x86_64 assembly.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



alsa-project/alsa-lib issue #471 was opened from sc1ntilla:

### **PREAMBLE:**

I have never worked with any sound system before, so I'm almost sure that it's just me doing something wrong, but I can't see what, so I'm asking for help.

I'm doing this project for fun, and to learn a lot of stuff, so feel free to give your opinions / advice if you want to.

### **WHAT HAPPENS:**

When calling `snd_pcm_hw_params_set_rate_near` and `snd_pcm_hw_params_set_period_size_near` memory protection violation is issued.
I find that strange, because `snd_pcm_hw_params_set_buffer_size_near` works perfectly fine, and it's similiar to these two.

### **WHAT I TRIED:**
- Making sure that stack after call is on address divisible by 96 (by adding 8 to stack pointer),
- Making sure that `*val` argument is on address divisible by 96,
- Misaligning stack by 8, 16, 24 and 32 before calling these functions (by subtracting from stack pointer),
- Providing 0 to `*val` argument, to rule out that writing to output crashes,
- Providing valid output address to `*dir` argument to rule out that 0 is causing crashes,
- Calling these functions in different order,
- Trying to call `snd_pcm_set_params` instead, but it says _"Channels count (0) not available for PLAYBACK: Invalid argument"_ however, I'm sure that I provided a valid number (2). I even hardcoded it.

But to no avail. Is it my misunderstanding of how alsa-lib works? Very likely. Is my assembly code faulty? Quite possible. I just can't see where the problem lies. If you see error somewhere, please let me know.

### **ADDITIONAL INFORMATION:**

I have multiple audio outputs: monitors with built-in speakers, standalone speakers, and analog jack headphones. 
I hardcoded `hw:2,0` as device name to open. Sometimes it results in `snd_pcm_open` returning _"File descriptor in bad state"_.
When I tried using `sysdefault` it often returns _"ALSA lib /var/tmp/portage/media-libs/alsa-lib-1.2.14/work/alsa-lib-1.2.14/src/pcm/pcm_dmix.c:1000:(snd_pcm_dmix_open) unable to open slave"_



Below is .data section in which globals are stored, and source of function that will be used to play audio buffers.

.data section:

```
.section .data
.align 32

  test2: .8byte 0
  test:  .8byte 0

  SND_PCM_NONBLOCK:                .8byte 0x1
  SND_PCM_ASYNC:                   .8byte 0x2
  SND_PCM_STREAM_PLAYBACK:         .8byte 0

  SND_PCM_FORMAT_U8:               .8byte 1
  SND_PCM_FORMAT_U16_LE:           .8byte 4
  SND_PCM_FORMAT_U24_LE:           .8byte 8
  SND_PCM_FORMAT_U32_LE:           .8byte 12
  SND_PCM_FORMAT_S8:               .8byte 0
  SND_PCM_FORMAT_S16_LE:           .8byte 2
  SND_PCM_FORMAT_S24_LE:           .8byte 6
  SND_PCM_FORMAT_S32_LE:           .8byte 10

  SND_PCM_ACCESS_MMAP_INTERLEAVED: .8byte 0
  SND_PCM_STATE_PREPARED:          .8byte 2

  AUDIO_BUFFER_STATE_IDLE:         .8byte 0
  AUDIO_BUFFER_STATE_WRITING:      .8byte 1
  AUDIO_BUFFER_STATE_PLAYING:      .8byte 2

  t1: .8byte 0
  t2: .8byte 0

  alsa:
    alsa.pcm_handle:   .8byte 0
    alsa.hw_params:    .8byte 0
    alsa.last_error:   .8byte 0
    alsa.initialized:  .8byte 0
    alsa.device_name:  .ascii "hw:2,0\0"

  audio_buffers.count_max: .8byte 16

  amd64_audio_last_error: .8byte 0
```

function: 

```
  amd64_audio_play:

    /* rdi: (input) address to audio data:
     *        (+0/2) audio format (1: PCM, 2: IEEE754)
     *        (+2/2) amount of channels
     *        (+4/4) rate in hertz
     *        (+8/4) bytes per sec (frequency * bytes per block)
     *        (+12/2) bytes per block (number of channels * bits per sample / 8)
     *        (+14/2) bits per sample
     *        (+16/8) total size of samples data
     *        (+24/8) address to samples data
    */


    /* Align stack on 96byte boundary: */

    push %r15
    mov %rsp,  %r15
    and $-32,  %rsp

    mov %rsp, %rax
    mov  $96, %r14
    xor %rdx, %rdx
    div %r14
    sub %rdx, %rsp

    sub $96, %rsp
    mov %r15, (%rsp)


    /* Store registers: */

    sub $192, %rsp
    call amd64_util_store_gpr_regs


    /* Create stack space: */

    sub $192, %rsp
    mov %rdi, (%rsp)

    /* stack layout:
     *   (+0/8) rdi (address to audio data)
     *   (+8/8) buffer size (altered by *buffer_size_near)
     *   (+16/8) period size (set when setting period size)
     *   (+24/8) rate in hertz
     *   (+32/8) temp
    */


    xor %r15, %r15
    mov 16(%rdi), %r15
    mov %r15, 8(%rsp)

    xor %r15, %r15
    mov 4(%rdi), %r15d
    mov %r15d, 24(%rsp)

    movq $0, 32(%rsp)


    /* Open pcm if needed: */

    cmpq $0, (alsa.pcm_handle)
    jne .amd64_audio_play.pcm_is_open

      lea alsa.pcm_handle,  %rdi
      mov %rdi, (%rdi)
      lea alsa.device_name, %rsi
      mov (SND_PCM_ACCESS_MMAP_INTERLEAVED), %rdx
      mov (SND_PCM_NONBLOCK), %r10

      call snd_pcm_open

      cmp $0, %rax
      jne .amd64_audio_play.error.snd_pcm_open

    .amd64_audio_play.pcm_is_open:


    /* Allocate hw params: */

    cmpq $0, (alsa.hw_params)
    jne .amd64_audio_play.hw_params_are_allocated

      lea alsa.hw_params, %rdi
      mov %rdi, (%rdi)

      call snd_pcm_hw_params_malloc

      cmp $0, %rax
      jne .amd64_audio_play.error.snd_pcm_hw_params_malloc

    .amd64_audio_play.hw_params_are_allocated:


    /* Get all possible combinations into hw params: */

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi

    call snd_pcm_hw_params_any

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_any


    /* Set access: */

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi
    mov (SND_PCM_ACCESS_MMAP_INTERLEAVED), %rdx

    call snd_pcm_hw_params_set_access

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_access


    /* Set format: */

    xor %rdi, %rdi
    mov (%rsp), %rdi
    mov 14(%rdi), %r15w
    mov (%rdi), %r14w

    cmp $1, %r14w
    jne .amd64_audio_play.error.format_unsupported

    cmpw $32, %r15w
    je .amd64_audio_play.format32
    cmpw $24, %r15w
    je .amd64_audio_play.format24
    cmpw $16, %r15w
    je .amd64_audio_play.format16
    cmpw  $8, %r15w
    je .amd64_audio_play.format8
    jmp .amd64_audio_play.error.format_unsupported

    .amd64_audio_play.format32:
      mov (SND_PCM_FORMAT_S32_LE), %rdx
      jmp .amd64_audio_play.format_end

    .amd64_audio_play.format24:
      mov (SND_PCM_FORMAT_S24_LE), %rdx
      jmp .amd64_audio_play.format_end

    .amd64_audio_play.format16:
      mov (SND_PCM_FORMAT_S16_LE), %rdx
      jmp .amd64_audio_play.format_end

    .amd64_audio_play.format8:
      mov (SND_PCM_FORMAT_S8), %rdx
      jmp .amd64_audio_play.format_end

    .amd64_audio_play.format_end:

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi

    call snd_pcm_hw_params_set_format

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_format


    /* Set channels: */

    xor %rdx, %rdx
    mov (%rsp), %r15

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi
    mov 2(%r15), %dx

    call snd_pcm_hw_params_set_channels

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_channels


    /* Set buffer size near: */    /* Returns 0, meaning it succeeded. No crashes generated. */

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi
    mov %rsp, %rdx
    add   $8, %rdx
    mov   $0, %r10

    call snd_pcm_hw_params_set_buffer_size_near

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_buffer_size_near


    /* Set rate near: */   /* CRASHES */

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi
    mov %rsp, %rdx
    add  $24, %rdx
    mov   $0, %r10

    call snd_pcm_hw_params_set_rate_near

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_rate_near


    /* Set period size near: */  /* CRASHES */

    mov 8(%rsp), %rax
    mov $4, %r15
    xor %rdx, %rdx
    div %r15
    mov %rax, 16(%rsp)

    mov (alsa.pcm_handle), %rdi
    mov (alsa.hw_params), %rsi
    mov %rsp, %rdx
    add  $16, %rdx
    mov   $0, %r10

    call snd_pcm_hw_params_set_period_size_near

    cmp $0, %rax
    jne .amd64_audio_play.error.snd_pcm_hw_params_set_period_size_near








    /* Free hw params: */

    cmpq $0, (alsa.hw_params)
    je .amd64_audio_play.hw_params_not_allocated

      mov (alsa.hw_params), %rdi

      call snd_pcm_hw_params_free

      movq $0, (alsa.hw_params)

    .amd64_audio_play.hw_params_not_allocated:


    /* Register errors: */

    xor %rax, %rax
    jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_open:
      mov %rax, (amd64_audio_last_error)
      mov $-1, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_malloc:
      mov %rax, (amd64_audio_last_error)
      mov $-2, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_any:
      mov %rax, (amd64_audio_last_error)
      mov $-3, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_access:
      mov %rax, (amd64_audio_last_error)
      mov $-4, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.format_unsupported:
      mov $-5, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_format:
      mov %rax, (amd64_audio_last_error)
      mov $-6, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_channels:
      mov %rax, (amd64_audio_last_error)
      mov $-7, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_buffer_size_near:
      mov %rax, (amd64_audio_last_error)
      mov $-8, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_period_size_near:
      mov %rax, (amd64_audio_last_error)
      mov $-9, %rax
      jmp .amd64_audio_play.exit

    .amd64_audio_play.error.snd_pcm_hw_params_set_rate_near:
      mov %rax, (amd64_audio_last_error)
      mov $-10, %rax
      jmp .amd64_audio_play.exit


    /* Exit: */

    .amd64_audio_play.exit:


    /* Print error to stdout: */

    mov %rax, %rdi
    call amd64_util_print_dec
    call amd64_util_print_newline

    cmpq $0, (amd64_audio_last_error)
    je .amd64_audio_play.no_error

      mov (amd64_audio_last_error), %rdi
      call snd_strerror

      mov %rax, %rdi
      call amd64_util_print2
      call amd64_util_print_newline

    .amd64_audio_play.no_error:


    /* Restore stack: */

    add $192, %rsp


    /* Restore registers without rax: */

    mov %rax, 128(%rsp)
    call amd64_util_restore_gpr_regs
    mov 128(%rsp), %rax
    add $192, %rsp


    /* Restore stack alignment: */

    pop %rsp
    pop %r15

    ret
```

Issue URL     : https://github.com/alsa-project/alsa-lib/issues/471
Repository URL: https://github.com/alsa-project/alsa-lib



[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux