opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams) { int coupled_size; int mono_size; if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); return align(sizeof(OpusMSEncoder)) + nb_coupled_streams * align(coupled_size) + (nb_streams-nb_coupled_streams) * align(mono_size); }
OpusEncoder *opus_encoder_create(int Fs, int channels) { char *raw_state = malloc(opus_encoder_get_size(channels)); if (raw_state == NULL) return NULL; return opus_encoder_init((OpusEncoder*)raw_state, Fs, channels); }
static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) { int s; char *ptr; int coupled_size, mono_size; coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); ptr = (char*)st + align(sizeof(OpusMSEncoder)); for (s=0;s<st->layout.nb_streams;s++) { if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); } /* void* cast avoids clang -Wcast-align warning */ return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32)); }
int opus_multistream_encoder_init( OpusMSEncoder *st, opus_int32 Fs, int channels, int streams, int coupled_streams, const unsigned char *mapping, int application ) { int coupled_size; int mono_size; int i; char *ptr; if ((channels>255) || (coupled_streams>streams) || (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) return OPUS_BAD_ARG; st->layout.nb_channels = channels; st->layout.nb_streams = streams; st->layout.nb_coupled_streams = coupled_streams; for (i=0;i<st->layout.nb_channels;i++) st->layout.mapping[i] = mapping[i]; if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout)) return OPUS_BAD_ARG; ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); for (i=0;i<st->layout.nb_coupled_streams;i++) { opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); ptr += align(coupled_size); } for (;i<st->layout.nb_streams;i++) { opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); ptr += align(mono_size); } return OPUS_OK; }
bool FVoiceEncoderOpus::Init(int32 InSampleRate, int32 InNumChannels) { UE_LOG(LogVoiceEncode, Display, TEXT("EncoderVersion: %s"), ANSI_TO_TCHAR(opus_get_version_string())); SampleRate = InSampleRate; NumChannels = InNumChannels; // 20ms frame sizes are a good choice for most applications (1000ms / 20ms = 50) FrameSize = SampleRate / NUM_OPUS_FRAMES_PER_SEC; //MaxFrameSize = FrameSize * MAX_OPUS_FRAMES; int32 EncError = 0; #if USE_UE4_MEM_ALLOC int32 EncSize = opus_encoder_get_size(NumChannels); Encoder = (OpusEncoder*)FMemory::Malloc(EncSize); EncError = opus_encoder_init(Encoder, SampleRate, NumChannels, OPUS_APPLICATION_VOIP); #else Encoder = opus_encoder_create(SampleRate, NumChannels, OPUS_APPLICATION_VOIP, &EncError); #endif if (EncError != OPUS_OK) { UE_LOG(LogVoiceEncode, Warning, TEXT("Failed to init Opus Encoder: %s"), ANSI_TO_TCHAR(opus_strerror(EncError))); Destroy(); } // Turn on variable bit rate encoding int32 UseVbr = 1; opus_encoder_ctl(Encoder, OPUS_SET_VBR(UseVbr)); // Turn off constrained VBR int32 UseCVbr = 0; opus_encoder_ctl(Encoder, OPUS_SET_VBR_CONSTRAINT(UseCVbr)); // Complexity (1-10) int32 Complexity = 1; opus_encoder_ctl(Encoder, OPUS_SET_COMPLEXITY(Complexity)); // Forward error correction int32 InbandFEC = 0; opus_encoder_ctl(Encoder, OPUS_SET_INBAND_FEC(InbandFEC)); #if DEBUG_OPUS DebugEncoderInfo(Encoder); #endif // DEBUG_OPUS return EncError == OPUS_OK; }
/* * Open codec. */ static pj_status_t codec_open( pjmedia_codec *codec, pjmedia_codec_param *attr ) { struct opus_data *opus_data = (struct opus_data *)codec->codec_data; int idx, err; PJ_ASSERT_RETURN(codec && attr && opus_data, PJ_EINVAL); pj_mutex_lock (opus_data->mutex); TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__)); opus_data->cfg.sample_rate = attr->info.clock_rate; opus_data->cfg.channel_cnt = attr->info.channel_cnt; opus_data->ptime = attr->info.frm_ptime; /* Allocate memory used by the codec */ if (!opus_data->enc) { /* Allocate memory for max 2 channels */ opus_data->enc = pj_pool_zalloc(opus_data->pool, opus_encoder_get_size(2)); } if (!opus_data->dec) { /* Allocate memory for max 2 channels */ opus_data->dec = pj_pool_zalloc(opus_data->pool, opus_decoder_get_size(2)); } if (!opus_data->enc_packer) { opus_data->enc_packer = pj_pool_zalloc(opus_data->pool, opus_repacketizer_get_size()); } if (!opus_data->dec_packer) { opus_data->dec_packer = pj_pool_zalloc(opus_data->pool, opus_repacketizer_get_size()); } if (!opus_data->enc || !opus_data->dec || !opus_data->enc_packer || !opus_data->dec_packer) { PJ_LOG(2, (THIS_FILE, "Unable to allocate memory for the codec")); pj_mutex_unlock (opus_data->mutex); return PJ_ENOMEM; } /* Check max average bit rate */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE); if (idx >= 0) { unsigned rate; rate = (unsigned)pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); if (rate < attr->info.avg_bps) attr->info.avg_bps = rate; } /* Check plc */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_INBAND_FEC, PJ_FALSE); if (idx >= 0) { unsigned plc; plc = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); attr->setting.plc = plc > 0? PJ_TRUE: PJ_FALSE; } /* Check vad */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_DTX, PJ_FALSE); if (idx >= 0) { unsigned vad; vad = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); attr->setting.vad = vad > 0? PJ_TRUE: PJ_FALSE; } /* Check cbr */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_CBR, PJ_FALSE); if (idx >= 0) { unsigned cbr; cbr = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); opus_data->cfg.cbr = cbr > 0? PJ_TRUE: PJ_FALSE; } /* Check max average bit rate */ idx = find_fmtp(&attr->setting.dec_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE); if (idx >= 0) { unsigned rate; rate = (unsigned) pj_strtoul(&attr->setting.dec_fmtp.param[idx].val); if (rate < attr->info.avg_bps) attr->info.avg_bps = rate; } TRACE_((THIS_FILE, "%s:%d: sample_rate: %u", __FUNCTION__, __LINE__, opus_data->cfg.sample_rate)); /* Initialize encoder */ err = opus_encoder_init(opus_data->enc, opus_data->cfg.sample_rate, attr->info.channel_cnt, OPUS_APPLICATION_VOIP); if (err != OPUS_OK) { PJ_LOG(2, (THIS_FILE, "Unable to create encoder")); return PJMEDIA_CODEC_EFAILED; } /* Set signal type */ opus_encoder_ctl(opus_data->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); /* Set bitrate */ opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps)); /* Set VAD */ opus_encoder_ctl(opus_data->enc, OPUS_SET_DTX(attr->setting.vad ? 1 : 0)); /* Set PLC */ opus_encoder_ctl(opus_data->enc, OPUS_SET_INBAND_FEC(attr->setting.plc ? 1 : 0)); /* Set bandwidth */ opus_encoder_ctl(opus_data->enc, OPUS_SET_MAX_BANDWIDTH(get_opus_bw_constant( opus_data->cfg.sample_rate))); /* Set expected packet loss */ opus_encoder_ctl(opus_data->enc, OPUS_SET_PACKET_LOSS_PERC(opus_data->cfg.packet_loss)); /* Set complexity */ opus_encoder_ctl(opus_data->enc, OPUS_SET_COMPLEXITY(opus_data->cfg.complexity)); /* Set constant bit rate */ opus_encoder_ctl(opus_data->enc, OPUS_SET_VBR(opus_data->cfg.cbr ? 0 : 1)); PJ_LOG(5, (THIS_FILE, "Initialize Opus encoder, sample rate: %d, " "avg bitrate: %d, vad: %d, plc: %d, pkt loss: %d, " "complexity: %d, constant bit rate: %d", opus_data->cfg.sample_rate, attr->info.avg_bps, attr->setting.vad?1:0, attr->setting.plc?1:0, opus_data->cfg.packet_loss, opus_data->cfg.complexity, opus_data->cfg.cbr?1:0)); /* Initialize decoder */ err = opus_decoder_init (opus_data->dec, opus_data->cfg.sample_rate, attr->info.channel_cnt); if (err != OPUS_OK) { PJ_LOG(2, (THIS_FILE, "Unable to initialize decoder")); return PJMEDIA_CODEC_EFAILED; } /* Initialize temporary decode frames used for FEC */ opus_data->dec_frame[0].type = PJMEDIA_FRAME_TYPE_NONE; opus_data->dec_frame[0].buf = pj_pool_zalloc(opus_data->pool, (opus_data->cfg.sample_rate / 1000) * 60 * attr->info.channel_cnt * 2 /* bytes per sample */); opus_data->dec_frame[1].type = PJMEDIA_FRAME_TYPE_NONE; opus_data->dec_frame[1].buf = pj_pool_zalloc(opus_data->pool, (opus_data->cfg.sample_rate / 1000) * 60 * attr->info.channel_cnt * 2 /* bytes per sample */); opus_data->dec_frame_index = -1; /* Initialize the repacketizers */ opus_repacketizer_init(opus_data->enc_packer); opus_repacketizer_init(opus_data->dec_packer); pj_mutex_unlock (opus_data->mutex); return PJ_SUCCESS; }
/* * Open codec. */ static pj_status_t opus_codec_open(pjmedia_codec *codec, pjmedia_codec_param *attr) { pj_status_t status; struct opus_private *opus; int id, ret = 0; unsigned i; int structSizeBytes; int tmpFmtpVal = 0; unsigned max_nsamples; const pj_str_t STR_FMTP_USE_INBAND_FEC = {"useinbandfec", 12}; const pj_str_t STR_FMTP_MAX_AVERAGE_BITRATE = {"maxaveragebitrate", 17}; const pj_str_t STR_FMTP_MAX_CODED_AUDIO_BANDWIDTH = {"maxplaybackrate", 15}; const pj_str_t STR_FMTP_USE_DTX = {"usedtx", 6}; opus = (struct opus_private *)codec->codec_data; pj_assert(opus != NULL); pj_assert(opus->enc_ready == PJ_FALSE && opus->dec_ready == PJ_FALSE); PJ_LOG(4, (THIS_FILE, "Clock rate is %d ", attr->info.clock_rate)); opus->externalFs = attr->info.clock_rate; /* Create Encoder */ structSizeBytes = opus_encoder_get_size(attr->info.channel_cnt); opus->psEnc = pj_pool_zalloc(opus->pool, structSizeBytes); ret = opus_encoder_init(opus->psEnc, opus->externalFs, attr->info.channel_cnt, OPUS_APPLICATION_VOIP); if (ret) { PJ_LOG(1, (THIS_FILE, "Unable to init encoder : %d", ret)); return PJ_EINVAL; } /* * Set Encoder parameters * TODO : have it configurable */ opus_encoder_ctl(opus->psEnc, OPUS_SET_COMPLEXITY(2)); opus_encoder_ctl(opus->psEnc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); /* Apply fmtp params to Encoder */ for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) { if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_USE_INBAND_FEC) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); opus_encoder_ctl(opus->psEnc, OPUS_SET_INBAND_FEC(tmpFmtpVal)); break; } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_MAX_AVERAGE_BITRATE) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); if (tmpFmtpVal >= 6000 && tmpFmtpVal <= 510000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_BITRATE(tmpFmtpVal)); } } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_MAX_CODED_AUDIO_BANDWIDTH) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); if (tmpFmtpVal <= 8000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else if (tmpFmtpVal <= 12000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); } else if (tmpFmtpVal <= 16000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); } else if (tmpFmtpVal <= 24000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); } else if (tmpFmtpVal <= 48000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_USE_DTX) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); opus_encoder_ctl(opus->psEnc, OPUS_SET_DTX(tmpFmtpVal)); } } opus->enc_ready = PJ_TRUE; /* Decoder buffer */ opus->pcm_bytes_per_sample = attr->info.pcm_bits_per_sample / 8; max_nsamples = 120 * OPUS_CLOCK_RATE / 1000; /* 120ms is max frame time */ opus->dec_buf_max_size = max_nsamples * opus->pcm_bytes_per_sample; opus->dec_buf = pj_pool_alloc(opus->pool, opus->dec_buf_max_size); /* Create decoder */ structSizeBytes = opus_decoder_get_size(attr->info.channel_cnt); opus->psDec = pj_pool_zalloc(opus->pool, structSizeBytes); ret = opus_decoder_init(opus->psDec, opus->externalFs, attr->info.channel_cnt); if (ret) { PJ_LOG(1, (THIS_FILE, "Unable to init decoder : %d", ret)); return PJ_EINVAL; } opus->dec_ready = PJ_TRUE; return PJ_SUCCESS; }
virtual bool Cook(FName Format, const TArray<uint8>& SrcBuffer, FSoundQualityInfo& QualityInfo, TArray<uint8>& CompressedDataStore) const override { check(Format == NAME_OPUS); // Get best compatible sample rate const uint16 kOpusSampleRate = GetBestOutputSampleRate(QualityInfo.SampleRate); // Frame size must be one of 2.5, 5, 10, 20, 40 or 60 ms const int32 kOpusFrameSizeMs = 60; // Calculate frame size required by Opus const int32 kOpusFrameSizeSamples = (kOpusSampleRate * kOpusFrameSizeMs) / 1000; const uint32 kSampleStride = SAMPLE_SIZE * QualityInfo.NumChannels; const int32 kBytesPerFrame = kOpusFrameSizeSamples * kSampleStride; // Check whether source has compatible sample rate TArray<uint8> SrcBufferCopy; if (QualityInfo.SampleRate != kOpusSampleRate) { if (!ResamplePCM(QualityInfo.NumChannels, SrcBuffer, QualityInfo.SampleRate, SrcBufferCopy, kOpusSampleRate)) { return false; } } else { // Take a copy of the source regardless SrcBufferCopy = SrcBuffer; } // Initialise the Opus encoder OpusEncoder* Encoder = NULL; int32 EncError = 0; #if USE_UE4_MEM_ALLOC int32 EncSize = opus_encoder_get_size(QualityInfo.NumChannels); Encoder = (OpusEncoder*)FMemory::Malloc(EncSize); EncError = opus_encoder_init(Encoder, kOpusSampleRate, QualityInfo.NumChannels, OPUS_APPLICATION_AUDIO); #else Encoder = opus_encoder_create(kOpusSampleRate, QualityInfo.NumChannels, OPUS_APPLICATION_AUDIO, &EncError); #endif if (EncError != OPUS_OK) { Destroy(Encoder); return false; } int32 BitRate = GetBitRateFromQuality(QualityInfo); opus_encoder_ctl(Encoder, OPUS_SET_BITRATE(BitRate)); // Create a buffer to store compressed data CompressedDataStore.Empty(); FMemoryWriter CompressedData(CompressedDataStore); int32 SrcBufferOffset = 0; // Calc frame and sample count int32 FramesToEncode = SrcBufferCopy.Num() / kBytesPerFrame; uint32 TrueSampleCount = SrcBufferCopy.Num() / kSampleStride; // Pad the end of data with zeroes if it isn't exactly the size of a frame. if (SrcBufferCopy.Num() % kBytesPerFrame != 0) { int32 FrameDiff = kBytesPerFrame - (SrcBufferCopy.Num() % kBytesPerFrame); SrcBufferCopy.AddZeroed(FrameDiff); FramesToEncode++; } check(QualityInfo.NumChannels <= MAX_uint8); check(FramesToEncode <= MAX_uint16); SerializeHeaderData(CompressedData, kOpusSampleRate, TrueSampleCount, QualityInfo.NumChannels, FramesToEncode); // Temporary storage with more than enough to store any compressed frame TArray<uint8> TempCompressedData; TempCompressedData.AddUninitialized(kBytesPerFrame); while (SrcBufferOffset < SrcBufferCopy.Num()) { int32 CompressedLength = opus_encode(Encoder, (const opus_int16*)(SrcBufferCopy.GetData() + SrcBufferOffset), kOpusFrameSizeSamples, TempCompressedData.GetData(), TempCompressedData.Num()); if (CompressedLength < 0) { const char* ErrorStr = opus_strerror(CompressedLength); UE_LOG(LogAudio, Warning, TEXT("Failed to encode: [%d] %s"), CompressedLength, ANSI_TO_TCHAR(ErrorStr)); Destroy(Encoder); CompressedDataStore.Empty(); return false; } else { // Store frame length and copy compressed data before incrementing pointers check(CompressedLength < MAX_uint16); SerialiseFrameData(CompressedData, TempCompressedData.GetData(), CompressedLength); SrcBufferOffset += kBytesPerFrame; } } Destroy(Encoder); return CompressedDataStore.Num() > 0; }
static int opus_multistream_encoder_init_impl( OpusMSEncoder *st, opus_int32 Fs, int channels, int streams, int coupled_streams, const unsigned char *mapping, int application, MappingType mapping_type ) { int coupled_size; int mono_size; int i, ret; char *ptr; if ((channels>255) || (channels<1) || (coupled_streams>streams) || (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) return OPUS_BAD_ARG; st->arch = opus_select_arch(); st->layout.nb_channels = channels; st->layout.nb_streams = streams; st->layout.nb_coupled_streams = coupled_streams; if (mapping_type != MAPPING_TYPE_SURROUND) st->lfe_stream = -1; st->bitrate_bps = OPUS_AUTO; st->application = application; st->variable_duration = OPUS_FRAMESIZE_ARG; for (i=0;i<st->layout.nb_channels;i++) st->layout.mapping[i] = mapping[i]; if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout)) return OPUS_BAD_ARG; ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); for (i=0;i<st->layout.nb_coupled_streams;i++) { ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); if(ret!=OPUS_OK)return ret; if (i==st->lfe_stream) opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); ptr += align(coupled_size); } for (;i<st->layout.nb_streams;i++) { ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); if (i==st->lfe_stream) opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); if(ret!=OPUS_OK)return ret; ptr += align(mono_size); } if (mapping_type == MAPPING_TYPE_SURROUND) { OPUS_CLEAR(ms_get_preemph_mem(st), channels); OPUS_CLEAR(ms_get_window_mem(st), channels*120); } st->mapping_type = mapping_type; return OPUS_OK; }
int main(int argc, char *argv[]) { struct hostent *server_host; char *server_host_str = "localhost"; char *certificate_file = NULL; char *key_file = NULL; char *password_file = NULL; char *token_file = NULL; char *username = "******"; int port = 64738; int ret; int development_mode = 0; int socket_fd; struct sockaddr_in server_addr; SSLRead socket_watcher; ev_io user_thread_watcher; ev_timer ping_watcher; ev_signal signal_watcher; ev_loop_main = EV_DEFAULT; /* * Lua initialization */ lua = luaL_newstate(); if (lua == NULL) { fprintf(stderr, "%s: could not initialize Lua\n", PIEPAN_NAME); return 1; } luaL_openlibs(lua); if (luaL_loadbuffer(lua, (const char *)src_piepan_impl_luac, src_piepan_impl_luac_len, "piepan_impl") != LUA_OK) { fprintf(stderr, "%s: could not load piepan implementation\n", PIEPAN_NAME); return 1; } lua_call(lua, 0, 0); lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "api"); lua_pushcfunction(lua, api_init); lua_setfield(lua, -2, "apiInit"); lua_settop(lua, 0); /* * Argument parsing */ { int opt; int i; int show_help = 0; int show_version = 0; lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "events"); lua_getfield(lua, -1, "onArgument"); opterr = 0; while ((opt = getopt(argc, argv, "u:c:k:s:t:p:-:dhv")) != -1) { switch (opt) { case 'u': username = optarg; break; case 'c': certificate_file = optarg; if (key_file == NULL) { key_file = certificate_file; } break; case 'k': key_file = optarg; break; case 's': { char *port_str; server_host_str = optarg; port_str = strrchr(server_host_str, ':'); if (port_str != NULL) { *port_str = '\0'; port = atoi(++port_str); } break; } case 't': token_file = optarg; break; case 'p': password_file = optarg; break; case '-': { char *key = optarg; char *value = strchr(key, '='); if (key == value) { break; } if (value != NULL) { *value++ = 0; } lua_pushvalue(lua, -1); lua_pushstring(lua, key); lua_pushstring(lua, value); lua_call(lua, 2, 0); break; } case 'd': development_mode = 1; break; case 'h': usage(stdout); return 0; case 'v': printf("%s %s (compiled on " __DATE__ " " __TIME__ ")\n", PIEPAN_NAME, PIEPAN_VERSION); return 0; default: fprintf(stderr, "%s: unknown or incomplete option '%c'\n", PIEPAN_NAME, optopt); return 1; } } lua_settop(lua, 0); } /* * Load user scripts */ { int i; lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "events"); lua_getfield(lua, -1, "onLoadScript"); for (i = optind; i < argc; i++) { lua_pushvalue(lua, -1); lua_pushstring(lua, argv[i]); if (development_mode) { lua_newuserdata(lua, sizeof(ScriptStat)); } else { lua_pushnil(lua); } lua_call(lua, 2, 3); if (lua_toboolean(lua, -3)) { if (development_mode) { ScriptStat *item = lua_touserdata(lua, -1); item->lua = lua; item->id = lua_tointeger(lua, -2); item->filename = argv[i]; ev_stat_init(&item->ev, script_stat_event, item->filename, 0); ev_stat_start(ev_loop_main, &item->ev); } } else { fprintf(stderr, "%s: %s\n", PIEPAN_NAME, lua_tostring(lua, -2)); } lua_pop(lua, 3); } lua_settop(lua, 0); } /* * Initialize Opus */ { OpusEncoder *encoder; int error; lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "opus"); encoder = lua_newuserdata(lua, opus_encoder_get_size(1)); lua_setfield(lua, -2, "encoder"); error = opus_encoder_init(encoder, 48000, 1, OPUS_APPLICATION_AUDIO); if (error != OPUS_OK) { fprintf(stderr, "%s: could not initialize the Opus encoder: %s\n", PIEPAN_NAME, opus_strerror(error)); return 1; } opus_encoder_ctl(encoder, OPUS_SET_VBR(0)); /* TODO: set this to the server's max bitrate */ opus_encoder_ctl(encoder, OPUS_SET_BITRATE(40000)); lua_settop(lua, 0); } /* * SSL initialization */ SSL_library_init(); ssl_context = SSL_CTX_new(SSLv23_client_method()); if (ssl_context == NULL) { fprintf(stderr, "%s: could not create SSL context\n", PIEPAN_NAME); return 1; } if (certificate_file != NULL) { if (!SSL_CTX_use_certificate_chain_file(ssl_context, certificate_file) || !SSL_CTX_use_PrivateKey_file(ssl_context, key_file, SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ssl_context)) { fprintf(stderr, "%s: could not load certificate and/or key file\n", PIEPAN_NAME); return 1; } } /* * Socket initialization and connection */ socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { fprintf(stderr, "%s: could not create socket\n", PIEPAN_NAME); return 1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_host = gethostbyname(server_host_str); if (server_host == NULL || server_host->h_addr_list[0] == NULL || server_host->h_addrtype != AF_INET) { fprintf(stderr, "%s: could not parse server address\n", PIEPAN_NAME); return 1; } memmove(&server_addr.sin_addr, server_host->h_addr_list[0], server_host->h_length); ret = connect(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); if (ret != 0) { fprintf(stderr, "%s: could not connect to server\n", PIEPAN_NAME); return 1; } ssl = SSL_new(ssl_context); if (ssl == NULL) { fprintf(stderr, "%s: could not create SSL object\n", PIEPAN_NAME); return 1; } if (SSL_set_fd(ssl, socket_fd) == 0) { fprintf(stderr, "%s: could not set SSL file descriptor\n", PIEPAN_NAME); return 1; } if (SSL_connect(ssl) != 1) { fprintf(stderr, "%s: could not create secure connection\n", PIEPAN_NAME); return 1; } /* * User thread pipe */ if (pipe(user_thread_pipe) != 0) { fprintf(stderr, "%s: could not create user thread pipe\n", PIEPAN_NAME); return 1; } /* * Trigger initial event */ lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "initialize"); lua_newtable(lua); lua_pushstring(lua, username); lua_setfield(lua, -2, "username"); if (password_file != NULL) { lua_pushstring(lua, password_file); lua_setfield(lua, -2, "passwordFile"); } if (token_file != NULL) { lua_pushstring(lua, token_file); lua_setfield(lua, -2, "tokenFile"); } lua_pushlightuserdata(lua, lua); lua_setfield(lua, -2, "state"); lua_call(lua, 1, 0); lua_settop(lua, 0); /* * Event loop */ ev_signal_init(&signal_watcher, signal_event, SIGINT); ev_signal_start(ev_loop_main, &signal_watcher); ev_io_init(&socket_watcher.ev, socket_read_event, socket_fd, EV_READ); socket_watcher.lua = lua; socket_watcher.ssl = ssl; ev_io_start(ev_loop_main, &socket_watcher.ev); ev_io_init(&user_thread_watcher, user_thread_event, user_thread_pipe[0], EV_READ); ev_io_start(ev_loop_main, &user_thread_watcher); ev_timer_init(&ping_watcher, ping_event, PING_TIMEOUT, PING_TIMEOUT); ev_timer_start(ev_loop_main, &ping_watcher); ev_run(ev_loop_main, 0); /* * Cleanup */ lua_getglobal(lua, "piepan"); lua_getfield(lua, -1, "internal"); lua_getfield(lua, -1, "events"); lua_getfield(lua, -1, "onDisconnect"); if (lua_isfunction(lua, -1)) { lua_newtable(lua); lua_call(lua, 1, 0); } SSL_shutdown(ssl); /* TODO: sigpipe is triggered here if connection breaks */ close(socket_fd); lua_close(lua); return 0; }
OpusEncoder *opus_encoder_init(OpusEncoder* st, int Fs, int channels, int application) { void *silk_enc; CELTEncoder *celt_enc; int err; int ret, silkEncSizeBytes; if (channels > 2 || channels<1) return NULL; if (application < OPUS_APPLICATION_VOIP || application > OPUS_APPLICATION_AUDIO) return NULL; if (Fs != 8000 && Fs != 12000 && Fs != 16000 && Fs != 24000 && Fs != 48000) return NULL; memset(st, 0, opus_encoder_get_size(channels)); /* Create SILK encoder */ ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); if( ret ) return NULL; silkEncSizeBytes = align(silkEncSizeBytes); st->silk_enc_offset = align(sizeof(OpusEncoder)); st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; silk_enc = (char*)st+st->silk_enc_offset; celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); st->stream_channels = st->channels = channels; st->Fs = Fs; ret = silk_InitEncoder( silk_enc, &st->silk_mode ); if( ret ) goto failure; /* default SILK parameters */ st->silk_mode.nChannelsAPI = channels; st->silk_mode.nChannelsInternal = channels; st->silk_mode.API_sampleRate = st->Fs; st->silk_mode.maxInternalSampleRate = 16000; st->silk_mode.minInternalSampleRate = 8000; st->silk_mode.desiredInternalSampleRate = 16000; st->silk_mode.payloadSize_ms = 20; st->silk_mode.bitRate = 25000; st->silk_mode.packetLossPercentage = 0; st->silk_mode.complexity = 10; st->silk_mode.useInBandFEC = 0; st->silk_mode.useDTX = 0; st->silk_mode.useCBR = 0; st->silk_mode.HP_cutoff_Hz = 0; st->hybrid_stereo_width_Q14 = 1 << 14; /* Create CELT encoder */ /* Initialize CELT encoder */ celt_encoder_init(celt_enc, Fs, channels, &err); if (err != CELT_OK) goto failure; celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); st->mode = MODE_HYBRID; st->bandwidth = OPUS_BANDWIDTH_FULLBAND; st->use_vbr = 0; st->user_bitrate_bps = OPUS_BITRATE_AUTO; st->bitrate_bps = 3000+Fs*channels; st->user_mode = application; st->signal_type = OPUS_SIGNAL_AUTO; st->user_bandwidth = OPUS_BANDWIDTH_AUTO; st->voice_ratio = 90; st->first = 1; st->encoder_buffer = st->Fs/100; st->delay_compensation = st->Fs/400; if (st->Fs > 16000) st->delay_compensation += 10; return st; failure: free(st); return NULL; }
int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) { va_list ap; int coupled_size, mono_size; char *ptr; int ret = OPUS_OK; va_start(ap, request); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); ptr = (char*)st + align(sizeof(OpusMSEncoder)); switch (request) { case OPUS_SET_BITRATE_REQUEST: { int chan, s; opus_int32 value = va_arg(ap, opus_int32); chan = st->layout.nb_streams + st->layout.nb_coupled_streams; value /= chan; for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); opus_encoder_ctl(enc, request, value * (s < st->layout.nb_coupled_streams ? 2 : 1)); } } break; case OPUS_GET_BITRATE_REQUEST: { int s; opus_int32 *value = va_arg(ap, opus_int32*); *value = 0; for (s=0;s<st->layout.nb_streams;s++) { opus_int32 rate; OpusEncoder *enc; enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); opus_encoder_ctl(enc, request, &rate); *value += rate; } } break; case OPUS_GET_VBR_REQUEST: case OPUS_GET_APPLICATION_REQUEST: case OPUS_GET_BANDWIDTH_REQUEST: case OPUS_GET_COMPLEXITY_REQUEST: case OPUS_GET_PACKET_LOSS_PERC_REQUEST: case OPUS_GET_DTX_REQUEST: case OPUS_GET_VOICE_RATIO_REQUEST: case OPUS_GET_VBR_CONSTRAINT_REQUEST: case OPUS_GET_SIGNAL_REQUEST: case OPUS_GET_LOOKAHEAD_REQUEST: case OPUS_GET_INBAND_FEC_REQUEST: { OpusEncoder *enc; /* For int32* GET params, just query the first stream */ opus_int32 *value = va_arg(ap, opus_int32*); enc = (OpusEncoder*)ptr; ret = opus_encoder_ctl(enc, request, value); } break; case OPUS_GET_FINAL_RANGE_REQUEST: { int s; opus_uint32 *value = va_arg(ap, opus_uint32*); opus_uint32 tmp; *value=0; for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); ret = opus_encoder_ctl(enc, request, &tmp); if (ret != OPUS_OK) break; *value ^= tmp; } } break; case OPUS_SET_COMPLEXITY_REQUEST: case OPUS_SET_VBR_REQUEST: case OPUS_SET_VBR_CONSTRAINT_REQUEST: case OPUS_SET_BANDWIDTH_REQUEST: case OPUS_SET_SIGNAL_REQUEST: case OPUS_SET_APPLICATION_REQUEST: case OPUS_SET_INBAND_FEC_REQUEST: case OPUS_SET_PACKET_LOSS_PERC_REQUEST: case OPUS_SET_DTX_REQUEST: case OPUS_SET_FORCE_MODE_REQUEST: { int s; /* This works for int32 params */ opus_int32 value = va_arg(ap, opus_int32); for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); ret = opus_encoder_ctl(enc, request, value); if (ret != OPUS_OK) break; } } break; case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: { int s; opus_int32 stream_id; OpusEncoder **value; stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) ret = OPUS_BAD_ARG; value = va_arg(ap, OpusEncoder**); for (s=0;s<stream_id;s++) { if (s < st->layout.nb_coupled_streams) ptr += align(coupled_size); else ptr += align(mono_size); } *value = (OpusEncoder*)ptr; } break; default: ret = OPUS_UNIMPLEMENTED; break; } va_end(ap); return ret; }
int opus_multistream_encode_float( #endif OpusMSEncoder *st, const opus_val16 *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes ) { int coupled_size; int mono_size; int s, i; char *ptr; int tot_size; VARDECL(opus_val16, buf); unsigned char tmp_data[MS_FRAME_TMP]; OpusRepacketizer rp; ALLOC_STACK; ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); if (max_data_bytes < 4*st->layout.nb_streams-1) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } /* Counting ToC */ tot_size = 0; for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; int len; int curr_max; opus_repacketizer_init(&rp); enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) { int left, right; left = get_left_channel(&st->layout, s, -1); right = get_right_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) { buf[2*i] = pcm[st->layout.nb_channels*i+left]; buf[2*i+1] = pcm[st->layout.nb_channels*i+right]; } ptr += align(coupled_size); } else { int chan = get_mono_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) buf[i] = pcm[st->layout.nb_channels*i+chan]; ptr += align(mono_size); } /* number of bytes left (+Toc) */ curr_max = max_data_bytes - tot_size; /* Reserve three bytes for the last stream and four for the others */ curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1); curr_max = IMIN(curr_max,MS_FRAME_TMP); len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max); if (len<0) { RESTORE_STACK; return len; } /* We need to use the repacketizer to add the self-delimiting lengths while taking into account the fact that the encoder can now return more than one frame at a time (e.g. 60 ms CELT-only) */ opus_repacketizer_cat(&rp, tmp_data, len); len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1); data += len; tot_size += len; } RESTORE_STACK; return tot_size; }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1size (JNIEnv *enc, jclass clazz, jint channels) { return opus_encoder_get_size(channels); }