static pj_status_t file_fill_buffer(struct playlist_port *fport)
{
    pj_uint32_t size_left = fport->bufsize;
    pj_uint32_t size_to_read;
    pj_ssize_t size;
    pj_status_t status;
    int current_file = fport->current_file;

    /* Can't read file if EOF and loop flag is disabled */
    if (fport->eof)
	return PJ_EEOF;

    while (size_left > 0)
    {
	/* Calculate how many bytes to read in this run. */
	size = size_to_read = size_left;
	status = pj_file_read(fport->fd_list[current_file],
			      &fport->buf[fport->bufsize-size_left],
			      &size);
	if (status != PJ_SUCCESS)
	    return status;
	
	if (size < 0)
	{
	    /* Should return more appropriate error code here.. */
	    return PJ_ECANCELLED;
	}

        if (size > (pj_ssize_t)fport->data_left_list[current_file]) {
            /* We passed the end of the data chunk,
             * only count the portion read from the data chunk.
             */
            size = (pj_ssize_t)fport->data_left_list[current_file];
        }
	
	size_left -= (pj_uint32_t)size;
	fport->data_left_list[current_file] -= (pj_uint32_t)size;
	fport->fpos_list[current_file] += size;	
	
	/* If size is less than size_to_read, it indicates that we've
	 * encountered EOF. Rewind the file.
	 */
	if (size < (pj_ssize_t)size_to_read)
	{
	    /* Rewind the file for the next iteration */
	    fport->fpos_list[current_file] = 
		fport->start_data_list[current_file];
	    pj_file_setpos(fport->fd_list[current_file], 
			   fport->fpos_list[current_file], PJ_SEEK_SET);
	    fport->data_left_list[current_file] = 
					    fport->data_len_list[current_file];

	    /* Move to next file */
	    current_file++;
	    fport->current_file = current_file;

	    if (fport->current_file == fport->max_file)
	    {
		/* Clear the remaining part of the buffer first, to prevent
		 * old samples from being played. If the playback restarts,
		 * this will be overwritten by new reading.
		 */
		if (size_left > 0) {
		    pj_bzero(&fport->buf[fport->bufsize-size_left], 
			     size_left);
		}

		/* All files have been played. Call callback, if any. */
		if (fport->cb2) {
	    	    pj_bool_t no_loop = (fport->options & PJMEDIA_FILE_NO_LOOP);

	    	    if (!fport->subscribed) {
	    		status = pjmedia_event_subscribe(NULL, &file_on_event,
	    				         	 fport, fport);
	    		fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
	    			    	    PJ_FALSE;
	    	    }

	    	    if (fport->subscribed && fport->eof != 2) {
	    	    	pjmedia_event event;

	    		if (no_loop) {
	    	    	    /* To prevent the callback from being called
	    	    	     * repeatedly.
	    	    	     */
	    	    	    fport->eof = 2;
	    		} else {
	    	    	    fport->eof = PJ_FALSE;
		    	    /* start with first file again. */
		    	    fport->current_file = current_file = 0;
		    	    fport->fpos_list[0] = fport->start_data_list[0];
		    	    pj_file_setpos(fport->fd_list[0],
		    	    		   fport->fpos_list[0], PJ_SEEK_SET);
		    	    fport->data_left_list[0] = fport->data_len_list[0];
	    		}

	    	    	pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
	                      	       	   NULL, fport);
	    	    	pjmedia_event_publish(NULL, fport, &event,
	                              	  PJMEDIA_EVENT_PUBLISH_POST_EVENT);
	            }

	    	    /* Should not access player port after this since
	     	     * it might have been destroyed by the callback.
	     	     */
	    	    return (no_loop? PJ_EEOF: PJ_SUCCESS);

	    	} else if (fport->cb) {
		    PJ_LOG(5,(THIS_FILE,
			      "File port %.*s EOF, calling callback",
			      (int)fport->base.info.name.slen,
			      fport->base.info.name.ptr));
		    
		    fport->eof = PJ_TRUE;

		    status = (*fport->cb)(&fport->base,
					  fport->base.port_data.pdata);

		    if (status != PJ_SUCCESS)
		    {
			/* This will crash if file port is destroyed in the
			 * callback, that's why we set the eof flag before
			 * calling the callback:
			 fport->eof = PJ_TRUE;
			 */
			return status;
		    }

		    fport->eof = PJ_FALSE;
		}


		if (fport->options & PJMEDIA_FILE_NO_LOOP)
		{
		    PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..",
			      (int)fport->base.info.name.slen,
			      fport->base.info.name.ptr));
		    fport->eof = PJ_TRUE;
		    return PJ_EEOF;
		}
		else
		{
		    PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..",
			      (int)fport->base.info.name.slen,
			      fport->base.info.name.ptr));
		    
		    /* start with first file again. */
		    fport->current_file = current_file = 0;
		    fport->fpos_list[0] = fport->start_data_list[0];
		    pj_file_setpos(fport->fd_list[0], fport->fpos_list[0],
				   PJ_SEEK_SET);
		    fport->data_left_list[0] = fport->data_len_list[0];
		}		
		
	    } /* if current_file == max_file */

	} /* size < size_to_read */

    } /* while () */
    
    /* Convert samples to host rep */
    samples_to_host((pj_int16_t*)fport->buf, fport->bufsize/BYTES_PER_SAMPLE);
    
    return PJ_SUCCESS;
}