static int icecast_internal_connect(t_channel *c, t_channel_outputstream *os, t_icecast *icecast, char *error, int errsize) { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; (void)c; (void)os; if (icecast->connected) return MSERV_SUCCESS; if (shout_open(icecast->shout) != SHOUTERR_SUCCESS) { snprintf(error, errsize, "icecast: failed opening connection: %s", shout_get_error(icecast->shout)); goto failed; } mserv_log("Successfully connected to Icecast server '%s:%d'" " for mount '%s'", shout_get_host(icecast->shout), shout_get_port(icecast->shout), shout_get_mount(icecast->shout)); icecast->connected = 1; vorbis_info_init(&icecast->vi); if (vorbis_encode_init(&icecast->vi, os->channels, os->samplerate, -1, icecast->bitrate, -1) != 0) { snprintf(error, errsize, "icecast: failed to initialise vorbis engine"); goto failed; } vorbis_comment_init(&icecast->vc); vorbis_comment_add_tag(&icecast->vc, "ENCODER", "mserv " VERSION); vorbis_analysis_init(&icecast->vd, &icecast->vi); vorbis_block_init(&icecast->vd, &icecast->vb); ogg_stream_init(&icecast->os, rand()); vorbis_analysis_headerout(&icecast->vd, &icecast->vc, &header, &header_comm, &header_code); ogg_stream_packetin(&icecast->os, &header); ogg_stream_packetin(&icecast->os, &header_comm); ogg_stream_packetin(&icecast->os, &header_code); for (;;) { if (ogg_stream_flush(&icecast->os, &icecast->og) == 0) break; if (shout_send(icecast->shout, icecast->og.header, icecast->og.header_len) != SHOUTERR_SUCCESS || shout_send(icecast->shout, icecast->og.body, icecast->og.body_len) != SHOUTERR_SUCCESS) { snprintf(error, errsize, "icecast: failed to send starter to " "shout: %s", shout_get_error(icecast->shout)); vorbis_block_clear(&icecast->vb); vorbis_dsp_clear(&icecast->vd); vorbis_info_clear(&icecast->vi); goto failed; } } return MSERV_SUCCESS; failed: if (icecast->connected) shout_close(icecast->shout); icecast->connected = 0; return MSERV_FAILURE; }
/* The main loop for each instance. Gets data passed to it from the stream * manager (which gets it from the input module), and streams it to the * specified server */ void *ices_instance_stream(void *arg) { int ret, shouterr; ref_buffer *buffer; char *connip; stream_description *sdsc = arg; instance_t *stream = sdsc->stream; input_module_t *inmod = sdsc->input; int reencoding = (inmod->type == ICES_INPUT_VORBIS) && stream->encode; int encoding = (inmod->type == ICES_INPUT_PCM) && stream->encode; char *stream_name = NULL, *stream_genre = NULL, *stream_description = NULL; char *user = NULL; vorbis_comment_init(&sdsc->vc); sdsc->shout = shout_new(); /* we only support the ice protocol and vorbis streams currently */ shout_set_format(sdsc->shout, SHOUT_FORMAT_VORBIS); //shout_set_protocol(sdsc->shout, SHOUT_PROTOCOL_ICE); shout_set_protocol(sdsc->shout, SHOUT_PROTOCOL_HTTP); signal(SIGPIPE, signal_hup_handler); connip = malloc(16); if(!resolver_getip(stream->hostname, connip, 16)) { LOG_ERROR1("Could not resolve hostname \"%s\"", stream->hostname); free(connip); stream->died = 1; return NULL; } if (!(shout_set_host(sdsc->shout, connip)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } shout_set_port(sdsc->shout, stream->port); if (!(shout_set_password(sdsc->shout, stream->password)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if (stream->user) user = stream->user; else user = "******"; if(shout_set_user(sdsc->shout, user) != SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if (!(shout_set_agent(sdsc->shout, VERSIONSTRING)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if (!(shout_set_mount(sdsc->shout, stream->mount)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } /* set the metadata for the stream */ if(stream->stream_name) stream_name = stream->stream_name; else if (ices_config->stream_name) stream_name = ices_config->stream_name; if(stream->stream_description) stream_description = stream->stream_description; else if (ices_config->stream_description) stream_description = ices_config->stream_description; if(stream->stream_genre) stream_genre = stream->stream_genre; else if (ices_config->stream_genre) stream_genre = ices_config->stream_genre; if(stream_name) if (!(shout_set_name(sdsc->shout, stream_name)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if (stream_genre) if (!(shout_set_genre(sdsc->shout, stream_genre)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if (stream_description) if (!(shout_set_description(sdsc->shout, stream_description)) == SHOUTERR_SUCCESS) { LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout)); free(connip); stream->died = 1; return NULL; } if(stream->downmix && encoding && stream->channels == 1) { stream->channels = 1; sdsc->downmix = downmix_initialise(); } if(stream->resampleinrate && stream->resampleoutrate && encoding) { stream->samplerate = stream->resampleoutrate; sdsc->resamp = resample_initialise(stream->channels, stream->resampleinrate, stream->resampleoutrate); } if(encoding) { if(inmod->metadata_update) inmod->metadata_update(inmod->internal, &sdsc->vc); sdsc->enc = encode_initialise(stream->channels, stream->samplerate, stream->managed, stream->min_br, stream->nom_br, stream->max_br, stream->quality, stream->serial++, &sdsc->vc); if(!sdsc->enc) { LOG_ERROR0("Failed to configure encoder"); stream->died = 1; return NULL; /* FIXME: probably leaking some memory here */ } } else if(reencoding) sdsc->reenc = reencode_init(stream); if(stream->savefilename != NULL) { stream->savefile = fopen(stream->savefilename, "wb"); if(!stream->savefile) LOG_ERROR2("Failed to open stream save file %s: %s", stream->savefilename, strerror(errno)); else LOG_INFO1("Saving stream to file %s", stream->savefilename); } if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS) { LOG_INFO3("Connected to server: %s:%d%s", shout_get_host(sdsc->shout), shout_get_port(sdsc->shout), shout_get_mount(sdsc->shout)); while(1) { if(stream->buffer_failures > MAX_ERRORS) { LOG_WARN0("Too many errors, shutting down"); break; } buffer = stream_wait_for_data(stream); /* buffer being NULL means that either a fatal error occured, * or we've been told to shut down */ if(!buffer) break; /* If data is NULL or length is 0, we should just skip this one. * Probably, we've been signalled to shut down, and that'll be * caught next iteration. Add to the error count just in case, * so that we eventually break out anyway */ if(!buffer->buf || !buffer->len) { LOG_WARN0("Bad buffer dequeued!"); stream->buffer_failures++; continue; } if(stream->wait_for_critical) { LOG_INFO0("Trying restart on new substream"); stream->wait_for_critical = 0; } ret = process_and_send_buffer(sdsc, buffer); /* No data produced, do nothing */ if(ret == -1) ; /* Fatal error */ else if(ret == -2) { LOG_ERROR0("Serious error, waiting to restart on " "next substream. Stream temporarily suspended."); /* Set to wait until a critical buffer comes through (start of * a new substream, typically), and flush existing queue. */ thread_mutex_lock(&ices_config->flush_lock); stream->wait_for_critical = 1; input_flush_queue(stream->queue, 0); thread_mutex_unlock(&ices_config->flush_lock); } /* Non-fatal shout error */ else if(ret == 0) { LOG_ERROR2("Send error: %s (%s)", shout_get_error(sdsc->shout), strerror(errno)); if(shout_get_errno(sdsc->shout) == SHOUTERR_SOCKET) { int i=0; /* While we're trying to reconnect, don't receive data * to this instance, or we'll overflow once reconnect * succeeds */ thread_mutex_lock(&ices_config->flush_lock); stream->skip = 1; /* Also, flush the current queue */ input_flush_queue(stream->queue, 1); thread_mutex_unlock(&ices_config->flush_lock); while((i < stream->reconnect_attempts || stream->reconnect_attempts==-1) && !ices_config->shutdown) { i++; LOG_WARN0("Trying reconnect after server socket error"); shout_close(sdsc->shout); if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS) { LOG_INFO3("Connected to server: %s:%d%s", shout_get_host(sdsc->shout), shout_get_port(sdsc->shout), shout_get_mount(sdsc->shout)); /* This stream can't restart until the next * logical stream comes along, since the * server won't have any cached headers for * this source/connection. So, don't continue * yet. */ thread_mutex_lock(&ices_config->flush_lock); stream->wait_for_critical = 1; input_flush_queue(stream->queue, 0); thread_mutex_unlock(&ices_config->flush_lock); break; } else { LOG_ERROR3("Failed to reconnect to %s:%d (%s)", shout_get_host(sdsc->shout),shout_get_port(sdsc->shout), shout_get_error(sdsc->shout)); if(i==stream->reconnect_attempts) { LOG_ERROR0("Reconnect failed too many times, " "giving up."); /* We want to die now */ stream->buffer_failures = MAX_ERRORS+1; } else /* Don't try again too soon */ sleep(stream->reconnect_delay); } } stream->skip = 0; } stream->buffer_failures++; } stream_release_buffer(buffer); } } else { LOG_ERROR3("Failed initial connect to %s:%d (%s)", shout_get_host(sdsc->shout),shout_get_port(sdsc->shout), shout_get_error(sdsc->shout)); } shout_close(sdsc->shout); if(stream->savefile != NULL) fclose(stream->savefile); shout_free(sdsc->shout); encode_clear(sdsc->enc); reencode_clear(sdsc->reenc); downmix_clear(sdsc->downmix); resample_clear(sdsc->resamp); vorbis_comment_clear(&sdsc->vc); stream->died = 1; return NULL; }
void QEncoder::stream() { if (!m_streaming) { m_streaming = true; m_enc=new OggTheoraEncoder(); m_enc->video_quality = m_Vquality->text().toInt(); m_enc->video_bitrate = m_Vbitrate->text().toInt(); if (m_Qfreej->IsAudioOn()) { m_Qjack = m_Qfreej->getQjack(); if (m_enc->audio = m_Qjack->getAudio()) { m_enc->use_audio = true; (m_Qjack->getJack())->isEncoded(false); m_enc->audio_quality = m_Aquality->text().toInt(); // m_enc->audio_bitrate = m_Abitrate->text().toInt(); } } else m_enc->audio = NULL; if (m_dumpButton->isChecked()) { m_enc->set_filedump(m_FileName->text().toAscii()); } if (m_IceButton->isChecked()) { if(shout_set_host(m_enc->ice, m_Host->text().toAscii())) qDebug() << "shout_set_host: " << shout_get_error(m_enc->ice); if(shout_set_port(m_enc->ice, m_Port->text().toInt())) qDebug() << "shout_set_port: " << shout_get_error(m_enc->ice); if(shout_set_name(m_enc->ice, m_ShoutName->text().toAscii())) qDebug() << "shout_set_title: " << shout_get_error(m_enc->ice); if(shout_set_user(m_enc->ice, m_User->text().toAscii())) qDebug() << "shout_set_user: "******"shout_set_pass: "******"shout_set_mount: " << shout_get_error(m_enc->ice); if(shout_open(m_enc->ice) == SHOUTERR_SUCCESS) { qDebug() << "streaming on url: http://" << shout_get_host(m_enc->ice) << ":" \ << shout_get_port(m_enc->ice) << shout_get_mount(m_enc->ice); m_enc->write_to_stream = true; } else { qDebug() << "error connecting to server " << shout_get_host(m_enc->ice) << ":" \ << shout_get_error(m_enc->ice); m_enc->write_to_stream = false; } } m_freej->add_encoder(m_enc); //also calls the OggTheoraEncoder::init method if (m_enc->audio) { m_enc->audio->Jack->isEncoded(true); //starts to fill the audio encoder ring buffer QString val; val.setNum(m_enc->getAvBitRate(), 10); m_Abitrate->setText(val); } m_enc->active = true; m_streamButton->setText("Close to STOP"); pollerRate->start(2000); } else { m_streaming = false; m_enc->stop(); m_enc->active = false; deleteLater(); } }