Esempio n. 1
0
void BbMediaPlayerControl::continueLoadMedia()
{
    attach();
    updateMetaData();
    if (m_playAfterMediaLoaded)
        play();
}
Esempio n. 2
0
void EngineShoutcast::process(const CSAMPLE* pBuffer, const int iBufferSize) {
    //Check to see if Shoutcast is enabled, and pass the samples off to be broadcast if necessary.
    bool prefEnabled = (m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"enabled")).toInt() == 1);

    if (!prefEnabled) {
        if (isConnected()) {
            // We are conneced but shoutcast is disabled. Disconnect.
            serverDisconnect();
            infoDialog(tr("Mixxx has successfully disconnected from the shoutcast server"), "");
        }
        return;
    }

    // If we are here then the user wants to be connected (shoutcast is enabled
    // in the preferences).

    bool connected = isConnected();

    // If we aren't connected or the user has changed their preferences,
    // disconnect, update from prefs, and reconnect.
    if (!connected || m_pUpdateShoutcastFromPrefs->get() > 0.0f) {
        if (connected) {
            serverDisconnect();
        }

        // Initialize/update the encoder and libshout setup.
        updateFromPreferences();

        if (serverConnect()) {
            infoDialog(tr("Mixxx has successfully connected to the shoutcast server"), "");
        } else {
            errorDialog(tr("Mixxx could not connect to streaming server"),
                        tr("Please check your connection to the Internet and verify that your username and password are correct."));
        }
    }

    // If we aren't connected, bail.
    if (m_iShoutStatus != SHOUTERR_CONNECTED)
        return;

    // If we are connected, encode the samples.
    if (iBufferSize > 0 && m_encoder){
        m_encoder->encodeBuffer(pBuffer, iBufferSize);
    }

    // Check if track metadata has changed and if so, update.
    if (metaDataHasChanged()) {
        updateMetaData();
    }
}
Esempio n. 3
0
static boolean processEntry(struct sqlConnection *conn,
                            struct gbStatusTbl* statusTbl,
                            HGID faFileId, HGID pepFaId)
