// wave_write // // DESCRIPTION: // // Meant to be asynchronous, it supplies the wave sample to the lower // audio layer and returns. The sample is played later on. [[[WDW - // we purposely do not open the audio device as non-blocking because // managing that would be a pain. So, we rely a lot upon fifo.cpp and // event.cpp to not overload us, allowing us to get away with a // blocking write. event.cpp:polling_thread in particular appears to // use get_remaining_time to prevent flooding.]]] // // PARAMETERS: // // theHandler: the audio device file descriptor // theMono16BitsWaveBuffer: the audio data // theSize: the number of bytes (not 16-bit samples) // // GLOBALS USED/MODIFIED: // // total_samples_sent: modified based upon 16-bit samples sent // // RETURNS: // // the number of bytes (not 16-bit samples) sent // size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) { size_t num; if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) return 0; #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN // BIG-ENDIAN, swap the order of bytes in each sound sample int c; char *out_ptr; char *out_end; out_ptr = (char *)theMono16BitsWaveBuffer; out_end = out_ptr + theSize; while (out_ptr < out_end) { c = out_ptr[0]; out_ptr[0] = out_ptr[1]; out_ptr[1] = c; out_ptr += 2; } #endif num = write((int)theHandler, theMono16BitsWaveBuffer, theSize); // Keep track of the total number of samples sent -- we use this in // wave_get_read_position and also use it to help calculate the // total_samples_skipped in wave_close. // total_samples_sent += num / 2; return num; }
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) { ENTER("wave_write"); size_t bytes_to_write = theSize; char* aBuffer=theMono16BitsWaveBuffer; assert(stream); size_t aTotalFreeMem=0; pthread_mutex_lock(&pulse_mutex); while (1) { if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) { SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); theSize=0; goto terminate; } aTotalFreeMem = pulse_free(); if (aTotalFreeMem >= bytes_to_write) { SHOW("wave_write > aTotalFreeMem(%d) >= bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); break; } // TBD: check if really helpful if (aTotalFreeMem >= MAXLENGTH*2) { aTotalFreeMem = MAXLENGTH*2; } SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); // 500: threshold for avoiding too many calls to pulse_write if (aTotalFreeMem>500) { pulse_write(aBuffer, aTotalFreeMem); bytes_to_write -= aTotalFreeMem; aBuffer += aTotalFreeMem; } usleep(10000); } pulse_write(aBuffer, bytes_to_write); terminate: pthread_mutex_unlock(&pulse_mutex); SHOW("wave_write: theSize=%d", theSize); SHOW_TIME("wave_write > LEAVE"); return theSize; }
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) { size_t num; ENTER("wave_write"); if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) { SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); return 0; } #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN { // BIG-ENDIAN, swap the order of bytes in each sound sample int c; char *out_ptr; char *out_end; out_ptr = (char *)theMono16BitsWaveBuffer; out_end = out_ptr + theSize; while(out_ptr < out_end) { c = out_ptr[0]; out_ptr[0] = out_ptr[1]; out_ptr[1] = c; out_ptr += 2; } } #endif num = write((int) theHandler, theMono16BitsWaveBuffer, theSize); // Keep track of the total number of samples sent -- we use this in // wave_get_read_position and also use it to help calculate the // total_samples_skipped in wave_close. // total_samples_sent += num / 2; if (num < theSize) { SHOW("ERROR: wave_write only wrote %d of %d bytes\n", num, theSize); } else { SHOW("wave_write wrote %d bytes\n", theSize); } SHOW_TIME("wave_write > LEAVE"); return num; }
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) { ENTER("wave_write"); size_t bytes_written = 0; // space in ringbuffer for the sample needed: 1x mono channel but 2x for 1 stereo channel size_t bytes_to_write = (out_channels==1) ? theSize : theSize*2; my_stream_could_start = 0; if(pa_stream == NULL) { SHOW_TIME("wave_write > wave_open_sound\n"); if (0 != wave_open_sound()) { SHOW_TIME("wave_write > wave_open_sound fails!"); return 0; } my_stream_could_start=1; } else if (!wave_is_busy(NULL)) { my_stream_could_start = 1; } assert(BUFFER_LENGTH >= bytes_to_write); if (myWrite >= myBuffer + BUFFER_LENGTH) { myWrite = myBuffer; } // end if (myWrite >= myBuffer + BUFFER_LENGTH) size_t aTotalFreeMem=0; char* aRead = myRead; SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite); while (1) { if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) { SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); return 0; } aRead = myRead; // write pointer is before read pointer? if (myWrite >= aRead) { aTotalFreeMem = aRead + BUFFER_LENGTH - myWrite; } else // read pointer is before write pointer! { aTotalFreeMem = aRead - myWrite; } // end if (myWrite >= aRead) if (aTotalFreeMem>1) { // -1 because myWrite must be different of aRead // otherwise buffer would be considered as empty aTotalFreeMem -= 1; } // end if (aTotalFreeMem>1) if (aTotalFreeMem >= bytes_to_write) { break; } // end if (aTotalFreeMem >= bytes_to_write) //SHOW_TIME("wave_write > wait"); SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem); SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite); usleep(10000); } // end while (1) aRead = myRead; // write pointer is ahead the read pointer? if (myWrite >= aRead) { SHOW_TIME("wave_write > myWrite >= aRead"); // determine remaining free memory to the end of the ringbuffer size_t aFreeMem = myBuffer + BUFFER_LENGTH - myWrite; // is enough linear space available (regardless 1 or 2 channels)? if (aFreeMem >= bytes_to_write) { // copy direct - no wrap around at end of ringbuffer needed myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize); } else // not enough linear space available { // 2 channels (stereo)? if (out_channels == 2) { // copy with wrap around at the end of ringbuffer copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem/2); myWrite = myBuffer; myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem/2, theSize - aFreeMem/2); } else // 1 channel (mono) { // copy with wrap around at the end of ringbuffer copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem); myWrite = myBuffer; myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem); } // end if (out_channels == 2) } // end if (aFreeMem >= bytes_to_write) } // if (myWrite >= aRead) else // read pointer is ahead the write pointer { SHOW_TIME("wave_write > myWrite <= aRead"); myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize); } // end if (myWrite >= aRead) bytes_written = bytes_to_write; myWritePosition += theSize/sizeof(uint16_t); // add number of samples if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER)) { start_stream(); } // end if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER)) SHOW_TIME("wave_write > LEAVE"); return bytes_written; }