Ignore:
Timestamp:
Apr 10, 2008 9:53:16 AM (16 years ago)
Author:
bennylp
Message:

Ticket #523: Handle incomplete audio frame from sound device (e.g. OSS)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/pasound.c

    r1893 r1918  
    7878    pj_thread_desc       play_thread_desc; 
    7979    pj_thread_t         *play_thread; 
     80 
     81    /* Sometime the record callback does not return framesize as configured 
     82     * (e.g: in OSS), while this module must guarantee returning framesize 
     83     * as configured in the creation settings. In this case, we need a buffer  
     84     * for the recorded samples. 
     85     */ 
     86    pj_int16_t          *rec_buf; 
     87    unsigned             rec_buf_size; 
     88 
     89    /* Sometime the player callback does not request framesize as configured 
     90     * (e.g: in Linux OSS) while sound device will always get samples from  
     91     * the other component as many as configured samples_per_frame.  
     92     */ 
     93    pj_int16_t          *play_buf; 
     94    unsigned             play_buf_size; 
    8095}; 
    8196 
     
    89104{ 
    90105    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData; 
    91     pj_status_t status; 
    92  
    93     pj_assert(frameCount * stream->channel_count == stream->samples_per_frame); 
     106    pj_status_t status = 0; 
     107    unsigned nsamples; 
    94108 
    95109    PJ_UNUSED_ARG(output); 
     
    119133    stream->rec_timestamp += frameCount; 
    120134 
    121     status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp,  
    122                                (void*)input,  
    123                                frameCount * stream->bytes_per_sample * 
    124                                  stream->channel_count); 
    125      
     135    /* Calculate number of samples we've got */ 
     136    nsamples = frameCount * stream->channel_count + stream->rec_buf_size; 
     137 
     138    if (nsamples >= stream->samples_per_frame)  
     139    { 
     140        /* If buffer is not empty, combine the buffer with the just incoming 
     141         * samples, then call put_frame. 
     142         */ 
     143        if (stream->rec_buf_size) { 
     144            unsigned chunk_size = 0; 
     145         
     146            chunk_size = stream->samples_per_frame - stream->rec_buf_size; 
     147            pjmedia_copy_samples(stream->rec_buf + stream->rec_buf_size, 
     148                                 (pj_int16_t*)input, chunk_size); 
     149            status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp, 
     150                                       (void*) stream->rec_buf,  
     151                                       stream->samples_per_frame *  
     152                                       stream->bytes_per_sample); 
     153 
     154            input = (pj_int16_t*) input + chunk_size; 
     155            nsamples -= stream->samples_per_frame; 
     156            stream->rec_buf_size = 0; 
     157        } 
     158 
     159        /* Give all frames we have */ 
     160        while (nsamples >= stream->samples_per_frame && status == 0) { 
     161            status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp, 
     162                                       (void*) input,  
     163                                       stream->samples_per_frame *  
     164                                       stream->bytes_per_sample); 
     165            input = (pj_int16_t*) input + stream->samples_per_frame; 
     166            nsamples -= stream->samples_per_frame; 
     167        } 
     168 
     169        /* Store the remaining samples into the buffer */ 
     170        if (nsamples && status == 0) { 
     171            stream->rec_buf_size = nsamples; 
     172            pjmedia_copy_samples((pj_int16_t*)stream->rec_buf,  
     173                                 (pj_int16_t*)input, nsamples); 
     174        } 
     175 
     176    } else { 
     177        /* Not enough samples, let's just store them in the buffer */ 
     178        pjmedia_copy_samples((pj_int16_t*)(stream->rec_buf +  
     179                                           stream->rec_buf_size), 
     180                                           (pj_int16_t*)input,  
     181                                           frameCount * stream->channel_count); 
     182        stream->rec_buf_size += frameCount * stream->channel_count; 
     183    } 
     184 
    126185    if (status==0)  
    127186        return paContinue; 
     
    140199{ 
    141200    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData; 
    142     pj_status_t status; 
    143     unsigned size = frameCount * stream->bytes_per_sample * 
    144                     stream->channel_count; 
    145  
    146     pj_assert(frameCount * stream->channel_count == stream->samples_per_frame); 
     201    pj_status_t status = 0; 
     202    unsigned nsamples_req = frameCount * stream->channel_count; 
    147203 
    148204    PJ_UNUSED_ARG(input); 
     
    172228    stream->play_timestamp += frameCount; 
    173229 
    174     status = (*stream->play_cb)(stream->user_data, stream->play_timestamp,  
    175                                 output, size); 
     230    /* Check if any buffered samples */ 
     231    if (stream->play_buf_size) { 
     232        /* samples buffered >= requested by sound device */ 
     233        if (stream->play_buf_size >= nsamples_req) { 
     234            pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,  
     235                                 nsamples_req); 
     236            stream->play_buf_size -= nsamples_req; 
     237            pjmedia_move_samples(stream->play_buf,  
     238                                 stream->play_buf + nsamples_req, 
     239                                 stream->play_buf_size); 
     240            nsamples_req = 0; 
     241             
     242            return paContinue; 
     243        } 
     244 
     245        /* samples buffered < requested by sound device */ 
     246        pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,  
     247                             stream->play_buf_size); 
     248        nsamples_req -= stream->play_buf_size; 
     249        output = (pj_int16_t*)output + stream->play_buf_size; 
     250        stream->play_buf_size = 0; 
     251    } 
     252 
     253    /* Fill output buffer as requested */ 
     254    while (nsamples_req && status == 0) { 
     255        if (nsamples_req >= stream->samples_per_frame) { 
     256            status = (*stream->play_cb)(stream->user_data,  
     257                                        stream->play_timestamp,  
     258                                        output,  
     259                                        stream->samples_per_frame *  
     260                                        stream->bytes_per_sample); 
     261            nsamples_req -= stream->samples_per_frame; 
     262            output = (pj_int16_t*)output + stream->samples_per_frame; 
     263        } else { 
     264            status = (*stream->play_cb)(stream->user_data,  
     265                                        stream->play_timestamp,  
     266                                        stream->play_buf, 
     267                                        stream->samples_per_frame *  
     268                                        stream->bytes_per_sample); 
     269            pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,  
     270                                 nsamples_req); 
     271            stream->play_buf_size = stream->samples_per_frame - nsamples_req; 
     272            pjmedia_move_samples(stream->play_buf, stream->play_buf+nsamples_req, 
     273                                 stream->play_buf_size); 
     274            nsamples_req = 0; 
     275        } 
     276    } 
    176277     
    177278    if (status==0)  
     
    450551    stream->rec_cb = rec_cb; 
    451552 
     553    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool,  
     554                      stream->samples_per_frame * stream->bytes_per_sample); 
     555    stream->rec_buf_size = 0; 
     556 
    452557    pj_bzero(&inputParam, sizeof(inputParam)); 
    453558    inputParam.device = index; 
     
    547652    stream->channel_count = channel_count; 
    548653    stream->play_cb = play_cb; 
     654 
     655    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool,  
     656                       stream->samples_per_frame * stream->bytes_per_sample); 
     657    stream->play_buf_size = 0; 
    549658 
    550659    pj_bzero(&outputParam, sizeof(outputParam)); 
     
    670779    stream->rec_cb = rec_cb; 
    671780    stream->play_cb = play_cb; 
     781 
     782    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool,  
     783                      stream->samples_per_frame * stream->bytes_per_sample); 
     784    stream->rec_buf_size = 0; 
     785 
     786    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool,  
     787                       stream->samples_per_frame * stream->bytes_per_sample); 
     788    stream->play_buf_size = 0; 
    672789 
    673790    pj_bzero(&inputParam, sizeof(inputParam)); 
Note: See TracChangeset for help on using the changeset viewer.