/* Parse and process the next ra entry, check to see if it is selected
 * for update. */
{
char* acc;
struct gbStatus* status;

if ((acc = gbMDParseEntry()) == NULL)
    return FALSE;

status = gbStatusTblFind(statusTbl, acc);
if ((status != NULL) && (status->selectProc != NULL) && (!status->metaDone)
    && (status->selectProc->modDate == raModDate))
    updateMetaData(conn, status, statusTbl, faFileId, pepFaId);
return TRUE;
}
Esempio n. 4
0
bool rspfImageMetaData::loadState(const rspfKeywordlist& kwl, const char* prefix)
{
   bool result = false; // return status
   
   // Clear the object:
   clear();

   std::string pfx = ( prefix ? prefix : "" );
   
   rspf_uint32 bands = getBandCount( kwl, pfx );
   if ( bands )
   {
      result = true;

      setNumberOfBands( bands );
      
      theMinValuesValidFlag  = true;
      theMaxValuesValidFlag  = true;
      theNullValuesValidFlag = true;

      updateMetaData( kwl, pfx ); // Initializes the rest of object.
   }
   else
   {
      if (traceDebug())
      {
         rspfNotify(rspfNotifyLevel_WARN)
            << " ERROR:\n"
            << "Required keyword not found:  " << rspfKeywordNames::NUMBER_BANDS_KW << std::endl;
      }
   }
   
   if (traceDebug())
   {
      print( rspfNotify(rspfNotifyLevel_DEBUG) );
   }

   return result;
}
Esempio n. 5
0
// Read the PNG file using the libpng.  The low-level interface is used here
// because we want to do various transformations (including setting the
// matte background if any, and applying gama) which can't be done with
// the high-level interface. The scanline also begins at the bottom of
// the image (per SecondLife conventions) instead of at the top, so we
// must assign row-pointers in "reverse" order.
BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop)
{
	try
	{
		// Create and initialize the png structures
		mReadPngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			this, &errorHandler, NULL);
		if (mReadPngPtr == NULL)
		{
			throw "Problem creating png read structure";
		}

		// Allocate/initialize the memory for image information.
		mReadInfoPtr = png_create_info_struct(mReadPngPtr);

		// Set up the input control
		PngDataInfo dataPtr;
		dataPtr.mData = src;
		dataPtr.mOffset = 0;

		png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback);
		png_set_sig_bytes(mReadPngPtr, 0);

		// setup low-level read and get header information
		png_read_info(mReadPngPtr, mReadInfoPtr);
		png_get_IHDR(mReadPngPtr, mReadInfoPtr, &mWidth, &mHeight,
			&mBitDepth, &mColorType, &mInterlaceType,
			&mCompressionType, &mFilterMethod);

		// Normalize the image, then get updated image information
		// after transformations have been applied
		normalizeImage();
		updateMetaData();

		// If a raw object is supplied, read the PNG image into its
		// data space
		if (rawImage != NULL)
		{
			rawImage->resize(static_cast<U16>(mWidth),
				static_cast<U16>(mHeight), mChannels);
			U8 *dest = rawImage->getData();
			int offset = mWidth * mChannels;

			// Set up the row pointers and read the image
			mRowPointers = new U8* [mHeight];
			for (U32 i=0; i < mHeight; i++)
			{
				mRowPointers[i] = &dest[(mHeight-i-1)*offset];
			}

			png_read_image(mReadPngPtr, mRowPointers);

			// Finish up, ensures all metadata are updated
			png_read_end(mReadPngPtr, NULL);
		}

		// If an info object is supplied, copy the relevant info
		if (infop != NULL)
		{
			infop->mHeight = static_cast<U16>(mHeight);
			infop->mWidth = static_cast<U16>(mWidth);
			infop->mComponents = mChannels;
		}

		mFinalSize = dataPtr.mOffset;
	}
	catch (png_const_charp msg)
	{
		mErrorMessage = msg;
		releaseResources();
		return (FALSE);
	}

	// Clean up and return
	releaseResources();
	return (TRUE);
}
static VideoFrame *extractVideoFrameWithCodecFlags(
        OMXClient *client,
        const sp<MetaData> &trackMeta,
        const sp<MediaSource> &source,
        uint32_t flags,
        int64_t frameTimeUs,
        int seekMode) {

#ifdef OMAP_ENHANCEMENT
    flags |= OMXCodec::kPreferThumbnailMode;
#ifdef TARGET_OMAP4

    int32_t isInterlaced = false;

    //Call config parser to update profile,level,interlaced,reference frame data
    updateMetaData(trackMeta);

    trackMeta->findInt32(kKeyVideoInterlaced, &isInterlaced);

    if(isInterlaced)
    {
      flags |= OMXCodec::kPreferInterlacedOutputContent;
    }
#endif
#endif
    sp<MediaSource> decoder =
        OMXCodec::Create(
                client->interface(), source->getFormat(), false, source,
                NULL, flags | OMXCodec::kClientNeedsFramebuffer);

    if (decoder.get() == NULL) {
        LOGV("unable to instantiate video decoder.");

        return NULL;
    }

    status_t err = decoder->start();
    if (err != OK) {
        LOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
        return NULL;
    }

    // Read one output buffer, ignore format change notifications
    // and spurious empty buffers.

    MediaSource::ReadOptions options;
    if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
        seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {

        LOGE("Unknown seek mode: %d", seekMode);
        return NULL;
    }

    MediaSource::ReadOptions::SeekMode mode =
            static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);

    int64_t thumbNailTime;
    if (frameTimeUs < 0 && trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
        options.setSeekTo(thumbNailTime, mode);
    } else {
        thumbNailTime = -1;
        options.setSeekTo(frameTimeUs < 0 ? 0 : frameTimeUs, mode);
    }

    MediaBuffer *buffer = NULL;
    do {
        if (buffer != NULL) {
            buffer->release();
            buffer = NULL;
        }

        err = decoder->read(&buffer, &options);
#ifdef OMAP_ENHANCEMENT
        if(err == INFO_FORMAT_CHANGED)
        {
            int32_t w1,h1;
            decoder->getFormat()->findInt32(kKeyWidth, &w1);
            decoder->getFormat()->findInt32(kKeyHeight, &h1);
            LOGD("Got portreconfig event. New WxH %dx%d. wait 5mS for port to be enabled",w1,h1);
            usleep(5000); //sleep 5mS for port disable-enable to complete
        }
#endif
        options.clearSeekTo();
    } while (err == INFO_FORMAT_CHANGED
             || (buffer != NULL && buffer->range_length() == 0));

    if (err != OK) {
        CHECK_EQ(buffer, NULL);

        LOGV("decoding frame failed.");
        decoder->stop();

        return NULL;
    }

    LOGV("successfully decoded video frame.");

    int32_t unreadable;
    if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
            && unreadable != 0) {
        LOGV("video frame is unreadable, decoder does not give us access "
             "to the video data.");

        buffer->release();
        buffer = NULL;

        decoder->stop();

        return NULL;
    }

    int64_t timeUs;
    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
    if (thumbNailTime >= 0) {
        if (timeUs != thumbNailTime) {
            const char *mime;
            CHECK(trackMeta->findCString(kKeyMIMEType, &mime));

            LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
                 thumbNailTime, timeUs, mime);
        }
    }

    sp<MetaData> meta = decoder->getFormat();

    int32_t width, height;
    CHECK(meta->findInt32(kKeyWidth, &width));
    CHECK(meta->findInt32(kKeyHeight, &height));

    int32_t rotationAngle;
    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
        rotationAngle = 0;  // By default, no rotation
    }

    VideoFrame *frame = new VideoFrame;

