private void connectVoice() {
		RtmpReader reader = null;
		RtmpWriter writer = null;
		if (audioFilename != null && audioFilename.length() > 0) {
			if (sendAudio) {
				try {
					reader = new FlvReader(audioFilename);
				} catch (Exception e) {
					e.printStackTrace();
					log.error("Can't create a FlvReader instance for " + audioFilename);
				}
			} else if (recordAudio) {
				try {
					writer = new LimitedSizeFlvWriter(audioFilename, audioSampleSize);
				} catch (Exception e) {
					e.printStackTrace();
					log.error("Can't create a FlvWriter instance for " + audioFilename);
				}
			}
		}

		voiceConnection = new BbbVoiceConnection(this, reader, writer) {
			private void reconnect() {
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// do nothing, just return
					return;
				}
				voiceConnection.start();
			}
			
			@Override
			public void channelDisconnected(ChannelHandlerContext ctx,
					ChannelStateEvent e) throws Exception {
				super.channelDisconnected(ctx, e);
				if (!disconnected_myself) {
					log.error("{} has dropped from the voice conference, reconnecting to {}", name, getJoinService().getApplicationService().getServerUrl());
					reconnect();
				}
			}
			
			@Override
			protected void onConnectedUnsuccessfully() {
				if (!disconnected_myself) {
					log.error("The voice connection of {} to {} was unsucceeded, trying one more time", name, getJoinService().getApplicationService().getServerUrl());
					reconnect();
				}
			}
		};
		voiceConnection.setListenOnly(listenOnly);
		voiceConnection.setLoop(true);
		voiceConnection.start();
	}