static const char * ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk, size_t *length_r) { GError *error = NULL; size_t length; const char *data = ao_chunk_data(ao, chunk, ao->replay_gain_filter, &ao->replay_gain_serial, &length); if (data == NULL) return NULL; if (length == 0) { /* empty chunk, nothing to do */ *length_r = 0; return data; } /* cross-fade */ if (chunk->other != NULL) { size_t other_length; const char *other_data = ao_chunk_data(ao, chunk->other, ao->other_replay_gain_filter, &ao->other_replay_gain_serial, &other_length); if (other_data == NULL) return NULL; if (other_length == 0) { *length_r = 0; return data; } /* if the "other" chunk is longer, then that trailer is used as-is, without mixing; it is part of the "next" song being faded in, and if there's a rest, it means cross-fading ends here */ if (length > other_length) length = other_length; char *dest = pcm_buffer_get(&ao->cross_fade_buffer, other_length); memcpy(dest, other_data, other_length); pcm_mix(dest, data, length, &ao->in_audio_format, 1.0 - chunk->mix_ratio); data = dest; length = other_length; } /* apply filter chain */ data = filter_filter(ao->filter, data, length, &length, &error); if (data == NULL) { g_warning("\"%s\" [%s] failed to filter: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); return NULL; } *length_r = length; return data; }
void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) { int pause = 0; int quit = 0; int bbp = buffered_before_play; int doCrossFade = 0; int crossFadeChunks = 0; int fadePosition; int nextChunk = -1; int test; int decodeWaitedOn = 0; char silence[CHUNK_SIZE] = { 0 }; int previousMetadataChunk = -1; MetadataChunk currentMetadataChunk; int currentChunkSent = 1; int end; int next = -1; // fprintf(stderr,"In decode.c decodeParent func :\r\n"); if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) return; pc->elapsedTime = 0; pc->state = PLAYER_STATE_PLAY; pc->play = 0; kill(getppid(),SIGUSR1); while(mpm_get_id(MPM_DECODE)>0 && cb->end-cb->begin<bbp && cb->end!=buffered_chunks-1 && dc->state!=DECODE_STATE_STOP) { processDecodeInput(); if(quit) return; playSilenceOrSleep(); } while(!quit) { processDecodeInput(); handleDecodeStart(); handleMetadata(cb, pc, &previousMetadataChunk, ¤tChunkSent, ¤tMetadataChunk); if(dc->state==DECODE_STATE_STOP && pc->queueState==PLAYER_QUEUE_FULL && pc->queueLockState==PLAYER_QUEUE_UNLOCKED) { next = cb->end; dc->start = 1; pc->queueState = PLAYER_QUEUE_DECODE; kill(getppid(),SIGUSR1); } if(next>=0 && doCrossFade==0 && !dc->start && dc->state!=DECODE_STATE_START) { nextChunk = -1; if(isCurrentAudioFormat(&(cb->audioFormat))) { doCrossFade = 1; crossFadeChunks = calculateCrossFadeChunks(pc, &(cb->audioFormat)); if(!crossFadeChunks || pc->crossFade>=dc->totalTime) { doCrossFade = -1; } } else doCrossFade = -1; } /* copy thse to locale variables to prevent any potential race conditions and weirdness */ end = cb->end; if(pause) my_usleep(10000); else if(cb->begin!=end && cb->begin!=next) { if(doCrossFade==1 && next>=0 && ((next>cb->begin && (fadePosition=next-cb->begin) <=crossFadeChunks) || (cb->begin>next && (fadePosition=next-cb->begin+ buffered_chunks)<=crossFadeChunks))) { if(nextChunk<0) { crossFadeChunks = fadePosition; } test = end; if(end < cb->begin) test+=buffered_chunks; nextChunk = cb->begin+crossFadeChunks; if(nextChunk<test) { if(nextChunk>=buffered_chunks) { nextChunk -= buffered_chunks; } pcm_mix(cb->chunks+cb->begin*CHUNK_SIZE, cb->chunks+nextChunk* CHUNK_SIZE, cb->chunkSize[ cb->begin], cb->chunkSize[ nextChunk], &(cb->audioFormat), ((float)fadePosition)/ crossFadeChunks); if(cb->chunkSize[nextChunk]> cb->chunkSize[cb->begin] ) { cb->chunkSize[cb->begin] = cb->chunkSize [nextChunk]; } } else { if(dc->state==DECODE_STATE_STOP) { doCrossFade = -1; } else continue; } } pc->elapsedTime = cb->times[cb->begin]; pc->bitRate = cb->bitRate[cb->begin]; pcm_volumeChange(cb->chunks+cb->begin* CHUNK_SIZE, cb->chunkSize[cb->begin], &(cb->audioFormat), pc->softwareVolume); if(playAudio(cb->chunks+cb->begin*CHUNK_SIZE, cb->chunkSize[cb->begin])<0) { quit = 1; } if( cb->begin+1 >= buffered_chunks ) { cb->begin = 0; } else cb->begin++; } else if(next==cb->begin) { if(doCrossFade==1 && nextChunk>=0) { nextChunk = cb->begin+crossFadeChunks; test = cb->end; if(end < cb->begin) test+=buffered_chunks; if(nextChunk<test) { if(nextChunk>=buffered_chunks) { nextChunk -= buffered_chunks; } advanceOutputBufferTo(cb, pc, &previousMetadataChunk, ¤tChunkSent, ¤tMetadataChunk, nextChunk); } } while(pc->queueState==PLAYER_QUEUE_DECODE || pc->queueLockState==PLAYER_QUEUE_LOCKED) { processDecodeInput(); if(quit) { quitDecode(pc,dc); return; } fprintf(stderr,"In decode.c decodeParent while loop with my_usleep\r\n"); // my_usleep(10000); } if(pc->queueState!=PLAYER_QUEUE_PLAY) { quit = 1; break; } else { next = -1; if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) { return; } nextChunk = -1; doCrossFade = 0; crossFadeChunks = 0; pc->queueState = PLAYER_QUEUE_EMPTY; kill(getppid(),SIGUSR1); } } else if(mpm_get_id(MPM_DECODE)<=0 || (dc->state==DECODE_STATE_STOP && !dc->start)) { quit = 1; break; } else { if(playAudio(silence, CHUNK_SIZE) < 0) quit = 1; } } quitDecode(pc,dc); }