static int play_file(unsigned rate, unsigned channels, int fd,
              unsigned flags, const char *device, unsigned data_sz)
{
    struct pcm *pcm;
    struct mixer *mixer;
    struct pcm_ctl *ctl = NULL;
    unsigned bufsize;
    char *data;
    long avail;
    long frames;
    int nfds = 1;
    struct snd_xferi x;
    unsigned offset = 0;
    int err;
    static int start = 0;
    struct pollfd pfd[1];
    int remainingData = 0;

    flags |= PCM_OUT;

    if (channels == 1)
        flags |= PCM_MONO;
    else if (channels == 6)
	flags |= PCM_5POINT1;
    else
        flags |= PCM_STEREO;

    if (debug)
        flags |= DEBUG_ON;
    else
        flags |= DEBUG_OFF;

    pcm = pcm_open(flags, device);
    if (pcm < 0)
        return pcm;

    if (!pcm_ready(pcm)) {
        pcm_close(pcm);
        return -EBADFD;
    }

#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
    if (compressed) {
       struct snd_compr_caps compr_cap;
       struct snd_compr_params compr_params;
       if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
          fprintf(stderr, "Aplay: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
       if (!period)
           period = compr_cap.min_fragment_size;
           switch (get_compressed_format(compr_codec)) {
           case FORMAT_MP3:
               compr_params.codec.id = compr_cap.codecs[FORMAT_MP3];
               break;
           case FORMAT_AC3_PASS_THROUGH:
               compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH];
               printf("codec -d = %x\n", compr_params.codec.id);
               break;
           default:
               break;
           }
       if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
          fprintf(stderr, "Aplay: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
    }
#endif
    pcm->channels = channels;
    pcm->rate = rate;
    pcm->flags = flags;
    pcm->format = format;
    if (set_params(pcm)) {
        fprintf(stderr, "Aplay:params setting failed\n");
        pcm_close(pcm);
        return -errno;
    }

    if (!pcm_flag) {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
       if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
          fprintf(stderr, "Aplay: Hostless IOCTL_START Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
        while(1);
    }

    remainingData = data_sz;

    if (flags & PCM_MMAP) {
        u_int8_t *dst_addr = NULL;
        struct snd_pcm_sync_ptr *sync_ptr1 = pcm->sync_ptr;
        if (mmap_buffer(pcm)) {
             fprintf(stderr, "Aplay:params setting failed\n");
             pcm_close(pcm);
             return -errno;
        }
        if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
        }

        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);

        pfd[0].fd = pcm->timer_fd;
        pfd[0].events = POLLIN;

        frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
        for (;;) {
             if (!pcm->running) {
                  if (pcm_prepare(pcm)) {
                      fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
                      pcm_close(pcm);
                      return -errno;
                  }
                  pcm->running = 1;
                  start = 0;
             }
             /* Sync the current Application pointer from the kernel */
             pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
             err = sync_ptr(pcm);
             if (err == EPIPE) {
                 fprintf(stderr, "Aplay:Failed in sync_ptr \n");
                 /* we failed to make our window -- try to restart */
                 pcm->underruns++;
                 pcm->running = 0;
                 continue;
             }
             /*
              * Check for the available buffer in driver. If available buffer is
              * less than avail_min we need to wait
              */
             avail = pcm_avail(pcm);
             if (avail < 0) {
                 fprintf(stderr, "Aplay:Failed in pcm_avail\n");
                 pcm_close(pcm);
                 return avail;
             }
             if (avail < pcm->sw_p->avail_min) {
                 poll(pfd, nfds, TIMEOUT_INFINITE);
                 continue;
             }
             /*
              * Now that we have buffer size greater than avail_min available to
              * to be written we need to calcutate the buffer offset where we can
              * start writting.
              */
             dst_addr = dst_address(pcm);

             if (debug) {
                 fprintf(stderr, "dst_addr = 0x%08x\n", dst_addr);
                 fprintf(stderr, "Aplay:avail = %d frames = %d\n",avail, frames);
                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
             }

             /*
              * Read from the file to the destination buffer in kernel mmaped buffer
              * This reduces a extra copy of intermediate buffer.
              */
             memset(dst_addr, 0x0, bufsize);

             if (data_sz && !piped) {
                 if (remainingData < bufsize) {
                     bufsize = remainingData;
                     frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4);
                 }
             }

             err = read(fd, dst_addr , bufsize);
             if (debug)
                 fprintf(stderr, "read %d bytes from file\n", err);
             if (err <= 0)
                 break;

             if (data_sz && !piped) {
                 remainingData -= bufsize;
                 if (remainingData <= 0)
                     break;
             }

             /*
              * Increment the application pointer with data written to kernel.
              * Update kernel with the new sync pointer.
              */
             pcm->sync_ptr->c.control.appl_ptr += frames;
             pcm->sync_ptr->flags = 0;

             err = sync_ptr(pcm);
             if (err == EPIPE) {
                 fprintf(stderr, "Aplay:Failed in sync_ptr 2 \n");
                 /* we failed to make our window -- try to restart */
                 pcm->underruns++;
                 pcm->running = 0;
                 continue;
             }

             if (debug) {
                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->sync_ptr->c.control.appl_ptr);
#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
                 if (compressed && start) {
                    struct snd_compr_tstamp tstamp;
		    if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
			fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
                    else
	                fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
		}
#endif
             }
             /*
              * If we have reached start threshold of buffer prefill,
              * its time to start the driver.
              */
                 if(start)
                     goto start_done;
                 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
                     err = -errno;
                     if (errno == EPIPE) {
                         fprintf(stderr, "Aplay:Failed in SNDRV_PCM_IOCTL_START\n");
                         /* we failed to make our window -- try to restart */
                         pcm->underruns++;
                         pcm->running = 0;
                         continue;
                    } else {
                        fprintf(stderr, "Aplay:Error no %d \n", errno);
                        pcm_close(pcm);
                        return -errno;
                    }
                } else
                    start = 1;

