Guest User

audio.c

a guest
Aug 7th, 2012
40
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <assert.h>
  5. #include <unistd.h>
  6. #include <semaphore.h>
  7.  
  8. #include <libmodplug/modplug.h>
  9.  
  10. #include "bcm_host.h"
  11. #include "ilclient.h"
  12.  
  13. #include "HybridSong.xm.h"
  14.  
  15. #ifndef countof
  16.    #define countof(arr) (sizeof(arr) / sizeof(arr[0]))
  17. #endif
  18.  
  19. //#define BUFFER_SIZE_SAMPLES 1024
  20. #define BUFFER_SIZE_SAMPLES 512*1024
  21.  
  22. typedef int int32_t;
  23.  
  24. typedef struct {
  25.    sem_t sema;
  26.    ILCLIENT_T *client;
  27.    COMPONENT_T *audio_render;
  28.    COMPONENT_T *list[2];
  29.    OMX_BUFFERHEADERTYPE *user_buffer_list; // buffers owned by the client
  30.    uint32_t num_buffers;
  31.    uint32_t bytes_per_sample;
  32. } AUDIOPLAY_STATE_T;
  33.  
  34. static void input_buffer_callback(void *data, COMPONENT_T *comp)
  35. {
  36.    // do nothing - could add a callback to the user
  37.    // to indicate more buffers may be available.
  38. }
  39.  
  40. int32_t audioplay_create(AUDIOPLAY_STATE_T **handle,
  41.                          uint32_t sample_rate,
  42.                          uint32_t num_channels,
  43.                          uint32_t bit_depth,
  44.                          uint32_t num_buffers,
  45.                          uint32_t buffer_size)
  46. {
  47.    uint32_t bytes_per_sample = (bit_depth * num_channels) >> 3;
  48.    int32_t ret = -1;
  49.  
  50.    *handle = NULL;
  51.  
  52.    // basic sanity check on arguments
  53.    if(sample_rate >= 8000 && sample_rate <= 96000 &&
  54.       (num_channels == 1 || num_channels == 2 || num_channels == 4 || num_channels == 8) &&
  55.       (bit_depth == 16 || bit_depth == 32) &&
  56.       num_buffers > 0 &&
  57.       buffer_size >= bytes_per_sample)
  58.    {
  59.       // buffer lengths must be 16 byte aligned for VCHI
  60.       int size = (buffer_size + 15) & ~15;
  61.       AUDIOPLAY_STATE_T *st;
  62.  
  63.       // buffer offsets must also be 16 byte aligned for VCHI
  64.       st = calloc(1, sizeof(AUDIOPLAY_STATE_T));
  65.  
  66.       if(st)
  67.       {
  68.          OMX_ERRORTYPE error;
  69.          OMX_PARAM_PORTDEFINITIONTYPE param;
  70.          OMX_AUDIO_PARAM_PCMMODETYPE pcm;
  71.          int32_t s;
  72.  
  73.          ret = 0;
  74.          *handle = st;
  75.  
  76.          // create and start up everything
  77.          s = sem_init(&st->sema, 0, 1);
  78.          assert(s == 0);
  79.  
  80.          st->bytes_per_sample = bytes_per_sample;
  81.          st->num_buffers = num_buffers;
  82.  
  83.          st->client = ilclient_init();
  84.          assert(st->client != NULL);
  85.  
  86.          ilclient_set_empty_buffer_done_callback(st->client, input_buffer_callback, st);
  87.  
  88.          error = OMX_Init();
  89.          assert(error == OMX_ErrorNone);
  90.  
  91.          ilclient_create_component(st->client, &st->audio_render, "audio_render", ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_DISABLE_ALL_PORTS);
  92.          assert(st->audio_render != NULL);
  93.  
  94.          st->list[0] = st->audio_render;
  95.  
  96.          // set up the number/size of buffers
  97.          memset(&param, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
  98.          param.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
  99.          param.nVersion.nVersion = OMX_VERSION;
  100.          param.nPortIndex = 100;
  101.  
  102.          error = OMX_GetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
  103.          assert(error == OMX_ErrorNone);
  104.  
  105.          param.nBufferSize = size;
  106.          param.nBufferCountActual = num_buffers;
  107.  
  108.          error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
  109.          assert(error == OMX_ErrorNone);
  110.  
  111.          // set the pcm parameters
  112.          memset(&pcm, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
  113.          pcm.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
  114.          pcm.nVersion.nVersion = OMX_VERSION;
  115.          pcm.nPortIndex = 100;
  116.          pcm.nChannels = num_channels;
  117.          pcm.eNumData = OMX_NumericalDataSigned;
  118.          pcm.eEndian = OMX_EndianLittle;
  119.          pcm.nSamplingRate = sample_rate;
  120.          pcm.bInterleaved = OMX_TRUE;
  121.          pcm.nBitPerSample = bit_depth;
  122.          pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
  123.  
  124.          switch(num_channels) {
  125.          case 1:
  126.             pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
  127.             break;
  128.          case 8:
  129.             pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
  130.             pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
  131.             pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
  132.             pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
  133.             pcm.eChannelMapping[4] = OMX_AUDIO_ChannelLR;
  134.             pcm.eChannelMapping[5] = OMX_AUDIO_ChannelRR;
  135.             pcm.eChannelMapping[6] = OMX_AUDIO_ChannelLS;
  136.             pcm.eChannelMapping[7] = OMX_AUDIO_ChannelRS;
  137.             break;
  138.          case 4:
  139.             pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
  140.             pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
  141.             pcm.eChannelMapping[2] = OMX_AUDIO_ChannelLR;
  142.             pcm.eChannelMapping[3] = OMX_AUDIO_ChannelRR;
  143.             break;
  144.          case 2:
  145.             pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
  146.             pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
  147.             break;
  148.          }
  149.  
  150.          error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamAudioPcm, &pcm);
  151.          assert(error == OMX_ErrorNone);
  152.  
  153.          ilclient_change_component_state(st->audio_render, OMX_StateIdle);
  154.          if(ilclient_enable_port_buffers(st->audio_render, 100, NULL, NULL, NULL) < 0)
  155.          {
  156.             // error
  157.             ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
  158.             ilclient_cleanup_components(st->list);
  159.  
  160.             error = OMX_Deinit();
  161.             assert(error == OMX_ErrorNone);
  162.  
  163.             ilclient_destroy(st->client);
  164.  
  165.             sem_destroy(&st->sema);
  166.             free(st);
  167.             *handle = NULL;
  168.             return -1;
  169.          }
  170.  
  171.          ilclient_change_component_state(st->audio_render, OMX_StateExecuting);
  172.       }
  173.    }
  174.  
  175.    return ret;
  176. }
  177.  
  178. int32_t audioplay_delete(AUDIOPLAY_STATE_T *st)
  179. {
  180.    OMX_ERRORTYPE error;
  181.  
  182.    ilclient_change_component_state(st->audio_render, OMX_StateIdle);
  183.  
  184.    error = OMX_SendCommand(ILC_GET_HANDLE(st->audio_render), OMX_CommandStateSet, OMX_StateLoaded, NULL);
  185.    assert(error == OMX_ErrorNone);
  186.  
  187.    ilclient_disable_port_buffers(st->audio_render, 100, st->user_buffer_list, NULL, NULL);
  188.    ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
  189.    ilclient_cleanup_components(st->list);
  190.  
  191.    error = OMX_Deinit();
  192.    assert(error == OMX_ErrorNone);
  193.  
  194.    ilclient_destroy(st->client);
  195.  
  196.    sem_destroy(&st->sema);
  197.    free(st);
  198.  
  199.    return 0;
  200. }
  201.  
  202. uint8_t *audioplay_get_buffer(AUDIOPLAY_STATE_T *st)
  203. {
  204.    OMX_BUFFERHEADERTYPE *hdr = NULL;
  205.  
  206.    hdr = ilclient_get_input_buffer(st->audio_render, 100, 0);
  207.  
  208.    if(hdr)
  209.    {
  210.       // put on the user list
  211.       sem_wait(&st->sema);
  212.  
  213.       hdr->pAppPrivate = st->user_buffer_list;
  214.       st->user_buffer_list = hdr;
  215.  
  216.       sem_post(&st->sema);
  217.    }
  218.  
  219.    return hdr ? hdr->pBuffer : NULL;
  220. }
  221.  
  222. int32_t audioplay_play_buffer(AUDIOPLAY_STATE_T *st,
  223.                               uint8_t *buffer,
  224.                               uint32_t length)
  225. {
  226.    OMX_BUFFERHEADERTYPE *hdr = NULL, *prev = NULL;
  227.    int32_t ret = -1;
  228.  
  229.    if(length % st->bytes_per_sample)
  230.       return ret;
  231.  
  232.    sem_wait(&st->sema);
  233.  
  234.    // search through user list for the right buffer header
  235.    hdr = st->user_buffer_list;
  236.    while(hdr != NULL && hdr->pBuffer != buffer && hdr->nAllocLen < length)
  237.    {
  238.       prev = hdr;
  239.       hdr = hdr->pAppPrivate;
  240.    }
  241.  
  242.    if(hdr) // we found it, remove from list
  243.    {
  244.       ret = 0;
  245.       if(prev)
  246.          prev->pAppPrivate = hdr->pAppPrivate;
  247.       else
  248.          st->user_buffer_list = hdr->pAppPrivate;
  249.    }
  250.  
  251.    sem_post(&st->sema);
  252.  
  253.    if(hdr)
  254.    {
  255.       OMX_ERRORTYPE error;
  256.  
  257.       hdr->pAppPrivate = NULL;
  258.       hdr->nOffset = 0;
  259.       hdr->nFilledLen = length;
  260.  
  261.       error = OMX_EmptyThisBuffer(ILC_GET_HANDLE(st->audio_render), hdr);
  262.       assert(error == OMX_ErrorNone);
  263.    }
  264.  
  265.    return ret;
  266. }
  267.  
  268. int32_t audioplay_set_dest(AUDIOPLAY_STATE_T *st, const char *name)
  269. {
  270.    int32_t success = -1;
  271.    OMX_CONFIG_BRCMAUDIODESTINATIONTYPE ar_dest;
  272.  
  273.    if (name && strlen(name) < sizeof(ar_dest.sName))
  274.    {
  275.       OMX_ERRORTYPE error;
  276.       memset(&ar_dest, 0, sizeof(ar_dest));
  277.       ar_dest.nSize = sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE);
  278.       ar_dest.nVersion.nVersion = OMX_VERSION;
  279.       strcpy((char *)ar_dest.sName, name);
  280.  
  281.       error = OMX_SetConfig(ILC_GET_HANDLE(st->audio_render), OMX_IndexConfigBrcmAudioDestination, &ar_dest);
  282.       assert(error == OMX_ErrorNone);
  283.       success = 0;
  284.    }
  285.  
  286.    return success;
  287. }
  288.  
  289.  
  290. uint32_t audioplay_get_latency(AUDIOPLAY_STATE_T *st)
  291. {
  292.    OMX_PARAM_U32TYPE param;
  293.    OMX_ERRORTYPE error;
  294.  
  295.    memset(&param, 0, sizeof(OMX_PARAM_U32TYPE));
  296.    param.nSize = sizeof(OMX_PARAM_U32TYPE);
  297.    param.nVersion.nVersion = OMX_VERSION;
  298.    param.nPortIndex = 100;
  299.  
  300.    error = OMX_GetConfig(ILC_GET_HANDLE(st->audio_render), OMX_IndexConfigAudioRenderingLatency, &param);
  301.    assert(error == OMX_ErrorNone);
  302.  
  303.    return param.nU32;
  304. }
  305.  
  306. #define CTTW_SLEEP_TIME 10
  307. #define MIN_LATENCY_TIME 20
  308.  
  309. const int SAMPLERATE[] = {8000, 11025, 44100, 96000};
  310. const int BITDEPTH[] = {16, 32};
  311. const int CHANNELS[] = {1, 2, 4, 8};
  312.  
  313. static const char *audio_dest[] = {"local", "hdmi"};
  314. void play_api_test(int samplerate, int bitdepth, int nchannels, int dest)
  315. {
  316.    AUDIOPLAY_STATE_T *st;
  317.    int32_t ret;
  318.    unsigned int i, j, n;
  319.    int phase = 0;
  320.    int inc = 256<<16;
  321.    int dinc = 0;
  322.    int buffer_size = (BUFFER_SIZE_SAMPLES * bitdepth * nchannels)>>3;
  323.    
  324.    assert(dest == 0 || dest == 1);
  325.  
  326.    ret = audioplay_create(&st, samplerate, nchannels, bitdepth, 10, buffer_size);
  327.    assert(ret == 0);
  328.  
  329.    ret = audioplay_set_dest(st, audio_dest[dest]);
  330.    assert(ret == 0);
  331.    
  332.     ModPlug_Settings settings;
  333.     //memset(&settings, 0, sizeof(settings));
  334.     ModPlug_GetSettings(&settings);
  335.    
  336.     settings.mFlags = 0;
  337.     settings.mChannels = nchannels;
  338.     settings.mBits = bitdepth;
  339.     settings.mFrequency = samplerate;
  340.     settings.mResamplingMode = MODPLUG_RESAMPLE_NEAREST;
  341.     settings.mLoopCount = -1;
  342.     settings.mMaxMixChannels = 32;
  343.    
  344.    ModPlug_SetSettings(&settings);
  345.    
  346.    ModPlugFile* _module = ModPlug_Load((const void*) rawData, sizeof(rawData));
  347.  
  348.    // iterate for 5 seconds worth of packets
  349.    int res = 0;
  350.    //for (n=0; n<((samplerate * 5)/ BUFFER_SIZE_SAMPLES); n++)
  351.    do
  352.    {
  353.       uint8_t *buf;
  354.       int16_t *p;
  355.       uint32_t latency;
  356.  
  357.       //printf("buffer.."); fflush(stdout);
  358.       // ez hulyeseg
  359.       //while((buf = audioplay_get_buffer(st)) == NULL) usleep(10);
  360.      
  361.       buf = audioplay_get_buffer(st);
  362.      
  363.       p = (int16_t *) buf;
  364.      
  365.       printf("render.."); fflush(stdout);
  366.       res = ModPlug_Read(_module, (void*) p, nchannels*BUFFER_SIZE_SAMPLES*sizeof(*p));
  367.      
  368.       printf("latecy, "); fflush(stdout);
  369.      
  370.       // todo: threadbe vagni mindezt, es elfelejteni, hogy van.
  371.       // threadet minden render utan felfuggeszteni, es visszaterni akkor amikor lejar a buffer
  372.      
  373.       // ez mi a fene
  374.       // de ha kiszedem, akkor nem megy
  375.       while((latency = audioplay_get_latency(st)) > (samplerate * (MIN_LATENCY_TIME + CTTW_SLEEP_TIME) / 1000)) usleep(CTTW_SLEEP_TIME*100);
  376.    
  377.       printf("kesz, "); fflush(stdout);
  378.        
  379.       ret = audioplay_play_buffer(st, buf, buffer_size);
  380.      
  381.       printf("play\n"); fflush(stdout);
  382.      
  383.       //assert(ret == 0);
  384.    
  385.    } while (res);
  386.    
  387.     ModPlug_Unload(_module);
  388.    
  389.    audioplay_delete(st);
  390. }
  391.  
  392. int main (int argc, char **argv)
  393. {
  394.    // 0=headphones, 1=hdmi
  395.    int audio_dest = 0;
  396.    // audio sample rate in Hz
  397.    int samplerate = 96000;
  398.    // numnber of audio channels
  399.    int channels = 2;
  400.    // number of bits per sample
  401.    int bitdepth = 16;
  402.    bcm_host_init();
  403.  
  404.    if (argc > 1)
  405.       audio_dest = atoi(argv[1]);
  406.  
  407.    printf("Outputting audio to %s\n", audio_dest==0 ? "analogue":"hdmi");
  408.  
  409.    play_api_test(samplerate, bitdepth, channels, audio_dest);
  410.    return 0;
  411. }
RAW Paste Data