#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP4)
    int32_t srcFormat;
    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));

    int32_t format;
    const char *component;

    //cache the display width and height
    int32_t displayWidth, displayHeight;
    displayWidth = width;
    displayHeight = height;

    //update width & height with the buffer width&height
    if(!(meta->findInt32(kKeyPaddedWidth, &width))) {
        CHECK(meta->findInt32(kKeyWidth, &width));
    }
    if(!(meta->findInt32(kKeyPaddedHeight, &height))) {
        CHECK(meta->findInt32(kKeyHeight, &height));
    }
    LOGD("VideoFrame WxH %dx%d", displayWidth, displayHeight);

    if(((OMX_COLOR_FORMATTYPE)srcFormat == OMX_COLOR_FormatYUV420PackedSemiPlanar) ||
       ((OMX_COLOR_FORMATTYPE)srcFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar_Sequential_TopBottom)){
        frame->mWidth = displayWidth;
        frame->mHeight = displayHeight;
        frame->mDisplayWidth = displayWidth;
        frame->mDisplayHeight = displayHeight;
        frame->mSize = displayWidth * displayHeight * 2;
        frame->mData = new uint8_t[frame->mSize];
    frame->mRotationAngle = rotationAngle;
    }else {
        frame->mWidth = width;
        frame->mHeight = height;
        frame->mDisplayWidth = width;
        frame->mDisplayHeight = height;
        frame->mSize = width * height * 2;
        frame->mData = new uint8_t[frame->mSize];
    frame->mRotationAngle = rotationAngle;
    }

    if(((OMX_COLOR_FORMATTYPE)srcFormat == OMX_COLOR_FormatYUV420PackedSemiPlanar) ||
       ((OMX_COLOR_FORMATTYPE)srcFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar_Sequential_TopBottom)){

        ColorConverter converter(
                (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);

        CHECK(converter.isValid());

        converter.convert(
                width, height,
                (const uint8_t *)buffer->data() + buffer->range_offset(),
                0, //1D buffer in 1.16 Ducati rls. If 2D buffer -> 4096 stride should be used
                frame->mData, displayWidth * 2,
                displayWidth,displayHeight,buffer->range_offset(),isInterlaced);
    }
    else{

        ColorConverter converter(
                (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);

        CHECK(converter.isValid());

        converter.convert(
                width, height,
                (const uint8_t *)buffer->data() + buffer->range_offset(),
                0,
                frame->mData, width * 2);
    }

#else
    frame->mWidth = width;
    frame->mHeight = height;
    frame->mDisplayWidth = width;
    frame->mDisplayHeight = height;
    frame->mSize = width * height * 2;
    frame->mData = new uint8_t[frame->mSize];
    frame->mRotationAngle = rotationAngle;

    int32_t srcFormat;
    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));

    ColorConverter converter(
            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
    CHECK(converter.isValid());

    converter.convert(
            width, height,
            (const uint8_t *)buffer->data() + buffer->range_offset(),
            0,
            frame->mData, width * 2);
#endif

    buffer->release();
    buffer = NULL;

    decoder->stop();

    return frame;
}
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 == 4)
	flags |= PCM_QUAD;
    else if (channels == 6)
	flags |= PCM_5POINT1;
    else if (channels == 8)
	flags |= PCM_7POINT1;
    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;
    }

    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 SND_AUDIOCODEC_MP3:
               compr_params.codec.id = SND_AUDIOCODEC_MP3;
               break;
           case SND_AUDIOCODEC_AC3_PASS_THROUGH:
               compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
               printf("codec -d = %x\n", SND_AUDIOCODEC_AC3_PASS_THROUGH);
               break;
           case SND_AUDIOCODEC_AAC:
               compr_params.codec.id = SND_AUDIOCODEC_AAC;
               printf("codec -d = %x\n", SND_AUDIOCODEC_AAC);
               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;
       }
       outputMetadataLength = sizeof(struct output_metadata_handle_t);
    } else if (channels > 2) {
        if(set_channel_map) {
            send_channel_map_driver(pcm);
        }
    }
    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 = bufsize / (2*channels);
        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 = remainingData / (2*channels);
                 }
             }
             fprintf(stderr, "addr = %d, size = %d \n", (dst_addr + outputMetadataLength),(bufsize - outputMetadataLength));
             err = read(fd, (dst_addr + outputMetadataLength) , (bufsize - outputMetadataLength));
             if(compressed) {
                 updateMetaData(err);
                 memcpy(dst_addr, &outputMetadataTunnel, outputMetadataLength);
             }

             if (debug)
                 fprintf(stderr, "read %d bytes from file\n", err);
             if (err <= 0 ) {
                 fprintf(stderr," EOS set\n ");
                 eosSet = 1;
                 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);
                 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);
    }
             }
             /*
              * 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);

                if(compressed && eosSet) {
                    fprintf(stderr,"Audio Drain DONE ++\n");
                    if ( ioctl(pcm->fd, SNDRV_COMPRESS_DRAIN) < 0 ) {
                        fprintf(stderr,"Audio Drain failed\n");
                    }
                    fprintf(stderr,"Audio Drain DONE --\n");
                }
                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;
}