//The recording stuff runs in its own thread //this prevents dropouts in the recording, in case the //bandwidth is smaller than the selected streaming bitrate void* snd_rec_thread(void *data) { int rb_read_bytes; int ogg_header_written; int enc_bytes_read; char *enc_buf = (char*)malloc(rec_rb.size * sizeof(char)*10); char *audio_buf = (char*)malloc(rec_rb.size * sizeof(short)); ogg_header_written = 0; while(record) { pthread_cond_wait(&rec_cond, &rec_mut); rb_read_bytes = rb_read(&rec_rb, audio_buf); if(rb_read_bytes == 0) continue; #if HAVE_LIBLAME if(!strcmp(cfg.rec.codec, "mp3")) { enc_bytes_read = lame_enc_encode(&lame_rec, (short int*)audio_buf, enc_buf, rb_read_bytes/(2*cfg.rec.channel), rec_rb.size*10); bytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd); } #endif #if HAVE_LIBVORBIS if (!strcmp(cfg.rec.codec, "ogg")) { if(!ogg_header_written) { vorbis_enc_write_header(&vorbis_rec); ogg_header_written = 1; } enc_bytes_read = vorbis_enc_encode(&vorbis_rec, (short int*)audio_buf, enc_buf, rb_read_bytes/(2*cfg.rec.channel)); bytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd); } #endif if (!strcmp(cfg.rec.codec, "wav")) { //this permanently updates the filesize value in the WAV header //so we still have a valid WAV file in case of a crash wav_write_header(cfg.rec.fd, cfg.audio.channel, cfg.audio.samplerate, /*bps*/ 16); bytes_written += fwrite(audio_buf, sizeof(char), rb_read_bytes, cfg.rec.fd); } } fclose(cfg.rec.fd); free(enc_buf); free(audio_buf); return NULL; }
void *snd_stream_thread(void *data) { int sent; int rb_read_bytes; int encode_bytes_read; char *enc_buf = (char*)malloc(stream_rb.size * sizeof(char)*10); char *audio_buf = (char*)malloc(stream_rb.size * sizeof(short)); int (*xc_send)(char *buf, int buf_len) = NULL; encode_bytes_read = 0; if(cfg.srv[cfg.selected_srv]->type == SHOUTCAST) xc_send = &sc_send; if(cfg.srv[cfg.selected_srv]->type == ICECAST) xc_send = &ic_send; while(connected) { pthread_cond_wait(&stream_cond, &stream_mut); if(!connected) break; rb_read_bytes = rb_read(&stream_rb, audio_buf); if(rb_read_bytes == 0) continue; #if HAVE_LIBLAME if(!strcmp(cfg.audio.codec, "mp3")) encode_bytes_read = lame_enc_encode(&lame_stream, (short int*)audio_buf, enc_buf, rb_read_bytes/(2*cfg.audio.channel), stream_rb.size*10); #endif #if HAVE_LIBVORBIS if(!strcmp(cfg.audio.codec, "ogg")) encode_bytes_read = vorbis_enc_encode(&vorbis_stream, (short int*)audio_buf, enc_buf, rb_read_bytes/(2*cfg.audio.channel)); #endif if((sent = xc_send(enc_buf, encode_bytes_read)) == -1) connected = 0; else bytes_sent += encode_bytes_read; } free(enc_buf); free(audio_buf); return NULL; }
//The recording stuff runs in its own thread //this prevents dropouts in the recording in case the //bandwidth is smaller than the selected streaming bitrate void* snd_rec_thread(void *data) { int rb_bytes_read; int bytes_to_read; int ogg_header_written; int opus_header_written; int enc_bytes_read; char *enc_buf = (char*)malloc(rec_rb.size * sizeof(char)*10); char *audio_buf = (char*)malloc(rec_rb.size * sizeof(char)*10); ogg_header_written = 0; opus_header_written = 0; while(record) { pthread_cond_wait(&rec_cond, &rec_mut); if(next_file == 1) { if(!strcmp(cfg.rec.codec, "flac")) // The flac encoder closes the file flac_enc_close(&flac_rec); else fclose(cfg.rec.fd); cfg.rec.fd = next_fd; next_file = 0; if(!strcmp(cfg.rec.codec, "ogg")) { vorbis_enc_reinit(&vorbis_rec); ogg_header_written = 0; } if(!strcmp(cfg.rec.codec, "opus")) { opus_enc_reinit(&opus_rec); opus_header_written = 0; } if(!strcmp(cfg.rec.codec, "flac")) { flac_enc_reinit(&flac_rec); flac_enc_init_FILE(&flac_rec, cfg.rec.fd); } } // Opus needs a special treatment // The encoder needs a predefined count of frames // Therefore we don't feed the encoder with all data we have in the // ringbuffer at once if(!strcmp(cfg.rec.codec, "opus")) { bytes_to_read = 960 * sizeof(short)*cfg.audio.channel; while ((rb_filled(&rec_rb)) >= bytes_to_read) { rb_read_len(&rec_rb, audio_buf, bytes_to_read); if(!opus_header_written) { opus_enc_write_header(&opus_rec); opus_header_written = 1; } enc_bytes_read = opus_enc_encode(&opus_rec, (short*)audio_buf, enc_buf, bytes_to_read/(2*cfg.audio.channel)); kbytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd)/1024.0; } } else { if(rb_filled(&rec_rb) < framepacket_size*sizeof(short)) continue; rb_bytes_read = rb_read(&rec_rb, audio_buf); if(rb_bytes_read == 0) continue; if(!strcmp(cfg.rec.codec, "mp3")) { enc_bytes_read = lame_enc_encode(&lame_rec, (short*)audio_buf, enc_buf, rb_bytes_read/(2*cfg.audio.channel), rec_rb.size*10); kbytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd)/1024.0; } if(!strcmp(cfg.rec.codec, "ogg")) { if(!ogg_header_written) { vorbis_enc_write_header(&vorbis_rec); ogg_header_written = 1; } enc_bytes_read = vorbis_enc_encode(&vorbis_rec, (short*)audio_buf, enc_buf, rb_bytes_read/(2*cfg.audio.channel)); kbytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd)/1024.0; } if(!strcmp(cfg.rec.codec, "flac")) { flac_enc_encode(&flac_rec, (short*)audio_buf, rb_bytes_read/sizeof(short)/cfg.audio.channel, cfg.audio.channel); kbytes_written = flac_enc_get_bytes_written()/1024.0; } if(!strcmp(cfg.rec.codec, "wav")) { //this permanently updates the filesize value in the WAV header //so we still have a valid WAV file in case of a crash wav_write_header(cfg.rec.fd, cfg.audio.channel, cfg.audio.samplerate, 16); kbytes_written += fwrite(audio_buf, sizeof(char), rb_bytes_read, cfg.rec.fd)/1024.0; } if(!strcmp(cfg.rec.codec, "aac")) { enc_bytes_read = aac_enc_encode(&aac_rec, (short*) audio_buf, enc_buf, rb_bytes_read / (2*cfg.audio.channel), cfg.audio.channel); kbytes_written += fwrite(enc_buf, 1, enc_bytes_read, cfg.rec.fd) / 1024.0; } } } if(!strcmp(cfg.rec.codec, "flac")) // The flac encoder closes the file flac_enc_close(&flac_rec); else fclose(cfg.rec.fd); free(enc_buf); free(audio_buf); return NULL; }
void *snd_stream_thread(void *data) { int sent; int rb_bytes_read; int encode_bytes_read = 0; int bytes_to_read; char *enc_buf = (char*)malloc(stream_rb.size * sizeof(char)*10); char *audio_buf = (char*)malloc(stream_rb.size * sizeof(char)*10); int (*xc_send)(char *buf, int buf_len) = NULL; if(cfg.srv[cfg.selected_srv]->type == SHOUTCAST) xc_send = &sc_send; else //Icecast xc_send = &ic_send; while(connected) { pthread_cond_wait(&stream_cond, &stream_mut); if(!connected) break; if(!strcmp(cfg.audio.codec, "opus")) { // Read always chunks of 960 frames from the audio ringbuffer to be // compatible with OPUS bytes_to_read = 960 * sizeof(short)*cfg.audio.channel; while ((rb_filled(&stream_rb)) >= bytes_to_read) { // Read always chunks of 960 frames from the audio ringbuffer to be bytes_to_read = 960 * sizeof(short)*cfg.audio.channel; rb_read_len(&stream_rb, audio_buf, bytes_to_read); encode_bytes_read = opus_enc_encode(&opus_stream, (short*)audio_buf, enc_buf, bytes_to_read/(2*cfg.audio.channel)); if((sent = xc_send(enc_buf, encode_bytes_read)) == -1) { connected = 0; } else kbytes_sent += bytes_to_read/1024.0; } } else // ogg and mp3 need more data than opus in order to compress the audio data { if(rb_filled(&stream_rb) < framepacket_size*sizeof(short)) continue; rb_bytes_read = rb_read(&stream_rb, audio_buf); if(rb_bytes_read == 0) continue; if(!strcmp(cfg.audio.codec, "mp3")) encode_bytes_read = lame_enc_encode(&lame_stream, (short*)audio_buf, enc_buf, rb_bytes_read/(2*cfg.audio.channel), stream_rb.size*10); if(!strcmp(cfg.audio.codec, "ogg")) encode_bytes_read = vorbis_enc_encode(&vorbis_stream, (short*)audio_buf, enc_buf, rb_bytes_read/(2*cfg.audio.channel)); if(!strcmp(cfg.audio.codec, "aac")) { encode_bytes_read = aac_enc_encode(&aac_stream, (short*) audio_buf, enc_buf, rb_bytes_read/2/cfg.audio.channel, stream_rb.size*10); } if(encode_bytes_read != 0) { if((sent = xc_send(enc_buf, encode_bytes_read)) == -1) connected = 0; else kbytes_sent += encode_bytes_read/1024.0; } } } free(enc_buf); free(audio_buf); return NULL; }