Oopenvela-robotfix wooden_fish
635ce228创建于 4月20日历史提交
/*********************
 *      INCLUDES
 *********************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>

#include "audio_ctl.h"
#include "wooden_fish.h"

#include <audioutils/nxaudio.h>

/**********************
 *  STATIC PROTOTYPES
 **********************/

static void app_dequeue_cb(unsigned long arg,
                           FAR struct ap_buffer_s *apb);
static void app_complete_cb(unsigned long arg);
static void app_user_cb(unsigned long arg,
                        FAR struct audio_msg_s *msg, FAR bool *running);

/**********************
 *  STATIC VARIABLES
 **********************/

static struct nxaudio_callbacks_s cbs =
{
  app_dequeue_cb,
  app_complete_cb,
  app_user_cb
};

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void app_dequeue_cb(unsigned long arg, FAR struct ap_buffer_s *apb)
{
    FAR audioctl_s *ctl = (FAR audioctl_s *)(uintptr_t)arg;

    if (!apb)
    {
        return;
    }

    if (ctl->fd < 0)
    {
        apb->nbytes = 0;
        return;
    }

    if (ctl->seek) {
        off_t pos = lseek(ctl->fd, ctl->seek_position, SEEK_SET);

        if (pos < 0) {


            return;

        }
        ctl->file_position = ctl->seek_position;
        ctl->seek = false;
    }

    if (apb->nmaxbytes > SSIZE_MAX) {
        apb->nbytes = 0;
        return;
    }

    ssize_t bytes_read = read(ctl->fd, apb->samp, apb->nmaxbytes);
    if (bytes_read < 0) {
        apb->nbytes = 0;
        return;
    }

    apb->nbytes = (size_t)bytes_read;
    apb->curbyte = 0;
    apb->flags = 0;

    while (0 < apb->nbytes && apb->nbytes < apb->nmaxbytes)
    {
        int n = apb->nmaxbytes - apb->nbytes;

        if (n <= 0 || n > SSIZE_MAX || apb->nbytes > apb->nmaxbytes) {
            break;
        }

        int ret = read(ctl->fd, &apb->samp[apb->nbytes], n);

        if (0 >= ret)
        {
            break;
        }
        apb->nbytes += ret;
    }

    if (apb->nbytes < apb->nmaxbytes)
    {
        close(ctl->fd);
        ctl->fd = -1;

        return ;
    }

    ctl->file_position += apb->nbytes;

    nxaudio_enqbuffer(&ctl->nxaudio, apb);
}

static void app_complete_cb(unsigned long arg)
{
    /* Audio playback completed - do not auto-cleanup to avoid crashes */
    printf("Audio playback completed\n");
}

static void app_user_cb(unsigned long arg,
                        FAR struct audio_msg_s *msg, FAR bool *running)
{
    /* Do nothing.. */
}

static FAR void *audio_loop_thread(void *arg)
{
    FAR audioctl_s *ctl = (FAR audioctl_s *)arg;

    nxaudio_start(&ctl->nxaudio);
    nxaudio_msgloop(&ctl->nxaudio, &cbs,
                    (unsigned long)(uintptr_t)ctl);

    return NULL;
}

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

FAR audioctl_s *audio_ctl_init_nxaudio(FAR const char *arg)
{
    FAR audioctl_s *ctl;
    int ret;
    int i;

    ctl = (FAR audioctl_s *)malloc(sizeof(audioctl_s));
    if(ctl == NULL)
    {
        return NULL;
    }

    ctl->seek = false;
    ctl->seek_position = 0;
    ctl->file_position = 0;

    ctl->fd = open(arg, O_RDONLY);
    if (ctl->fd < 0) {
       free(ctl);
       return NULL;
    }

    ssize_t read_ret = read(ctl->fd, &ctl->wav, sizeof(ctl->wav));
    if (read_ret < (ssize_t)sizeof(ctl->wav)) {
       close(ctl->fd);
       free(ctl);
       return NULL;
    }

    if (ctl->wav.fmt.samplerate > INT_MAX || ctl->wav.fmt.samplerate == 0) {
       close(ctl->fd);
       free(ctl);
       return NULL;
    }

    if (ctl->wav.fmt.bitspersample > INT_MAX || ctl->wav.fmt.bitspersample == 0) {
       close(ctl->fd);
       free(ctl);
       return NULL;
    }

    if (ctl->wav.fmt.numchannels > INT_MAX || ctl->wav.fmt.numchannels == 0) {
       close(ctl->fd);
       free(ctl);
       return NULL;
    }

    ret = init_nxaudio(&ctl->nxaudio, (int)ctl->wav.fmt.samplerate,
                       (int)ctl->wav.fmt.bitspersample,
                       (int)ctl->wav.fmt.numchannels);
    if (ret < 0)
    {
        close(ctl->fd);
        free(ctl);
        return NULL;
    }

    for (i = 0; i < ctl->nxaudio.abufnum; i++)
    {
        app_dequeue_cb((unsigned long)ctl, ctl->nxaudio.abufs[i]);
    }

    ctl->state = AUDIO_CTL_STATE_INIT;

    return ctl;
}