start_done:
                offset += frames;
        }
        while(1) {
            pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
            sync_ptr(pcm);
            /*
             * Check for the available buffer in driver. If available buffer is
             * less than avail_min we need to wait
             */
            if (pcm->sync_ptr->s.status.hw_ptr >= pcm->sync_ptr->c.control.appl_ptr) {
                fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                           pcm->sync_ptr->s.status.hw_ptr,
                           pcm->sync_ptr->c.control.appl_ptr);
                break;
            } else
                poll(pfd, nfds, TIMEOUT_INFINITE);
        }
    } else {
        if (pcm_prepare(pcm)) {
            fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
            pcm_close(pcm);
            return -errno;
        }

        bufsize = pcm->period_size;

        data = calloc(1, bufsize);
        if (!data) {
            fprintf(stderr, "Aplay:could not allocate %d bytes\n", bufsize);
            pcm_close(pcm);
            return -ENOMEM;
        }

        if (data_sz && !piped) {
            if (remainingData < bufsize)
                bufsize = remainingData;
        }

        while (read(fd, data, bufsize) > 0) {
            if (pcm_write(pcm, data, bufsize)){
                fprintf(stderr, "Aplay: pcm_write failed\n");
                free(data);
                pcm_close(pcm);
                return -errno;
            }
            memset(data, 0, bufsize);

            if (data_sz && !piped) {
                remainingData -= bufsize;
                if (remainingData <= 0)
                    break;
                if (remainingData < bufsize)
                       bufsize = remainingData;
            }
        }
        free(data);
    }
    fprintf(stderr, "Aplay: Done playing\n");
    pcm_close(pcm);
    return 0;
}
Example #2
0
int play_file(unsigned rate, unsigned channels, int fd, unsigned count,
              unsigned flags, const char *device)
{
    struct pcm *pcm;
    struct mixer *mixer;
    struct pcm_ctl *ctl = NULL;
    unsigned bufsize;
    char *data;
    long avail;
    long frames;
    int nfds = 1;
    struct snd_xferi x;
    unsigned offset = 0;
    int err;
    static int start = 0;
    struct pollfd pfd[1];

    flags |= PCM_OUT;

    if (channels == 1)
        flags |= PCM_MONO;
    else
        flags |= PCM_STEREO;

    if (debug)
        flags |= DEBUG_ON;
    else
        flags |= DEBUG_OFF;

    pcm = pcm_open(flags, device);
    if (pcm < 0)
        return pcm;

    if (!pcm_ready(pcm)) {
        pcm_close(pcm);
        return -EBADFD;
    }
    pcm->channels = channels;
    pcm->rate = rate;
    pcm->flags = flags;
    if (set_params(pcm)) {
        fprintf(stderr, "Aplay:params setting failed\n");
        pcm_close(pcm);
        return -errno;
    }

    if (!pcm_flag) {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        while(1);
    }

    if (flags & PCM_MMAP) {
        if (mmap_buffer(pcm)) {
             fprintf(stderr, "Aplay:params setting failed\n");
             pcm_close(pcm);
             return -errno;
        }
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);
        data = calloc(1, bufsize);
        if (!data) {
           fprintf(stderr, "Aplay:could not allocate %d bytes\n", count);
           pcm_close(pcm);
           return -ENOMEM;
        }

        pfd[0].fd = pcm->fd;
        pfd[0].events = POLLOUT;
        while (read(fd, data, bufsize) == bufsize) {
            x.buf = data;
            x.frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
            frames = x.frames;

            for (;;) {
                if (!pcm->running) {
                    if (pcm_prepare(pcm))
                        return --errno;
                    pcm->running = 1;
                    start = 0;
                }
                pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
                err = sync_ptr(pcm);
                if (err == EPIPE) {
                     fprintf(stderr, "Aplay:Failed in sync_ptr \n");
                     /* we failed to make our window -- try to restart */
                     pcm->underruns++;
                     pcm->running = 0;
                     continue;
                }
                avail = pcm_avail(pcm);
                if (debug)
                    fprintf(stderr, "Aplay:avail 1 = %d frames = %d\n",avail, frames);
                if (avail < 0)
                    return avail;
                if (avail < pcm->sw_p->avail_min) {
                    poll(pfd, nfds, TIMEOUT_INFINITE);
                    continue;
                }
                if (x.frames > avail)
                    frames = avail;
                if (debug) {
                    fprintf(stderr, "Aplay:avail = %d frames = %d\n",avail, frames);
                    fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
                }
                err = mmap_transfer(pcm, data , offset, frames);
                if (err == EPIPE) {
                    fprintf(stderr, "Aplay:Failed in mmap_transfer \n");
                    /* we failed to make our window -- try to restart */
                    pcm->underruns++;
                    pcm->running = 0;
                    continue;
                }
                x.frames -= frames;
                pcm->sync_ptr->c.control.appl_ptr += frames;
                pcm->sync_ptr->flags = 0;

                err = sync_ptr(pcm);
                if (err == EPIPE) {
                    fprintf(stderr, "Aplay:Failed in sync_ptr 2 \n");
                    /* we failed to make our window -- try to restart */
                    pcm->underruns++;
                    pcm->running = 0;
                    continue;
                }
                if (debug) {
                    fprintf(stderr, "Aplay:sync_ptr 2 \n");
                    fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
                }
                if (pcm->sync_ptr->c.control.appl_ptr >= pcm->sw_p->start_threshold) {
                    if(start)
                        goto xyz;
                    if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
                        err = -errno;
                        if (errno == EPIPE) {
                            fprintf(stderr, "Aplay:Failed in SNDRV_PCM_IOCTL_START\n");
                            /* we failed to make our window -- try to restart */
                            pcm->underruns++;
                            pcm->running = 0;
                            continue;
                        } else {
                            fprintf(stderr, "Aplay:Error no %d \n", errno);
                            return -errno;
                        }
                    } else
                        start = 1;
                }
xyz:
                offset += frames;
                break;
            }
        }
    } else {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);
        data = calloc(1, bufsize);
        if (!data) {
            fprintf(stderr, "Aplay:could not allocate %d bytes\n", count);
            pcm_close(pcm);
            return -ENOMEM;
        }

        while (read(fd, data, bufsize) == bufsize) {
            if (pcm_write(pcm, data, bufsize)){
                fprintf(stderr, "Aplay: pcm_write failed\n");
                break;
            }
        }
    }
    fprintf(stderr, "Aplay: Done playing\n");
    free(data);
    pcm_close(pcm);
    return 0;
}