Changeset 1255

Show
Ignore:
Timestamp:
06/08/08 10:17:32 (16 years ago)
Author:
ppalmers
Message:

improve ALSA plugin

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/src/libutil/IpcRingBuffer.cpp

    r1240 r1255  
    417417} 
    418418 
     419// wait for a block of space to be available 
     420enum IpcRingBuffer::eResult 
     421IpcRingBuffer::waitForWrite() 
     422{ 
     423    debugOutput(DEBUG_LEVEL_VERBOSE, "(%p,  %s) IpcRingBuffer\n", this, m_name.c_str()); 
     424    while(getBufferFill() >= m_blocks-1) { 
     425        debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) full\n", this, m_name.c_str()); 
     426        // wait 
     427        sem_wait(&m_activity); 
     428    } 
     429    return eR_OK; 
     430} 
     431 
    419432enum IpcRingBuffer::eResult 
    420433IpcRingBuffer::requestBlockForRead(void **block) 
     
    544557} 
    545558 
     559// wait for a block of data to be available 
     560enum IpcRingBuffer::eResult 
     561IpcRingBuffer::waitForRead() 
     562{ 
     563    while(getBufferFill() == 0) { 
     564        debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) empty\n", this, m_name.c_str()); 
     565        // FIXME: this will work only when no non-data messages are sent 
     566        m_ping_queue.Wait(); 
     567    } 
     568    return eR_OK; 
     569} 
     570 
    546571void 
    547572IpcRingBuffer::show() 
  • trunk/libffado/src/libutil/IpcRingBuffer.h

    r1254 r1255  
    171171    enum IpcRingBuffer::eResult releaseBlockForWrite(); 
    172172 
     173    enum IpcRingBuffer::eResult waitForRead(); 
     174    enum IpcRingBuffer::eResult waitForWrite(); 
     175 
    173176    void show(); 
    174177    void setVerboseLevel(int l); 
  • trunk/libffado/src/libutil/PosixMessageQueue.cpp

    r1240 r1255  
    2929#include <errno.h> 
    3030#include <string.h> 
     31#include <poll.h> 
    3132 
    3233#define MQ_INVALID_ID ((mqd_t) -1) 
     
    328329} 
    329330 
     331bool 
     332PosixMessageQueue::Wait() 
     333{ 
     334    int err; 
     335    struct pollfd poll_fds[1]; 
     336    poll_fds[0].fd = m_handle; // NOTE: not portable, Linux only 
     337    poll_fds[0].events = POLLIN; 
     338 
     339    err = poll (poll_fds, 1, -1); 
     340 
     341    if (err < 0) { 
     342        if (errno == EINTR) { 
     343            debugOutput(DEBUG_LEVEL_VERBOSE, "Ignoring poll return due to signal\n"); 
     344            return true; 
     345        } 
     346        debugFatal("poll error: %s\n", strerror (errno)); 
     347        return false; 
     348    } 
     349 
     350    return true; 
     351} 
    330352 
    331353int 
  • trunk/libffado/src/libutil/PosixMessageQueue.h

    r1240 r1255  
    100100    virtual bool disableNotification(); 
    101101 
     102    virtual bool Wait(); 
     103 
    102104    virtual unsigned int getMaxMessageLength() 
    103105        {return m_attr.mq_msgsize;}; 
  • trunk/libffado/support/alsa/alsa_plugin.cpp

    r1254 r1255  
    4747#include <alsa/pcm_external.h> 
    4848 
    49 #define FFADO_PLUGIN_VERSION "0.0.1
    50  
    51 // #define PRINT_FUNCTION_ENTRY (printMessage("entering %s\n",__FUNCTION__)) 
    52 #define PRINT_FUNCTION_ENTRY 
     49#define FFADO_PLUGIN_VERSION "0.0.2
     50 
     51#define PRINT_FUNCTION_ENTRY (printMessage("entering %s\n",__FUNCTION__)) 
     52// #define PRINT_FUNCTION_ENTRY 
    5353 
    5454typedef struct { 
     
    5959 
    6060    unsigned int hw_ptr; 
    61     unsigned int period_size; 
    6261    unsigned int channels; 
    6362    snd_pcm_channel_area_t *areas; 
     
    7372    // options 
    7473    long int verbose; 
    75     long int period; 
     74    snd_pcm_uframes_t period; 
    7675    long int nb_buffers; 
    7776 
     
    9493} 
    9594 
     95// static snd_pcm_sframes_t snd_pcm_ffado_write(snd_pcm_ioplug_t *io, 
     96//                    const snd_pcm_channel_area_t *areas, 
     97//                    snd_pcm_uframes_t offset, 
     98//                    snd_pcm_uframes_t size) 
     99// { 
     100//     PRINT_FUNCTION_ENTRY; 
     101//     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data; 
     102//     IpcRingBuffer::eResult res; 
     103//     unsigned int i; 
     104//  
     105//     do { 
     106//         uint32_t *audiobuffers_raw; 
     107//         res = ffado->buffer->requestBlockForWrite((void**) &audiobuffers_raw); // pointer voodoo 
     108//         if(res == IpcRingBuffer::eR_OK) { 
     109//             memset(audiobuffers_raw, 0, ffado->channels * ffado->period * 4); 
     110//             for (i = 0; i < ffado->channels; i++) { 
     111//                 uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8)); 
     112//                 uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period; 
     113//                 memcpy(ffado_data_ptr, alsa_data_ptr, ffado->period * 4); 
     114//             } 
     115//             // release the block 
     116//             res = ffado->buffer->releaseBlockForWrite(); 
     117//             if(res != IpcRingBuffer::eR_OK) { 
     118//                 debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error committing memory block\n"); 
     119//                 break; 
     120//             } 
     121//         } else if(res != IpcRingBuffer::eR_Again) { 
     122//             debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error getting memory block\n"); 
     123//         } 
     124//     } while (res == IpcRingBuffer::eR_Again); 
     125//  
     126//     ffado->hw_ptr += ffado->period; 
     127//     ffado->hw_ptr %= io->buffer_size; 
     128//  
     129//     if(size != ffado->period) { 
     130//         debugWarning("size %d, period %d, offset %d\n", size, ffado->period, offset); 
     131//     } else { 
     132//         debugOutput(DEBUG_LEVEL_NORMAL, "size %d, period %d, offset %d\n", size, ffado->period, offset); 
     133//     } 
     134//  
     135//     if(res == IpcRingBuffer::eR_OK) { 
     136//         return ffado->period; 
     137//     } else { 
     138//         debugOutput(DEBUG_LEVEL_NORMAL, "error happened\n"); 
     139//         return -1; 
     140//     } 
     141// } 
     142//  
     143// static snd_pcm_sframes_t snd_pcm_ffado_read(snd_pcm_ioplug_t *io, 
     144//                   const snd_pcm_channel_area_t *areas, 
     145//                   snd_pcm_uframes_t offset, 
     146//                   snd_pcm_uframes_t size) 
     147// { 
     148//     PRINT_FUNCTION_ENTRY; 
     149//     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data; 
     150//     IpcRingBuffer::eResult res; 
     151//     unsigned int i; 
     152//  
     153//     do { 
     154//         uint32_t *audiobuffers_raw; 
     155//         res = ffado->buffer->requestBlockForRead((void**) &audiobuffers_raw); // pointer voodoo 
     156//         if(res == IpcRingBuffer::eR_OK) { 
     157//             for (i = 0; i < ffado->channels; i++) { 
     158//                 uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8)); 
     159//                 uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period; 
     160//                 memcpy(alsa_data_ptr, ffado_data_ptr, ffado->period * 4); 
     161//             } 
     162//             // release the block 
     163//             res = ffado->buffer->releaseBlockForRead(); 
     164//             if(res != IpcRingBuffer::eR_OK) { 
     165//                 debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error committing memory block\n"); 
     166//                 break; 
     167//             } 
     168//         } else if(res != IpcRingBuffer::eR_Again) { 
     169//             debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error getting memory block\n"); 
     170//         } 
     171//     } while (res == IpcRingBuffer::eR_Again); 
     172//  
     173//     ffado->hw_ptr += ffado->period; 
     174//     ffado->hw_ptr %= io->buffer_size; 
     175//  
     176//     if(res == IpcRingBuffer::eR_OK) { 
     177//         return ffado->period; 
     178//     } else { 
     179//         debugOutput(DEBUG_LEVEL_NORMAL, "error happened\n"); 
     180//         return -1; 
     181//     } 
     182// } 
     183 
     184//     if (io->state != SND_PCM_STATE_RUNNING) { 
     185//         if (io->stream == SND_PCM_STREAM_PLAYBACK) { 
     186//             for (channel = 0; channel < io->channels; channel++) 
     187//                 snd_pcm_area_silence(&jack->areas[channel], 0, nframes, io->format); 
     188//             return 0; 
     189//         } 
     190//     } 
     191//      
     192//     areas = snd_pcm_ioplug_mmap_areas(io); 
     193//  
     194//     while (xfer < nframes) { 
     195//         snd_pcm_uframes_t frames = nframes - xfer; 
     196//         snd_pcm_uframes_t offset = jack->hw_ptr; 
     197//         snd_pcm_uframes_t cont = io->buffer_size - offset; 
     198//  
     199//         if (cont < frames) 
     200//             frames = cont; 
     201//  
     202//         for (channel = 0; channel < io->channels; channel++) { 
     203//             if (io->stream == SND_PCM_STREAM_PLAYBACK) 
     204//                 snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format); 
     205//             else 
     206//                 snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format); 
     207//         } 
     208//          
     209//         jack->hw_ptr += frames; 
     210//         jack->hw_ptr %= io->buffer_size; 
     211//         xfer += frames; 
     212//     } 
     213//  
     214//     write(jack->fd, buf, 1); /* for polling */ 
     215 
    96216static int 
    97217snd_pcm_ffado_pollfunction(snd_pcm_ffado_t *ffado) 
     
    102222    snd_pcm_ioplug_t *io = &ffado->io; 
    103223    const snd_pcm_channel_area_t *areas; 
    104     unsigned int i; 
    105224 
    106225    assert(ffado); 
    107226    assert(ffado->buffer); 
    108227 
    109     // wait for data to become available 
    110     // FIXME 
    111  
    112     // get the data address everything should go to/come from 
    113     areas = snd_pcm_ioplug_mmap_areas(io); 
    114  
    115     // get the current offset 
    116     snd_pcm_uframes_t offset = ffado->hw_ptr; 
    117  
    118228    IpcRingBuffer::eResult res; 
    119229    if (ffado->stream == SND_PCM_STREAM_PLAYBACK) { 
    120         do { 
    121             uint32_t *audiobuffers_raw; 
    122             res = ffado->buffer->requestBlockForWrite((void**) &audiobuffers_raw); // pointer voodoo 
    123             if(res == IpcRingBuffer::eR_OK) { 
    124                 memset(audiobuffers_raw, 0, ffado->channels * ffado->period * 4); 
    125                 for (i = 0; i < ffado->channels; i++) { 
    126                     uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8)); 
    127                     uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period; 
    128                     memcpy(ffado_data_ptr, alsa_data_ptr, ffado->period * 4); 
     230        debugOutput(DEBUG_LEVEL_VERBOSE, "PBK: wait\n"); 
     231        res = ffado->buffer->waitForWrite(); 
     232        debugOutput(DEBUG_LEVEL_VERBOSE, "PBK: done, fill: %d\n", ffado->buffer->getBufferFill()); 
     233 
     234        if(res == IpcRingBuffer::eR_OK) { 
     235            do { 
     236                uint32_t *audiobuffers_raw; 
     237                res = ffado->buffer->requestBlockForWrite((void**) &audiobuffers_raw); // pointer voodoo 
     238                if(res == IpcRingBuffer::eR_OK) { 
     239                    // we have the memory block, do the actual transfer 
     240                    // silence the block 
     241                    memset(audiobuffers_raw, 0, ffado->channels * ffado->period * 4); 
     242                    if(io->state == SND_PCM_STATE_RUNNING) { 
     243                        // get the data address the data comes from 
     244                        areas = snd_pcm_ioplug_mmap_areas(io); 
     245 
     246                        // create the list of areas where the data goes to 
     247                        unsigned int channel = 0; 
     248                        for (channel = 0; channel < ffado->channels; channel++) { 
     249                            uint32_t *target = (audiobuffers_raw + channel*ffado->period); 
     250                            ffado->areas[channel].addr = target; 
     251                            ffado->areas[channel].first = 0; 
     252                            ffado->areas[channel].step = 4*8; // FIXME: hardcoded sample size 
     253                        } 
     254                        snd_pcm_uframes_t xfer = 0; 
     255                        while (xfer < ffado->period) { 
     256                            snd_pcm_uframes_t frames = ffado->period - xfer; 
     257                            snd_pcm_uframes_t offset = ffado->hw_ptr; 
     258                            snd_pcm_uframes_t cont = io->buffer_size - offset; 
     259 
     260                            if (cont < frames) 
     261                                frames = cont; 
     262 
     263                            for (channel = 0; channel < ffado->channels; channel++) { 
     264                                snd_pcm_area_copy(&ffado->areas[channel], xfer, &areas[channel], offset, frames, io->format); 
     265                            } 
     266 
     267                            ffado->hw_ptr += frames; 
     268                            ffado->hw_ptr %= io->buffer_size; 
     269                            xfer += frames; 
     270                        } 
     271                    } 
     272                    // release the block 
     273                    res = ffado->buffer->releaseBlockForWrite(); 
     274                    if(res != IpcRingBuffer::eR_OK) { 
     275                        debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error committing memory block\n"); 
     276                        break; 
     277                    } 
     278                } else if(res != IpcRingBuffer::eR_Again) { 
     279                    debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error getting memory block\n"); 
    129280                } 
    130                 // release the block 
    131                 res = ffado->buffer->releaseBlockForWrite(); 
    132                 if(res != IpcRingBuffer::eR_OK) { 
    133                     debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error committing memory block\n"); 
    134                     break; 
     281                if (res == IpcRingBuffer::eR_Again) { 
     282                    debugWarning("Again\n"); 
    135283                } 
    136             } else if(res != IpcRingBuffer::eR_Again) { 
    137                 debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error getting memory block\n"); 
    138             } 
    139         } while (res == IpcRingBuffer::eR_Again); 
     284            } while (res == IpcRingBuffer::eR_Again); 
     285        } else { 
     286            debugError("Error while waiting\n"); 
     287        } 
    140288    } else { 
    141         do { 
    142             uint32_t *audiobuffers_raw; 
    143             res = ffado->buffer->requestBlockForRead((void**) &audiobuffers_raw); // pointer voodoo 
    144             if(res == IpcRingBuffer::eR_OK) { 
    145                 for (i = 0; i < ffado->channels; i++) { 
    146                     uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8)); 
    147                     uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period; 
    148                     memcpy(alsa_data_ptr, ffado_data_ptr, ffado->period * 4); 
     289        res = ffado->buffer->waitForRead(); 
     290        if(res == IpcRingBuffer::eR_OK) { 
     291            do { 
     292                uint32_t *audiobuffers_raw; 
     293                res = ffado->buffer->requestBlockForRead((void**) &audiobuffers_raw); // pointer voodoo 
     294                if(res == IpcRingBuffer::eR_OK) { 
     295                    // we have the memory block, do the actual transfer 
     296                    if(io->state == SND_PCM_STATE_RUNNING) { 
     297                        // get the data address the data goes to 
     298                        areas = snd_pcm_ioplug_mmap_areas(io); 
     299 
     300                        // create the list of areas where the data comes from 
     301                        unsigned int channel = 0; 
     302                        for (channel = 0; channel < io->channels; channel++) { 
     303                            ffado->areas[channel].addr = audiobuffers_raw + channel*ffado->period; 
     304                            ffado->areas[channel].first = 0; 
     305                            ffado->areas[channel].step = 4*8; // FIXME: hardcoded sample size 
     306                        } 
     307                        snd_pcm_uframes_t xfer = 0; 
     308                        while (xfer < ffado->period) { 
     309                            snd_pcm_uframes_t frames = ffado->period - xfer; 
     310                            snd_pcm_uframes_t offset = ffado->hw_ptr; 
     311                            snd_pcm_uframes_t cont = io->buffer_size - offset; 
     312 
     313                            if (cont < frames) 
     314                                frames = cont; 
     315 
     316                            for (channel = 0; channel < io->channels; channel++) { 
     317                                snd_pcm_area_copy(&areas[channel], offset, &ffado->areas[channel], xfer, frames, io->format); 
     318                            } 
     319 
     320                            ffado->hw_ptr += frames; 
     321                            ffado->hw_ptr %= io->buffer_size; 
     322                            xfer += frames; 
     323                        } 
     324                    } 
     325                    // release the block 
     326                    res = ffado->buffer->releaseBlockForRead(); 
     327                    if(res != IpcRingBuffer::eR_OK) { 
     328                        debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error committing memory block\n"); 
     329                        break; 
     330                    } 
     331                } else if(res != IpcRingBuffer::eR_Again) { 
     332                    debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error getting memory block\n"); 
    149333                } 
    150                 // release the block 
    151                 res = ffado->buffer->releaseBlockForRead(); 
    152                 if(res != IpcRingBuffer::eR_OK) { 
    153                     debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error committing memory block\n"); 
    154                     break; 
    155                 } 
    156             } else if(res != IpcRingBuffer::eR_Again) { 
    157                 debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error getting memory block\n"); 
    158             } 
    159         } while (res == IpcRingBuffer::eR_Again); 
    160     } 
    161  
    162     ffado->hw_ptr += ffado->period; 
    163     ffado->hw_ptr %= io->buffer_size; 
     334            } while (res == IpcRingBuffer::eR_Again); 
     335        } else { 
     336            debugError("Error while waiting\n"); 
     337        } 
     338    } 
    164339 
    165340    write(ffado->fd, buf, 1); /* for polling */ 
     
    173348} 
    174349 
     350// static int 
     351// snd_pcm_ffado_pollfunction(snd_pcm_ffado_t *ffado) 
     352// { 
     353//     // wait for a period 
     354//     IpcRingBuffer::eResult res; 
     355//     if(ffado->stream == SND_PCM_STREAM_PLAYBACK) { 
     356//         res = ffado->buffer->waitForWrite(); 
     357//     } else { 
     358//         res = ffado->buffer->waitForRead(); 
     359//     } 
     360//  
     361//     if(res == IpcRingBuffer::eR_OK) { 
     362//         char buf[1]; 
     363//         write(ffado->fd, buf, 1); /* for polling */ 
     364//         return 0; 
     365//     } else { 
     366//         return -1; 
     367//     } 
     368// } 
     369 
    175370static void * ffado_workthread(void *arg) 
    176371{ 
     
    182377    pthread_setcancelstate (PTHREAD_CANCEL_DEFERRED, &oldstate); 
    183378 
    184     while (1) { 
    185         snd_pcm_ffado_pollfunction(ffado); 
     379    while (snd_pcm_ffado_pollfunction(ffado) == 0) { 
    186380        pthread_testcancel(); 
    187381    } 
    188  
     382    return 0; 
    189383} 
    190384 
     
    205399    PRINT_FUNCTION_ENTRY; 
    206400    if (ffado) { 
    207         close(ffado->fd); 
    208         close(ffado->io.poll_fd); 
     401        if (ffado->fd >= 0) close(ffado->fd); 
     402        if (ffado->io.poll_fd >= 0) close(ffado->io.poll_fd); 
     403        free(ffado->areas); 
    209404        free(ffado); 
    210405    } 
     
    339534    ffado_pcm_callback.prepare = snd_pcm_ffado_prepare; 
    340535    ffado_pcm_callback.poll_revents = snd_pcm_ffado_poll_revents; 
     536//     if (stream == SND_PCM_STREAM_PLAYBACK) { 
     537//         ffado_pcm_callback.transfer = snd_pcm_ffado_write; 
     538//     } else { 
     539//         ffado_pcm_callback.transfer = snd_pcm_ffado_read; 
     540//     } 
    341541 
    342542    // prepare io struct 
     
    345545    ffado->io.callback = &ffado_pcm_callback; 
    346546    ffado->io.private_data = ffado; 
     547//     ffado->io.mmap_rw = 0; 
    347548    ffado->io.mmap_rw = 1; 
    348549    ffado->io.poll_fd = fd[1]; 
     
    370571 
    371572    setDebugLevel(ffado->verbose); 
     573 
     574    ffado->areas = (snd_pcm_channel_area_t *)calloc(ffado->channels, sizeof(snd_pcm_channel_area_t)); 
     575    if (!ffado->areas) { 
     576        snd_pcm_ffado_free(ffado); 
     577        return -ENOMEM; 
     578    } 
    372579 
    373580    // prepare the IPC buffer 
  • trunk/libffado/tests/streaming/test-ipcclient.cpp

    r1240 r1255  
    3131#include <iostream> 
    3232#include <signal.h> 
     33 
     34#include <math.h> 
    3335 
    3436using namespace Util; 
     
    7981    long int period; 
    8082    long int nb_buffers; 
     83    long int test_tone; 
     84    float test_tone_freq; 
    8185} arguments; 
    8286 
     
    173177    arguments.playback          = 0; 
    174178    arguments.capture           = 0; 
     179    arguments.test_tone_freq    = 0.01; 
     180    arguments.test_tone         = 1; 
    175181 
    176182    // arg parsing 
     
    243249    int pbkcnt = 0; 
    244250 
     251    float frame_counter = 0.0; 
     252    float sine_advance = 0.0; 
     253    float amplitude = 0.97; 
     254    sine_advance = 2.0*M_PI*arguments.test_tone_freq; 
     255    uint32_t sine_buff[arguments.period]; 
     256 
    245257    run=1; 
    246258    while(run) { 
     259        // test tone generation 
     260        if (arguments.test_tone) { 
     261            // generate the test tone 
     262            for (int i=0; i < arguments.period; i++) { 
     263                float v = amplitude * sin(sine_advance * (frame_counter + (float)i)); 
     264                v = (v * 2147483392.0); 
     265                int32_t tmp = ((int) v); 
     266                tmp = tmp >> 8; 
     267                memcpy(&sine_buff[i], &tmp, 4); 
     268            } 
     269            for(int j=0; j<arguments.playback; j++) { 
     270                uint32_t *target = (uint32_t *)(playback_buff + j*arguments.period*4); 
     271                memcpy(target, &sine_buff, arguments.period*4); 
     272            } 
     273        } 
     274        frame_counter += arguments.period; 
     275 
    247276        // write the data 
    248277        IpcRingBuffer::eResult res;