int audio_ctl_start(FAR audioctl_s *ctl)
{
    int ret;

    if (ctl == NULL)
        return -EINVAL;

    if (ctl->state != AUDIO_CTL_STATE_INIT && ctl->state != AUDIO_CTL_STATE_PAUSE)
    {
        return -1;
    }

    ctl->state = AUDIO_CTL_STATE_START;

    pthread_attr_t tattr;
    struct sched_param sparam;

    pthread_attr_init(&tattr);
    sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
    pthread_attr_setschedparam(&tattr, &sparam);
    pthread_attr_setstacksize(&tattr, 4096);

    ret = pthread_create(&ctl->pid, &tattr, audio_loop_thread,
                         (void *)ctl);

    pthread_attr_destroy(&tattr);

    if (ret != 0)
    {
        ctl->state = AUDIO_CTL_STATE_INIT;
        return -1;
    }

    pthread_setname_np(ctl->pid, "audioctl_thread");

    return 0;
}

int audio_ctl_pause(FAR audioctl_s *ctl)
{
    if (ctl == NULL)
        return -EINVAL;

    if (ctl->state != AUDIO_CTL_STATE_START)
    {
        return -1;
    }

    ctl->state = AUDIO_CTL_STATE_PAUSE;

    return nxaudio_pause(&ctl->nxaudio);
}

int audio_ctl_resume(FAR audioctl_s *ctl)
{
    if (ctl == NULL)
        return -EINVAL;

    if (ctl->state != AUDIO_CTL_STATE_PAUSE)
    {
        return -1;
    }

    ctl->state = AUDIO_CTL_STATE_START;

    return nxaudio_resume(&ctl->nxaudio);
}

int audio_ctl_seek(FAR audioctl_s *ctl, unsigned ms)
{
    if (ctl == NULL)
        return -EINVAL;

    ctl->seek_position = ms * ctl->wav.fmt.samplerate * ctl->wav.fmt.bitspersample * ctl->wav.fmt.numchannels / 8;
    ctl->seek = true;

    return 0;
}

int audio_ctl_stop(FAR audioctl_s *ctl)
{
    if (ctl == NULL)
        return -EINVAL;

    if (ctl->state != AUDIO_CTL_STATE_PAUSE && ctl->state != AUDIO_CTL_STATE_START)
    {
        return -1;
    }

    ctl->state = AUDIO_CTL_STATE_STOP;

    nxaudio_stop(&ctl->nxaudio);

    if (ctl->pid > 0)
    {
        pthread_join(ctl->pid, NULL);
    }

    return 0;
}

int audio_ctl_set_volume(FAR audioctl_s *ctl, uint16_t vol)
{
    if (ctl == NULL)
        return -EINVAL;

    return nxaudio_setvolume(&ctl->nxaudio, vol);
}

int audio_ctl_get_position(FAR audioctl_s *ctl)
{
    if (ctl == NULL)
        return -EINVAL;

    return ctl->file_position / (ctl->wav.fmt.bitspersample * ctl->wav.fmt.numchannels * ctl->wav.fmt.samplerate / 8);
}

int audio_ctl_uninit_nxaudio(FAR audioctl_s *ctl)
{
    if (ctl == NULL)
        return -EINVAL;

    if (ctl->state == AUDIO_CTL_STATE_NOP)
    {
        return 0;
    }

    if (ctl->fd > 0)
    {
        close(ctl->fd);
        ctl->fd = -1;
    }

    fin_nxaudio(&ctl->nxaudio);

    free(ctl);

    return 0;
}