Ignore:
Timestamp:
Apr 14, 2008 2:51:05 AM (16 years ago)
Author:
bennylp
Message:

Ticket #526: Pjsua crash after wav player destroyed inside the eof callback (thanks Tanguy Floc'h)

File:
1 edited

Legend:

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

    r1791 r1927  
    6161    char            *buf; 
    6262    char            *readpos; 
     63    char            *eofpos; 
    6364 
    6465    pj_off_t         fsize; 
     
    107108    pj_status_t status; 
    108109 
    109     /* Can't read file if EOF and loop flag is disabled */ 
    110     if (fport->eof) 
    111         return PJ_EEOF; 
    112  
     110    fport->eofpos = NULL; 
     111     
    113112    while (size_left > 0) { 
    114113 
     
    132131         */ 
    133132        if (size < (pj_ssize_t)size_to_read) { 
    134             /* Call callback, if any. */ 
    135             if (fport->cb) { 
    136                 PJ_LOG(5,(THIS_FILE,  
    137                           "File port %.*s EOF, calling callback", 
    138                           (int)fport->base.info.name.slen, 
    139                           fport->base.info.name.ptr)); 
    140  
    141                 fport->eof = PJ_TRUE; 
    142                 status=(*fport->cb)(&fport->base,fport->base.port_data.pdata); 
    143                 if (status != PJ_SUCCESS) { 
    144                     /* This will crash if file port is destroyed in the  
    145                      * callback, that's why we set the eof flag before 
    146                      * calling the callback: 
    147                      fport->eof = PJ_TRUE; 
    148                     */ 
    149                     return status; 
    150                 } 
    151                  
    152                 fport->eof = PJ_FALSE; 
     133            fport->eof = PJ_TRUE; 
     134            fport->eofpos = fport->buf + fport->bufsize - size_left; 
     135             
     136            if (fport->options & PJMEDIA_FILE_NO_LOOP) { 
     137                /* Zero remaining buffer */ 
     138                pj_bzero(fport->eofpos, size_left); 
    153139            } 
    154140 
    155             if (fport->options & PJMEDIA_FILE_NO_LOOP) { 
    156                 PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..", 
    157                           (int)fport->base.info.name.slen, 
    158                           fport->base.info.name.ptr)); 
    159                 /* Zero remaining buffer */ 
    160                 pj_bzero(fport->buf+size, size_left); 
    161                 /* Mark port as EOF */ 
    162                 fport->eof = PJ_TRUE; 
    163                 /* Must return PJ_SUCCESS, otherwise this buffer  
    164                  * is not read */ 
    165                 return PJ_SUCCESS; 
    166             } else { 
    167                 PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..", 
    168                           (int)fport->base.info.name.slen, 
    169                           fport->base.info.name.ptr)); 
    170                 fport->fpos = fport->start_data; 
    171                 pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); 
    172             } 
     141            /* Rewind file */ 
     142            fport->fpos = fport->start_data; 
     143            pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); 
    173144        } 
    174145    } 
     
    522493 
    523494    pj_assert(fport->base.info.signature == SIGNATURE); 
     495    pj_assert(frame->size <= fport->bufsize); 
     496 
     497    /* EOF is set and readpos already passed the eofpos */ 
     498    if (fport->eof && fport->readpos >= fport->eofpos) { 
     499        pj_status_t status = PJ_SUCCESS; 
     500 
     501        /* Call callback, if any */ 
     502        if (fport->cb) 
     503            status = (*fport->cb)(this_port, fport->base.port_data.pdata); 
     504 
     505        /* If callback returns non PJ_SUCCESS or 'no loop' is specified, 
     506         * return immediately (and don't try to access player port since 
     507         * it might have been destroyed by the callback). 
     508         */ 
     509        if ((status != PJ_SUCCESS) || (fport->options & PJMEDIA_FILE_NO_LOOP)) { 
     510            PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..", 
     511                      (int)fport->base.info.name.slen, 
     512                      fport->base.info.name.ptr)); 
     513 
     514            frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     515            frame->size = 0; 
     516            return PJ_EEOF; 
     517        } 
     518         
     519        PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..", 
     520                  (int)fport->base.info.name.slen, 
     521                  fport->base.info.name.ptr)); 
     522         
     523        fport->eof = PJ_FALSE; 
     524    } 
    524525 
    525526    //frame_size = fport->base.info.bytes_per_frame; 
     
    532533    frame->timestamp.u64 = 0; 
    533534 
    534     if (fport->readpos + frame_size <= fport->buf + fport->bufsize) { 
    535  
     535    if ((fport->readpos + frame_size) <= (fport->buf + fport->bufsize)) 
     536    { 
    536537        /* Read contiguous buffer. */ 
    537538        pj_memcpy(frame->buf, fport->readpos, frame_size); 
     
    559560        pj_memcpy(frame->buf, fport->readpos, endread); 
    560561 
     562        /* End Of Buffer and EOF and NO LOOP */ 
     563        if (fport->eof && (fport->options & PJMEDIA_FILE_NO_LOOP)) { 
     564            fport->readpos += endread; 
     565            pj_bzero((char*)frame->buf + endread, frame_size - endread); 
     566            return PJ_SUCCESS; 
     567        } 
     568 
    561569        /* Second stage: fill up buffer, and read from the start of buffer. */ 
    562570        status = fill_buffer(fport); 
    563571        if (status != PJ_SUCCESS) { 
    564             /* If we don't get anything, return NONE frame. Otherwise 
    565              * return AUDIO frame since we have partial audio. 
    566              */ 
    567             if (endread == 0) { 
    568                 frame->type = PJMEDIA_FRAME_TYPE_NONE; 
    569             } else { 
    570                 pj_bzero(((char*)frame->buf)+endread, frame_size-endread); 
    571             } 
     572            frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     573            frame->size = 0; 
    572574            fport->readpos = fport->buf + fport->bufsize; 
    573             return (endread? PJ_SUCCESS : status); 
     575            return status; 
    574576        } 
    575577 
Note: See TracChangeset for help on using the changeset viewer.