示例#1
0
uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap)
{
	uint64_t bitfield = 0;
	int x;

	for (x = 0; x < ast_format_cap_count(cap); x++) {
		struct ast_format *format = ast_format_cap_get_format(cap, x);

		bitfield |= ast_format_compatibility_format2bitfield(format);

		ao2_ref(format, -1);
	}

	return bitfield;
}
/*! \brief Add format/lang pairs to the array embedded in the sound object */
static int add_format_information_cb(void *obj, void *arg, int flags)
{
	char *language = obj;
	struct lang_format_info *args = arg;
	int idx;
	RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
	RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);

	if (!sounds_index) {
		return CMP_STOP;
	}

	cap = ast_media_get_format_cap(sounds_index, args->filename, language);
	if (!cap) {
		return CMP_STOP;
	}

	for (idx = 0; idx < ast_format_cap_count(cap); idx++) {
		struct ast_format *format = ast_format_cap_get_format(cap, idx);
		struct ast_json *lang_format_pair;

		if (!ast_strlen_zero(args->format_filter)
			&& strcmp(args->format_filter, ast_format_get_name(format))) {
			ao2_ref(format, -1);
			continue;
		}

		lang_format_pair = ast_json_pack("{s: s, s: s}",
			"language", language,
			"format", ast_format_get_name(format));
		if (!lang_format_pair) {
			ao2_ref(format, -1);
			return CMP_STOP;
		}

		ast_json_array_append(args->format_list, lang_format_pair);
		ao2_ref(format, -1);
	}

	return 0;
}
示例#3
0
int ooh323c_set_capability_for_call
   (ooCallData *call, struct ast_format_cap *cap, int dtmf, int dtmfcodec,
		 int t38support, int g729onlyA)
{
   int ret = 0, x, txframes;
   if (gH323Debug) {
     ast_verb(0, "\tAdding capabilities to call(%s, %s)\n", call->callType, 
                                                            call->callToken);
   }
   if(dtmf & H323_DTMF_CISCO || 1)
      ret |= ooCallEnableDTMFCISCO(call,dtmfcodec);
   if(dtmf & H323_DTMF_RFC2833 || 1)
      ret |= ooCallEnableDTMFRFC2833(call,dtmfcodec);
   if(dtmf & H323_DTMF_H245ALPHANUMERIC || 1)
      ret |= ooCallEnableDTMFH245Alphanumeric(call);
   if(dtmf & H323_DTMF_H245SIGNAL || 1)
      ret |= ooCallEnableDTMFH245Signal(call);

   if (t38support)
   	ooCapabilityAddT38Capability(call, OO_T38, OORXANDTX, 
					&ooh323c_start_receive_datachannel,
					&ooh323c_start_transmit_datachannel,
					&ooh323c_stop_receive_datachannel,
					&ooh323c_stop_transmit_datachannel,
					0);

   for(x=0; x<ast_format_cap_count(cap); x++)
   {
    struct ast_format *format = ast_format_cap_get_format(cap, x);
      if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g711 ulaw capability to call(%s, %s)\n", 
                                              call->callType, call->callToken);
	 }
	 txframes = ast_format_cap_get_format_framing(cap, format);
         ret= ooCallAddG711Capability(call, OO_G711ULAW64K, txframes, 
                                      txframes, OORXANDTX, 
                                      &ooh323c_start_receive_channel,
                                      &ooh323c_start_transmit_channel,
                                      &ooh323c_stop_receive_channel, 
                                      &ooh323c_stop_transmit_channel);
      }
      if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g711 alaw capability to call(%s, %s)\n",
                                            call->callType, call->callToken);
	 }
         txframes = ast_format_cap_get_format_framing(cap, format);
         ret= ooCallAddG711Capability(call, OO_G711ALAW64K, txframes, 
                                     txframes, OORXANDTX, 
                                     &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }

      if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g726 capability to call (%s, %s)\n",
                                           call->callType, call->callToken);
	 }
	 txframes = ast_format_cap_get_format_framing(cap, format);
         ret = ooCallAddG726Capability(call, OO_G726, txframes, grxframes, FALSE,
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g726aal2 capability to call (%s, %s)\n",
                                           call->callType, call->callToken);
	 }
	 txframes = ast_format_cap_get_format_framing(cap, format);
         ret = ooCallAddG726Capability(call, OO_G726AAL2, txframes, grxframes, FALSE,
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL)
      {
      
         txframes = (ast_format_cap_get_format_framing(cap, format))/10;
         if (gH323Debug) {
            ast_verb(0, "\tAdding g729A capability to call(%s, %s)\n",
                                            call->callType, call->callToken);
	 }
         ret= ooCallAddG729Capability(call, OO_G729A, txframes, txframes, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
	 if (g729onlyA)
		continue;
         if (gH323Debug) {
            ast_verb(0, "\tAdding g729 capability to call(%s, %s)\n",
                                            call->callType, call->callToken);
	 }
         ret|= ooCallAddG729Capability(call, OO_G729, txframes, txframes, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
         if (gH323Debug) {
            ast_verb(0, "\tAdding g729B capability to call(%s, %s)\n",
                                            call->callType, call->callToken);
	 }
         ret|= ooCallAddG729Capability(call, OO_G729B, txframes, txframes, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g7231 capability to call (%s, %s)\n",
                                           call->callType, call->callToken);
	 }
         ret = ooCallAddG7231Capability(call, OO_G7231, 1, 1, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding h263 capability to call (%s, %s)\n",
                                           call->callType, call->callToken);
	 }
         ret = ooCallAddH263VideoCapability(call, OO_H263VIDEO, 1, 0, 0, 0, 0, 320*1024, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding gsm capability to call(%s, %s)\n", 
                                             call->callType, call->callToken);
	 }
         ret = ooCallAddGSMCapability(call, OO_GSMFULLRATE, 4, FALSE, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }

      if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding Speex capability to call(%s, %s)\n", 
                                             call->callType, call->callToken);
	 }
         ret = ooCallAddSpeexCapability(call, OO_SPEEX, 4, 4, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }

      ao2_ref(format, -1);
   }
   return ret;
}
示例#4
0
int ooh323c_set_capability
   (struct ast_format_cap *cap, int dtmf, int dtmfcodec)
{
   int ret = 0, x;
   if (gH323Debug) {
     ast_verb(0, "\tAdding capabilities to H323 endpoint\n");
   }

   for(x=0; x<ast_format_cap_count(cap); x++)
   {
    struct ast_format *format = ast_format_cap_get_format(cap, x);
      if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g711 ulaw capability to H323 endpoint\n");
	 }
         ret= ooH323EpAddG711Capability(OO_G711ULAW64K, gtxframes, grxframes, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }
      if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g711 alaw capability to H323 endpoint\n");
	 }
         ret= ooH323EpAddG711Capability(OO_G711ALAW64K, gtxframes, grxframes, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }

      if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
	    ast_verb(0, "\tAdding g729A capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddG729Capability(OO_G729A, 2, 24, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

         if (gH323Debug) {
            ast_verb(0, "\tAdding g729 capability to H323 endpoint\n");
	 }
         ret |= ooH323EpAddG729Capability(OO_G729, 2, 24, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
         if (gH323Debug) {
            ast_verb(0, "\tAdding g729b capability to H323 endpoint\n");
	 }
         ret |= ooH323EpAddG729Capability(OO_G729B, 2, 24, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);
      }

      if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g7231 capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddG7231Capability(OO_G7231, 1, 1, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g726 capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddG726Capability(OO_G726, gtxframes, grxframes, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding g726aal2 capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddG726Capability(OO_G726AAL2, gtxframes, grxframes, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding h263 capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddH263VideoCapability(OO_H263VIDEO, 1, 0, 0, 0, 0, 320*1024, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding gsm capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddGSMCapability(OO_GSMFULLRATE, 4, FALSE, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

      if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL)
      {
         if (gH323Debug) {
            ast_verb(0, "\tAdding speex capability to H323 endpoint\n");
	 }
         ret = ooH323EpAddSpeexCapability(OO_SPEEX, 4, 4, FALSE, 
                                     OORXANDTX, &ooh323c_start_receive_channel,
                                     &ooh323c_start_transmit_channel,
                                     &ooh323c_stop_receive_channel, 
                                     &ooh323c_stop_transmit_channel);

      }

    ao2_ref(format, -1);      
   }
   
   if(dtmf & H323_DTMF_CISCO)
      ret |= ooH323EpEnableDTMFCISCO(0);
   if(dtmf & H323_DTMF_RFC2833)
      ret |= ooH323EpEnableDTMFRFC2833(0);
   else if(dtmf & H323_DTMF_H245ALPHANUMERIC)
      ret |= ooH323EpEnableDTMFH245Alphanumeric();
   else if(dtmf & H323_DTMF_H245SIGNAL)
      ret |= ooH323EpEnableDTMFH245Signal();

   return ret;
}
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
		    const struct pjmedia_sdp_media *stream)
{
	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup);
	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
	struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT;
	int fmts = 0;
	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
		ast_format_cap_count(session->direct_media_cap);

	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
		return -1;
	}

	/* get the endpoint capabilities */
	if (direct_media_enabled) {
		ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
		format_cap_only_type(caps, media_type);
	} else {
		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
	}

	/* get the capabilities on the peer */
	get_codecs(session, stream, &codecs);
	ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);

	/* get the joint capabilities between peer and endpoint */
	ast_format_cap_get_compatible(caps, peer, joint);
	if (!ast_format_cap_count(joint)) {
		struct ast_str *usbuf = ast_str_alloca(64);
		struct ast_str *thembuf = ast_str_alloca(64);

		ast_rtp_codecs_payloads_destroy(&codecs);
		ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
			session_media->stream_type,
			ast_format_cap_get_names(caps, &usbuf),
			ast_format_cap_get_names(peer, &thembuf));
		return -1;
	}

	ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
				     session_media->rtp);

	ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN);

	if (session->channel) {
		struct ast_format *fmt;

		ast_channel_lock(session->channel);
		ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_remove_by_type(caps, media_type);

		/*
		 * XXX Historically we picked the "best" joint format to use
		 * and stuck with it.  It would be nice to just append the
		 * determined joint media capabilities to give translation
		 * more formats to choose from when necessary.  Unfortunately,
		 * there are some areas of the system where this doesn't work
		 * very well. (The softmix bridge in particular is reluctant
		 * to pick higher fidelity formats and has a problem with
		 * asymmetric sample rates.)
		 */
		fmt = ast_format_cap_get_format(joint, 0);
		ast_format_cap_append(caps, fmt, 0);

		/*
		 * Apply the new formats to the channel, potentially changing
		 * raw read/write formats and translation path while doing so.
		 */
		ast_channel_nativeformats_set(session->channel, caps);
		ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
		ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
		ast_channel_unlock(session->channel);

		ao2_ref(fmt, -1);
	}

	ast_rtp_codecs_payloads_destroy(&codecs);
	return 0;
}
示例#6
0
文件: app_mp3.c 项目: KaloNK/asterisk
static int mp3_exec(struct ast_channel *chan, const char *data)
{
	int res=0;
	int fds[2];
	int ms = -1;
	int pid = -1;
	RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup);
	int timeout = 2000;
	struct timeval next;
	struct ast_frame *f;
	struct myframe {
		struct ast_frame f;
		char offset[AST_FRIENDLY_OFFSET];
		short frdata[160];
	} myf = {
		.f = { 0, },
	};
	struct ast_format * native_format;
	unsigned int sampling_rate;
	struct ast_format * write_format;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
		return -1;
	}

	if (pipe(fds)) {
		ast_log(LOG_WARNING, "Unable to create pipe\n");
		return -1;
	}
	
	ast_stopstream(chan);

	native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0);
	sampling_rate = ast_format_get_sample_rate(native_format);
	write_format = ast_format_cache_get_slin_by_rate(sampling_rate);

	owriteformat = ao2_bump(ast_channel_writeformat(chan));
	res = ast_set_write_format(chan, write_format);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		return -1;
	}

	myf.f.frametype = AST_FRAME_VOICE;
	myf.f.subclass.format = write_format;
	myf.f.mallocd = 0;
	myf.f.offset = AST_FRIENDLY_OFFSET;
	myf.f.src = __PRETTY_FUNCTION__;
	myf.f.delivery.tv_sec = 0;
	myf.f.delivery.tv_usec = 0;
	myf.f.data.ptr = myf.frdata;
	
	res = mp3play(data, sampling_rate, fds[1]);
	if (!strncasecmp(data, "http://", 7)) {
		timeout = 10000;
	}
	/* Wait 1000 ms first */
	next = ast_tvnow();
	next.tv_sec += 1;
	if (res >= 0) {
		pid = res;
		/* Order is important -- there's almost always going to be mp3...  we want to prioritize the
		   user */
		for (;;) {
			ms = ast_tvdiff_ms(next, ast_tvnow());
			if (ms <= 0) {
				res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
				if (res > 0) {
					myf.f.datalen = res;
					myf.f.samples = res / 2;
					if (ast_write(chan, &myf.f) < 0) {
						res = -1;
						break;
					}
				} else {
					ast_debug(1, "No more mp3\n");
					res = 0;
					break;
				}
				next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate));
			} else {
				ms = ast_waitfor(chan, ms);
				if (ms < 0) {
					ast_debug(1, "Hangup detected\n");
					res = -1;
					break;
				}
				if (ms) {
					f = ast_read(chan);
					if (!f) {
						ast_debug(1, "Null frame == hangup() detected\n");
						res = -1;
						break;
					}
					if (f->frametype == AST_FRAME_DTMF) {
						ast_debug(1, "User pressed a key\n");
						ast_frfree(f);
						res = 0;
						break;
					}
					ast_frfree(f);
				} 
			}
		}
	}
	close(fds[0]);
	close(fds[1]);
	
	if (pid > -1)
		kill(pid, SIGKILL);
	if (!res && owriteformat)
		ast_set_write_format(chan, owriteformat);

	ast_frfree(&myf.f);
	
	return res;
}
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
{
	struct ast_unreal_pvt *unreal;

	static const struct ast_jb_conf jb_conf = {
		.flags = 0,
		.max_size = -1,
		.resync_threshold = -1,
		.impl = "",
		.target_extra = -1,
	};

	unreal = ao2_alloc(size, destructor);
	if (!unreal) {
		return NULL;
	}

	unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
	if (!unreal->reqcap) {
		ao2_ref(unreal, -1);
		return NULL;
	}
	ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);

	memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));

	return unreal;
}

struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
	const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
	const struct ast_channel *requestor, struct ast_callid *callid)
{
	struct ast_channel *owner;
	struct ast_channel *chan;
	RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
	struct ast_assigned_ids id1 = {NULL, NULL};
	struct ast_assigned_ids id2 = {NULL, NULL};
	int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);

	/* set unique ids for the two channels */
	if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
		id1.uniqueid = assignedids->uniqueid;
		id2.uniqueid = assignedids->uniqueid2;
	}

	/* if id1 given but not id2, use default of id1;2 */
	if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
		char *uniqueid2;

		uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
		strcpy(uniqueid2, id1.uniqueid);/* Safe */
		strcat(uniqueid2, ";2");/* Safe */
		id2.uniqueid = uniqueid2;
	}

	/*
	 * Allocate two new Asterisk channels
	 *
	 * Make sure that the ;2 channel gets the same linkedid as ;1.
	 * You can't pass linkedid to both allocations since if linkedid
	 * isn't set, then each channel will generate its own linkedid.
	 */
	owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
		exten, context, &id1, requestor, 0,
		"%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
	if (!owner) {
		ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
		return NULL;
	}

	if (callid) {
		ast_channel_callid_set(owner, callid);
	}

	ast_channel_tech_set(owner, tech);
	ao2_ref(p, +1);
	ast_channel_tech_pvt_set(owner, p);

	ast_channel_nativeformats_set(owner, p->reqcap);

	/* Determine our read/write format and set it on each channel */
	fmt = ast_format_cap_get_format(p->reqcap, 0);
	if (!fmt) {
		ast_channel_tech_pvt_set(owner, NULL);
		ao2_ref(p, -1);
		ast_channel_unlock(owner);
		ast_channel_release(owner);
		return NULL;
	}

	ast_channel_set_writeformat(owner, fmt);
	ast_channel_set_rawwriteformat(owner, fmt);
	ast_channel_set_readformat(owner, fmt);
	ast_channel_set_rawreadformat(owner, fmt);

	ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);

	ast_jb_configure(owner, &p->jb_conf);

	if (ast_channel_cc_params_init(owner, requestor
		? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
		ast_channel_tech_pvt_set(owner, NULL);
		ao2_ref(p, -1);
		ast_channel_tech_pvt_set(owner, NULL);
		ast_channel_unlock(owner);
		ast_channel_release(owner);
		return NULL;
	}

	p->owner = owner;
	ast_channel_unlock(owner);

	chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
		exten, context, &id2, owner, 0,
		"%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
	if (!chan) {
		ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
		ast_channel_tech_pvt_set(owner, NULL);
		ao2_ref(p, -1);
		ast_channel_tech_pvt_set(owner, NULL);
		ast_channel_release(owner);
		return NULL;
	}

	if (callid) {
		ast_channel_callid_set(chan, callid);
	}

	ast_channel_tech_set(chan, tech);
	ao2_ref(p, +1);
	ast_channel_tech_pvt_set(chan, p);

	ast_channel_nativeformats_set(chan, p->reqcap);

	/* Format was already determined when setting up owner */
	ast_channel_set_writeformat(chan, fmt);
	ast_channel_set_rawwriteformat(chan, fmt);
	ast_channel_set_readformat(chan, fmt);
	ast_channel_set_rawreadformat(chan, fmt);

	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);

	p->chan = chan;
	ast_channel_unlock(chan);

	return owner;
}