Beispiel #1
0
	AACFileWriter::AACFileWriter( const char* filename, int samplerate, int channel )
	{
		m_samplerate = samplerate;
		m_channel = channel;
		m_aacfile = fopen( filename, "wb" );
		if(!m_aacfile)
		{
			return;
		}
		CHANNEL_MODE channle_mode = channel == 1 ? MODE_1 : MODE_2;
		AACENC_ERROR ErrorStatus;
		if(( ErrorStatus = aacEncOpen( &m_hAacEncoder, 0, 2 ) ) != AACENC_OK)
		{
			return;
		}
		ErrorStatus = aacEncoder_SetParam( m_hAacEncoder, AACENC_AOT, AOT_SBR );
		ErrorStatus = aacEncoder_SetParam( m_hAacEncoder, AACENC_BITRATE, 8 * 3500 );
		ErrorStatus = aacEncoder_SetParam( m_hAacEncoder, AACENC_SAMPLERATE, samplerate );
		ErrorStatus = aacEncoder_SetParam( m_hAacEncoder, AACENC_CHANNELMODE, channle_mode );
		ErrorStatus = aacEncEncode( m_hAacEncoder, NULL, NULL, NULL, NULL );
		AACENC_InfoStruct encInfo;
		ErrorStatus = aacEncInfo( m_hAacEncoder, &encInfo );
		m_framesize = encInfo.frameLength*channel;
		m_pInputbuf = new char[m_framesize * 2];
		m_outofbyte = new char[encInfo.maxOutBufBytes];

		m_in_eisize = 2;
		m_in_bufsize = m_framesize * sizeof( int16_t );
		m_in_buf_id = IN_AUDIO_DATA;

		m_encinBuf.bufElSizes = &m_in_eisize;
		m_encinBuf.bufferIdentifiers = &m_in_buf_id;
		m_encinBuf.bufSizes = &m_in_bufsize;
		m_encinBuf.numBufs = 1;

		m_out_eisize = 2;
		m_out_bufsize = encInfo.maxOutBufBytes;
		m_out_buf_id = OUT_BITSTREAM_DATA;
		m_encoutBuf.bufElSizes = &m_out_eisize;
		m_encoutBuf.bufferIdentifiers = &m_out_buf_id;
		m_encoutBuf.bufSizes = &m_out_bufsize;
		m_encoutBuf.numBufs = 1;
		m_encoutBuf.bufs = (void **)&m_outofbyte;


		m_in_args.numAncBytes = 0;

		m_bInit = true;
	}
Beispiel #2
0
int AacEncoderInit(AacEncoderContext *_pAacCtx)
{
        FdkaacConfig *pFdkaac;
        CHANNEL_MODE mode;
  
        pFdkaac = (FdkaacConfig *)_pAacCtx;
        if (aacEncOpen(&pFdkaac->pEncoder, 1, pFdkaac->channelMode) != AACENC_OK) {
                pFdkaac->pEncoder = NULL;
                Debug("err");
                return -1;
        }
        if((aacEncoder_SetParam(pFdkaac->pEncoder, AACENC_AOT, pFdkaac->objectType)) !=  AACENC_OK){
                Debug("error");
                return -1;
        }
        int nRet =  aacEncoder_SetParam(pFdkaac->pEncoder, AACENC_SAMPLERATE, pFdkaac->nSampleRate);
        if( nRet != AACENC_OK){
                Debug("error, nRet = %d", nRet);
                return -1;
        }
        if(aacEncoder_SetParam(pFdkaac->pEncoder, AACENC_CHANNELMODE, pFdkaac->channelMode) != AACENC_OK) {
                Debug("error");
                return -1;
        }
        if(aacEncoder_SetParam(pFdkaac->pEncoder, AACENC_TRANSMUX, pFdkaac->transportType) != AACENC_OK) {
                Debug("error");
                return -1;
        }
        // TODO add bitrate control
/*
        if (aacEncoder_SetParam(pFdkaac->pEncoder, AACENC_BITRATE, pFdkaac->nBitrate) != AACENC_OK) {
                return false;
        }
*/
        if (aacEncEncode(pFdkaac->pEncoder, NULL, NULL, NULL, NULL) != AACENC_OK) {
                Debug("error");
                return -1;
        }
        if (aacEncInfo(pFdkaac->pEncoder, &pFdkaac->info) != AACENC_OK) {
                Debug("error");
                return -1;
        }
        // calculate input size
        pFdkaac->nInputSize = pFdkaac->nChannels * pFdkaac->info.frameLength * pFdkaac->nSampleSize;
        pFdkaac->pConvertBuf = (uint8_t*)malloc(pFdkaac->nInputSize);

        return 0;
}
Beispiel #3
0
void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
    if (mSignalledError) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    if (!mSentCodecSpecificData) {
        // The very first thing we want to output is the codec specific
        // data. It does not require any input data but we will need an
        // output buffer to store it in.

        if (outQueue.empty()) {
            return;
        }

        if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
            ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        OMX_U32 actualBitRate  = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE);
        if (mBitRate != actualBitRate) {
            ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate);
        }

        AACENC_InfoStruct encInfo;
        if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
            ALOGE("Failed to get AAC encoder info");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

        if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) {
            ALOGE("b/34617444");
            android_errorWriteLog(0x534e4554,"34617444");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        outHeader->nFilledLen = encInfo.confSize;
        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;

        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
        memcpy(out, encInfo.confBuf, encInfo.confSize);

        outQueue.erase(outQueue.begin());
        outInfo->mOwnedByUs = false;
        notifyFillBufferDone(outHeader);

        mSentCodecSpecificData = true;
    }

    size_t numBytesPerInputFrame =
        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);

    // Limit input size so we only get one ELD frame
    if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) {
        numBytesPerInputFrame = 512;
    }

    for (;;) {
        // We do the following until we run out of buffers.

        while (mInputSize < numBytesPerInputFrame) {
            // As long as there's still input data to be read we
            // will drain "kNumSamplesPerFrame * mNumChannels" samples
            // into the "mInputFrame" buffer and then encode those
            // as a unit into an output buffer.

            if (mSawInputEOS || inQueue.empty()) {
                return;
            }

            BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

            const void *inData = inHeader->pBuffer + inHeader->nOffset;

            size_t copy = numBytesPerInputFrame - mInputSize;
            if (copy > inHeader->nFilledLen) {
                copy = inHeader->nFilledLen;
            }

            if (mInputFrame == NULL) {
                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
                mAllocatedFrameSize = numBytesPerInputFrame;
            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
                ALOGE("b/34621073: changed size from %d to %d",
                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
                android_errorWriteLog(0x534e4554,"34621073");
                delete mInputFrame;
                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
                mAllocatedFrameSize = numBytesPerInputFrame;

            }

            if (mInputSize == 0) {
                mInputTimeUs = inHeader->nTimeStamp;
            }

            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
            mInputSize += copy;

            inHeader->nOffset += copy;
            inHeader->nFilledLen -= copy;

            // "Time" on the input buffer has in effect advanced by the
            // number of audio frames we just advanced nOffset by.
            inHeader->nTimeStamp +=
                (copy * 1000000ll / mSampleRate)
                    / (mNumChannels * sizeof(int16_t));

            if (inHeader->nFilledLen == 0) {
                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                    mSawInputEOS = true;

                    // Pad any remaining data with zeroes.
                    memset((uint8_t *)mInputFrame + mInputSize,
                           0,
                           numBytesPerInputFrame - mInputSize);

                    mInputSize = numBytesPerInputFrame;
                }

                inQueue.erase(inQueue.begin());
                inInfo->mOwnedByUs = false;
                notifyEmptyBufferDone(inHeader);

                inData = NULL;
                inHeader = NULL;
                inInfo = NULL;
            }
        }

        // At this  point we have all the input data necessary to encode
        // a single frame, all we need is an output buffer to store the result
        // in.

        if (outQueue.empty()) {
            return;
        }

        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;

        AACENC_InArgs inargs;
        AACENC_OutArgs outargs;
        memset(&inargs, 0, sizeof(inargs));
        memset(&outargs, 0, sizeof(outargs));
        inargs.numInSamples = numBytesPerInputFrame / sizeof(int16_t);

        void* inBuffer[]        = { (unsigned char *)mInputFrame };
        INT   inBufferIds[]     = { IN_AUDIO_DATA };
        INT   inBufferSize[]    = { (INT)numBytesPerInputFrame };
        INT   inBufferElSize[]  = { sizeof(int16_t) };

        AACENC_BufDesc inBufDesc;
        inBufDesc.numBufs           = sizeof(inBuffer) / sizeof(void*);
        inBufDesc.bufs              = (void**)&inBuffer;
        inBufDesc.bufferIdentifiers = inBufferIds;
        inBufDesc.bufSizes          = inBufferSize;
        inBufDesc.bufElSizes        = inBufferElSize;

        void* outBuffer[]       = { outPtr };
        INT   outBufferIds[]    = { OUT_BITSTREAM_DATA };
        INT   outBufferSize[]   = { 0 };
        INT   outBufferElSize[] = { sizeof(UCHAR) };

        AACENC_BufDesc outBufDesc;
        outBufDesc.numBufs           = sizeof(outBuffer) / sizeof(void*);
        outBufDesc.bufs              = (void**)&outBuffer;
        outBufDesc.bufferIdentifiers = outBufferIds;
        outBufDesc.bufSizes          = outBufferSize;
        outBufDesc.bufElSizes        = outBufferElSize;

        // Encode the mInputFrame, which is treated as a modulo buffer
        AACENC_ERROR encoderErr = AACENC_OK;
        size_t nOutputBytes = 0;

        do {
            memset(&outargs, 0, sizeof(outargs));

            outBuffer[0] = outPtr;
            outBufferSize[0] = outAvailable - nOutputBytes;

            encoderErr = aacEncEncode(mAACEncoder,
                                      &inBufDesc,
                                      &outBufDesc,
                                      &inargs,
                                      &outargs);

            if (encoderErr == AACENC_OK) {
                outPtr += outargs.numOutBytes;
                nOutputBytes += outargs.numOutBytes;

                if (outargs.numInSamples > 0) {
                    int numRemainingSamples = inargs.numInSamples - outargs.numInSamples;
                    if (numRemainingSamples > 0) {
                        memmove(mInputFrame,
                                &mInputFrame[outargs.numInSamples],
                                sizeof(int16_t) * numRemainingSamples);
                    }
                    inargs.numInSamples -= outargs.numInSamples;
                }
            }
        } while (encoderErr == AACENC_OK && inargs.numInSamples > 0);

        outHeader->nFilledLen = nOutputBytes;

        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;

        if (mSawInputEOS) {
            // We also tag this output buffer with EOS if it corresponds
            // to the final input buffer.
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        }

        outHeader->nTimeStamp = mInputTimeUs;

#if 0
        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
              nOutputBytes, mInputTimeUs, outHeader->nFlags);

        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
#endif

        outQueue.erase(outQueue.begin());
        outInfo->mOwnedByUs = false;
        notifyFillBufferDone(outHeader);

        outHeader = NULL;
        outInfo = NULL;

        mInputSize = 0;
    }
}
Beispiel #4
0
int main(int argc, char *argv[]) {
	int bitrate = 64000;
	int ch;
	const char *infile, *outfile;
	FILE *out;
	void *wav;
	int format, sample_rate, channels, bits_per_sample;
	int input_size;
	uint8_t* input_buf;
	int16_t* convert_buf;
	int aot = 2;
	int afterburner = 1;
	int eld_sbr = 0;
	int vbr = 0;
	HANDLE_AACENCODER handle;
	CHANNEL_MODE mode;
	AACENC_InfoStruct info = { 0 };
	while ((ch = getopt(argc, argv, "r:t:a:s:v:")) != -1) {
		switch (ch) {
		case 'r':
			bitrate = atoi(optarg);
			break;
		case 't':
			aot = atoi(optarg);
			break;
		case 'a':
			afterburner = atoi(optarg);
			break;
		case 's':
			eld_sbr = atoi(optarg);
			break;
		case 'v':
			vbr = atoi(optarg);
			break;
		case '?':
		default:
			usage(argv[0]);
			return 1;
		}
	}
	if (argc - optind < 2) {
		usage(argv[0]);
		return 1;
	}
	infile = argv[optind];
	outfile = argv[optind + 1];

	wav = wav_read_open(infile);
	if (!wav) {
		fprintf(stderr, "Unable to open wav file %s\n", infile);
		return 1;
	}
	if (!wav_get_header(wav, &format, &channels, &sample_rate, &bits_per_sample, NULL)) {
		fprintf(stderr, "Bad wav file %s\n", infile);
		return 1;
	}
	if (format != 1) {
		fprintf(stderr, "Unsupported WAV format %d\n", format);
		return 1;
	}
	if (bits_per_sample != 16) {
		fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample);
		return 1;
	}
	switch (channels) {
	case 1: mode = MODE_1;       break;
	case 2: mode = MODE_2;       break;
	case 3: mode = MODE_1_2;     break;
	case 4: mode = MODE_1_2_1;   break;
	case 5: mode = MODE_1_2_2;   break;
	case 6: mode = MODE_1_2_2_1; break;
	default:
		fprintf(stderr, "Unsupported WAV channels %d\n", channels);
		return 1;
	}
	if (aacEncOpen(&handle, 0, channels) != AACENC_OK) {
		fprintf(stderr, "Unable to open encoder\n");
		return 1;
	}
	if (aacEncoder_SetParam(handle, AACENC_AOT, aot) != AACENC_OK) {
		fprintf(stderr, "Unable to set the AOT\n");
		return 1;
	}
	if (aot == 39 && eld_sbr) {
		if (aacEncoder_SetParam(handle, AACENC_SBR_MODE, 1) != AACENC_OK) {
			fprintf(stderr, "Unable to set SBR mode for ELD\n");
			return 1;
		}
	}
	if (aacEncoder_SetParam(handle, AACENC_SAMPLERATE, sample_rate) != AACENC_OK) {
		fprintf(stderr, "Unable to set the AOT\n");
		return 1;
	}
	if (aacEncoder_SetParam(handle, AACENC_CHANNELMODE, mode) != AACENC_OK) {
		fprintf(stderr, "Unable to set the channel mode\n");
		return 1;
	}
	if (aacEncoder_SetParam(handle, AACENC_CHANNELORDER, 1) != AACENC_OK) {
		fprintf(stderr, "Unable to set the wav channel order\n");
		return 1;
	}
	if (vbr) {
		if (aacEncoder_SetParam(handle, AACENC_BITRATEMODE, vbr) != AACENC_OK) {
			fprintf(stderr, "Unable to set the VBR bitrate mode\n");
			return 1;
		}
	} else {
		if (aacEncoder_SetParam(handle, AACENC_BITRATE, bitrate) != AACENC_OK) {
			fprintf(stderr, "Unable to set the bitrate\n");
			return 1;
		}
	}
	if (aacEncoder_SetParam(handle, AACENC_TRANSMUX, 2) != AACENC_OK) {
		fprintf(stderr, "Unable to set the ADTS transmux\n");
		return 1;
	}
	if (aacEncoder_SetParam(handle, AACENC_AFTERBURNER, afterburner) != AACENC_OK) {
		fprintf(stderr, "Unable to set the afterburner mode\n");
		return 1;
	}
	if (aacEncEncode(handle, NULL, NULL, NULL, NULL) != AACENC_OK) {
		fprintf(stderr, "Unable to initialize the encoder\n");
		return 1;
	}
	if (aacEncInfo(handle, &info) != AACENC_OK) {
		fprintf(stderr, "Unable to get the encoder info\n");
		return 1;
	}

	out = fopen(outfile, "wb");
	if (!out) {
		perror(outfile);
		return 1;
	}

	input_size = channels*2*info.frameLength;
	input_buf = (uint8_t*) malloc(input_size);
	convert_buf = (int16_t*) malloc(input_size);

	while (1) {
		AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 };
		AACENC_InArgs in_args = { 0 };
		AACENC_OutArgs out_args = { 0 };
		int in_identifier = IN_AUDIO_DATA;
		int in_size, in_elem_size;
		int out_identifier = OUT_BITSTREAM_DATA;
		int out_size, out_elem_size;
		int read, i;
		void *in_ptr, *out_ptr;
		uint8_t outbuf[20480];
		AACENC_ERROR err;

		read = wav_read_data(wav, input_buf, input_size);
		for (i = 0; i < read/2; i++) {
			const uint8_t* in = &input_buf[2*i];
			convert_buf[i] = in[0] | (in[1] << 8);
		}
		if (read <= 0) {
			in_args.numInSamples = -1;
		} else {
			in_ptr = convert_buf;
			in_size = read;
			in_elem_size = 2;

			in_args.numInSamples = read/2;
			in_buf.numBufs = 1;
			in_buf.bufs = &in_ptr;
			in_buf.bufferIdentifiers = &in_identifier;
			in_buf.bufSizes = &in_size;
			in_buf.bufElSizes = &in_elem_size;
		}
		out_ptr = outbuf;
		out_size = sizeof(outbuf);
		out_elem_size = 1;
		out_buf.numBufs = 1;
		out_buf.bufs = &out_ptr;
		out_buf.bufferIdentifiers = &out_identifier;
		out_buf.bufSizes = &out_size;
		out_buf.bufElSizes = &out_elem_size;

		if ((err = aacEncEncode(handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) {
			if (err == AACENC_ENCODE_EOF)
				break;
			fprintf(stderr, "Encoding failed\n");
			return 1;
		}
		if (out_args.numOutBytes == 0)
			continue;
		fwrite(outbuf, 1, out_args.numOutBytes, out);
	}
	free(input_buf);
	free(convert_buf);
	fclose(out);
	wav_read_close(wav);
	aacEncClose(&handle);

	return 0;
}
Beispiel #5
0
void *io_thread_a2dp_source_aac(void *arg) {
	struct ba_transport *t = (struct ba_transport *)arg;
	const a2dp_aac_t *cconfig = (a2dp_aac_t *)t->a2dp.cconfig;

	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_push(CANCEL_ROUTINE(io_thread_release), t);

	HANDLE_AACENCODER handle;
	AACENC_InfoStruct aacinf;
	AACENC_ERROR err;

	/* create AAC encoder without the Meta Data module */
	const unsigned int channels = transport_get_channels(t);
	if ((err = aacEncOpen(&handle, 0x07, channels)) != AACENC_OK) {
		error("Couldn't open AAC encoder: %s", aacenc_strerror(err));
		goto fail_open;
	}

	pthread_cleanup_push(CANCEL_ROUTINE(aacEncClose), &handle);

	unsigned int aot = AOT_NONE;
	unsigned int bitrate = AAC_GET_BITRATE(*cconfig);
	unsigned int samplerate = transport_get_sampling(t);
	unsigned int channelmode = channels == 1 ? MODE_1 : MODE_2;

	switch (cconfig->object_type) {
	case AAC_OBJECT_TYPE_MPEG2_AAC_LC:
#if AACENCODER_LIB_VERSION <= 0x03040C00 /* 3.4.12 */
		aot = AOT_MP2_AAC_LC;
		break;
#endif
	case AAC_OBJECT_TYPE_MPEG4_AAC_LC:
		aot = AOT_AAC_LC;
		break;
	case AAC_OBJECT_TYPE_MPEG4_AAC_LTP:
		aot = AOT_AAC_LTP;
		break;
	case AAC_OBJECT_TYPE_MPEG4_AAC_SCA:
		aot = AOT_AAC_SCAL;
		break;
	}

	if ((err = aacEncoder_SetParam(handle, AACENC_AOT, aot)) != AACENC_OK) {
		error("Couldn't set audio object type: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_BITRATE, bitrate)) != AACENC_OK) {
		error("Couldn't set bitrate: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_SAMPLERATE, samplerate)) != AACENC_OK) {
		error("Couldn't set sampling rate: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_CHANNELMODE, channelmode)) != AACENC_OK) {
		error("Couldn't set channel mode: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if (cconfig->vbr) {
		if ((err = aacEncoder_SetParam(handle, AACENC_BITRATEMODE, config.aac_vbr_mode)) != AACENC_OK) {
			error("Couldn't set VBR bitrate mode %u: %s", config.aac_vbr_mode, aacenc_strerror(err));
			goto fail_init;
		}
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_AFTERBURNER, config.aac_afterburner)) != AACENC_OK) {
		error("Couldn't enable afterburner: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_MP4_LATM_MCP1)) != AACENC_OK) {
		error("Couldn't enable LATM transport type: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncoder_SetParam(handle, AACENC_HEADER_PERIOD, 1)) != AACENC_OK) {
		error("Couldn't set LATM header period: %s", aacenc_strerror(err));
		goto fail_init;
	}

	if ((err = aacEncEncode(handle, NULL, NULL, NULL, NULL)) != AACENC_OK) {
		error("Couldn't initialize AAC encoder: %s", aacenc_strerror(err));
		goto fail_init;
	}
	if ((err = aacEncInfo(handle, &aacinf)) != AACENC_OK) {
		error("Couldn't get encoder info: %s", aacenc_strerror(err));
		goto fail_init;
	}

	int in_buffer_identifier = IN_AUDIO_DATA;
	int out_buffer_identifier = OUT_BITSTREAM_DATA;
	int in_buffer_element_size = sizeof(int16_t);
	int out_buffer_element_size = 1;
	int16_t *in_buffer, *in_buffer_head;
	uint8_t *out_buffer, *out_payload;
	int in_buffer_size;
	int out_payload_size;

	AACENC_BufDesc in_buf = {
		.numBufs = 1,
		.bufs = (void **)&in_buffer_head,
		.bufferIdentifiers = &in_buffer_identifier,
		.bufSizes = &in_buffer_size,
		.bufElSizes = &in_buffer_element_size,
	};
	AACENC_BufDesc out_buf = {
		.numBufs = 1,
		.bufs = (void **)&out_payload,
		.bufferIdentifiers = &out_buffer_identifier,
		.bufSizes = &out_payload_size,
		.bufElSizes = &out_buffer_element_size,
	};
	AACENC_InArgs in_args = { 0 };
	AACENC_OutArgs out_args = { 0 };

	in_buffer_size = in_buffer_element_size * aacinf.inputChannels * aacinf.frameLength;
	out_payload_size = aacinf.maxOutBufBytes;
	in_buffer = malloc(in_buffer_size);
	out_buffer = malloc(sizeof(rtp_header_t) + out_payload_size);

	pthread_cleanup_push(CANCEL_ROUTINE(free), in_buffer);
	pthread_cleanup_push(CANCEL_ROUTINE(free), out_buffer);

	if (in_buffer == NULL || out_buffer == NULL) {
		error("Couldn't create data buffers: %s", strerror(ENOMEM));
		goto fail;
	}

	uint16_t seq_number = random();
	uint32_t timestamp = random();

	/* initialize RTP header (the constant part) */
	rtp_header_t *rtp_header = (rtp_header_t *)out_buffer;
	memset(rtp_header, 0, sizeof(*rtp_header));
	rtp_header->version = 2;
	rtp_header->paytype = 96;

	/* anchor for RTP payload - audioMuxElement (RFC 3016) */
	out_payload = (uint8_t *)&rtp_header->csrc[rtp_header->cc];
	/* helper variable used during payload fragmentation */
	const size_t rtp_header_len = out_payload - out_buffer;

	/* initial input buffer head position and the available size */
	size_t in_samples = in_buffer_size / in_buffer_element_size;
	in_buffer_head = in_buffer;

	struct pollfd pfds[] = {
		{ t->event_fd, POLLIN, 0 },
		{ -1, POLLIN, 0 },
	};

	struct io_sync io_sync = {
		.sampling = samplerate,
	};

	debug("Starting IO loop: %s",
			bluetooth_profile_to_string(t->profile, t->codec));
	for (;;) {
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		ssize_t samples;

		/* add PCM socket to the poll if transport is active */
		pfds[1].fd = t->state == TRANSPORT_ACTIVE ? t->a2dp.pcm.fd : -1;

		if (poll(pfds, sizeof(pfds) / sizeof(*pfds), -1) == -1) {
			error("Transport poll error: %s", strerror(errno));
			goto fail;
		}

		if (pfds[0].revents & POLLIN) {
			/* dispatch incoming event */
			eventfd_t event;
			eventfd_read(pfds[0].fd, &event);
			io_sync.frames = 0;
			continue;
		}

		/* read data from the FIFO - this function will block */
		if ((samples = io_thread_read_pcm(&t->a2dp.pcm, in_buffer_head, in_samples)) <= 0) {
			if (samples == -1)
				error("FIFO read error: %s", strerror(errno));
			goto fail;
		}

		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

		if (io_sync.frames == 0) {
			gettimestamp(&io_sync.ts);
			io_sync.ts0 = io_sync.ts;
		}

		if (!config.a2dp_volume || !t->a2dp.supports_dbus_volume)
			/* scale volume or mute audio signal */
			io_thread_scale_pcm(t, in_buffer_head, samples, channels);

		/* overall input buffer size */
		samples += in_buffer_head - in_buffer;
		/* in the encoding loop head is used for reading */
		in_buffer_head = in_buffer;

		while ((in_args.numInSamples = samples) != 0) {

			if ((err = aacEncEncode(handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK)
				error("AAC encoding error: %s", aacenc_strerror(err));

			if (out_args.numOutBytes > 0) {

				size_t payload_len_max = t->mtu_write - rtp_header_len;
				size_t payload_len = out_args.numOutBytes;
				rtp_header->timestamp = htonl(timestamp);

				/* If the size of the RTP packet exceeds writing MTU, the RTP payload
				 * should be fragmented. According to the RFC 3016, fragmentation of
				 * the audioMuxElement requires no extra header - the payload should
				 * be fragmented and spread across multiple RTP packets.
				 *
				 * TODO: Confirm that the fragmentation logic is correct.
				 *
				 * This code has been tested with Jabra Move headset, however the
				 * outcome of this test is not positive. Fragmented packets are not
				 * recognized by the device. */
				for (;;) {

					ssize_t ret;
					size_t len;

					len = payload_len > payload_len_max ? payload_len_max : payload_len;
					rtp_header->markbit = len < payload_len_max;
					rtp_header->seq_number = htons(++seq_number);

					if ((ret = write(t->bt_fd, out_buffer, rtp_header_len + len)) == -1) {
						if (errno == ECONNRESET || errno == ENOTCONN) {
							/* exit the thread upon BT socket disconnection */
							debug("BT socket disconnected");
							goto fail;
						}
						error("BT socket write error: %s", strerror(errno));
						break;
					}

					/* break if the last part of the payload has been written */
					if ((payload_len -= ret - rtp_header_len) == 0)
						break;

					/* move rest of data to the beginning of the payload */
					debug("Payload fragmentation: extra %zd bytes", payload_len);
					memmove(out_payload, out_payload + ret, payload_len);

				}

			}

			/* progress the head position by the number of samples consumed by the
			 * encoder, also adjust the number of samples in the input buffer */
			in_buffer_head += out_args.numInSamples;
			samples -= out_args.numInSamples;

			/* keep data transfer at a constant bit rate, also
			 * get a timestamp for the next RTP frame */
			timestamp += io_thread_time_sync(&io_sync, out_args.numInSamples / channels);
			t->delay = io_sync.delay;

		}

		/* move leftovers to the beginning */
		if (samples > 0 && in_buffer != in_buffer_head)
			memmove(in_buffer, in_buffer_head, samples * in_buffer_element_size);
		/* reposition input buffer head */
		in_buffer_head = in_buffer + samples;
		in_samples = in_buffer_size / in_buffer_element_size - samples;

	}

fail:
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
fail_init:
	pthread_cleanup_pop(1);
fail_open:
	pthread_cleanup_pop(1);
	return NULL;
}
#endif

void *io_thread_rfcomm(void *arg) {
	struct ba_transport *t = (struct ba_transport *)arg;

	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_push(CANCEL_ROUTINE(io_thread_release), t);

	uint8_t mic_gain = t->rfcomm.sco->sco.mic_gain;
	uint8_t spk_gain = t->rfcomm.sco->sco.spk_gain;
	char buffer[64];
	struct at_command at;
	int i;

	struct pollfd pfds[] = {
		{ t->event_fd, POLLIN, 0 },
		{ t->bt_fd, POLLIN, 0 },
	};

	/* HSP only supports CVSD */
	if (t->profile == BLUETOOTH_PROFILE_HSP_HS || t->profile == BLUETOOTH_PROFILE_HSP_AG)
		t->rfcomm.sco->sco.codec = TRANSPORT_SCO_CODEC_CVSD;

	debug("Starting RFCOMM loop: %s",
			bluetooth_profile_to_string(t->profile, t->codec));
	for (;;) {

		const char *response = "OK";
		ssize_t ret;

		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		if (poll(pfds, sizeof(pfds) / sizeof(*pfds), -1) == -1) {
			error("Transport poll error: %s", strerror(errno));
			goto fail;
		}

		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

		if (pfds[0].revents & POLLIN) {
			/* dispatch incoming event */

			eventfd_t event;
			eventfd_read(pfds[0].fd, &event);

			if (mic_gain != t->rfcomm.sco->sco.mic_gain) {
				mic_gain = t->rfcomm.sco->sco.mic_gain;
				debug("Setting microphone gain: %d", mic_gain);
				sprintf(buffer, "+VGM=%d", mic_gain);
				io_thread_write_at_response(pfds[1].fd, buffer);
			}
			if (spk_gain != t->rfcomm.sco->sco.spk_gain) {
				spk_gain = t->rfcomm.sco->sco.spk_gain;
				debug("Setting speaker gain: %d", spk_gain);
				sprintf(buffer, "+VGS=%d", mic_gain);
				io_thread_write_at_response(pfds[1].fd, buffer);
			}

			continue;
		}

		if ((ret = read(pfds[1].fd, buffer, sizeof(buffer))) == -1) {
			switch (errno) {
			case ECONNABORTED:
			case ECONNRESET:
			case ENOTCONN:
			case ETIMEDOUT:
				/* exit the thread upon socket disconnection */
				debug("RFCOMM disconnected: %s", strerror(errno));
				transport_set_state(t, TRANSPORT_ABORTED);
				goto fail;
			default:
				error("RFCOMM read error: %s", strerror(errno));
				continue;
			}
		}

		/* Parse AT command received from the headset. */
		if (at_parse(buffer, &at)) {
			warn("Invalid AT command: %s", buffer);
			continue;
		}

		debug("AT command: %s=%s", at.command, at.value);

		if (strcmp(at.command, "RING") == 0) {
		}
		else if (strcmp(at.command, "+CKPD") == 0 && atoi(at.value) == 200) {
		}
		else if (strcmp(at.command, "+VGM") == 0)
			t->rfcomm.sco->sco.mic_gain = mic_gain = atoi(at.value);
		else if (strcmp(at.command, "+VGS") == 0)
			t->rfcomm.sco->sco.spk_gain = spk_gain = atoi(at.value);
		else if (strcmp(at.command, "+IPHONEACCEV") == 0) {

			char *ptr = at.value;
			size_t count = atoi(strsep(&ptr, ","));
			char tmp;

			while (count-- && ptr != NULL)
				switch (tmp = *strsep(&ptr, ",")) {
				case '1':
					if (ptr != NULL)
						t->device->xapl.accev_battery = atoi(strsep(&ptr, ","));
					break;
				case '2':
					if (ptr != NULL)
						t->device->xapl.accev_docked = atoi(strsep(&ptr, ","));
					break;
				default:
					warn("Unsupported IPHONEACCEV key: %c", tmp);
					strsep(&ptr, ",");
				}

		}
		else if (strcmp(at.command, "+XAPL") == 0) {

			unsigned int vendor, product;
			unsigned int version, features;

			if (sscanf(at.value, "%x-%x-%u,%u", &vendor, &product, &version, &features) == 4) {
				t->device->xapl.vendor_id = vendor;
				t->device->xapl.product_id = product;
				t->device->xapl.version = version;
				t->device->xapl.features = features;
				response = "+XAPL=BlueALSA,0";
			}
			else {
				warn("Invalid XAPL value: %s", at.value);
				response = "ERROR";
			}

		}
		else if (strcmp(at.command, "+BRSF") == 0) {

			uint32_t hf_features = strtoul(at.value, NULL, 10);
			debug("Got HFP HF features: 0x%x", hf_features);

			uint32_t ag_features = HFP_AG_FEATURES;
#if defined(ENABLE_MSBC)
			if (config.enable_msbc) {
				if (hf_features & HFP_HF_FEAT_CODEC) {
					ag_features |= HFP_AG_FEAT_CODEC;
				}
			}
#endif
			if ((ag_features & HFP_AG_FEAT_CODEC) == 0) {
				/* Codec negotiation is not supported,
				   hence no wideband audio support.
				   AT+BAC is not sent
				   */
				t->rfcomm.sco->sco.codec = TRANSPORT_SCO_CODEC_CVSD;
			}

			t->rfcomm.sco->sco.hf_features = hf_features;

			snprintf(buffer, sizeof(buffer), "+BRSF: %u", ag_features);
			io_thread_write_at_response(pfds[1].fd, buffer);

		}
		else if (strcmp(at.command, "+BAC") == 0 && at.type == AT_CMD_TYPE_SET) {

			debug("Supported codecs: %s", at.value);
			/* In case some headsets send BAC even if we don't
			 * advertise support for it, just OK and ignore
			 */
#if defined(ENABLE_MSBC)
			/* Split codecs string */
			gchar **codecs = g_strsplit(at.value, ",", 0);
			for (i = 0; codecs[i]; i++) {
				gchar *codec = codecs[i];
				uint32_t codec_value = strtoul(codec, NULL, 10);
				if (codec_value == HFP_CODEC_MSBC) {
					t->rfcomm.sco->sco.codec = TRANSPORT_SCO_CODEC_MSBC;
				}
			}
			g_strfreev(codecs);
#endif
			/* Default to CVSD if no other was found */
			if (t->rfcomm.sco->sco.codec == TRANSPORT_SCO_CODEC_UNKNOWN)
				t->rfcomm.sco->sco.codec = TRANSPORT_SCO_CODEC_CVSD;

		}
		else if (strcmp(at.command, "+CIND") == 0) {

			if ( at.type == AT_CMD_TYPE_GET) {
				io_thread_write_at_response(pfds[1].fd,
					"+CIND: 0,0,1,4,0,4,0");
			}
			else if(at.type == AT_CMD_TYPE_TEST) {
				io_thread_write_at_response(pfds[1].fd,
					"+CIND: "
					"(\"call\",(0,1))"
					",(\"callsetup\",(0-3))"
					",(\"service\",(0-1))"
					",(\"signal\",(0-5))"
					",(\"roam\",(0,1))"
					",(\"battchg\",(0-5))"
					",(\"callheld\",(0-2))"
					);
			}

		}
		else if (strcmp(at.command, "+CMER") == 0 && at.type == AT_CMD_TYPE_SET) {

			/* +CMER is the last step of the "Service Level
			   Connection establishment" procedure */

			/* Send OK */
			io_thread_write_at_response(pfds[1].fd, response);

			/* Send codec select if anything besides CVSD was found */
			if (t->rfcomm.sco->sco.codec > TRANSPORT_SCO_CODEC_CVSD) {
				snprintf(buffer, sizeof(buffer), "+BCS: %u", t->rfcomm.sco->sco.codec);
				io_thread_write_at_response(pfds[1].fd, buffer);
			}
			continue;

		}
		else if (strcmp(at.command, "+BCS") == 0 && at.type == AT_CMD_TYPE_SET) {
			debug("Got codec selected: %d", atoi(at.value));
		}
		else if (strcmp(at.command, "+BTRH") == 0 && at.type == AT_CMD_TYPE_GET) {
		}
		else if (strcmp(at.command, "+NREC") == 0 && at.type == AT_CMD_TYPE_SET) {
		}
		else if (strcmp(at.command, "+CCWA") == 0 && at.type == AT_CMD_TYPE_SET) {
		}
		else if (strcmp(at.command, "+BIA") == 0 && at.type == AT_CMD_TYPE_SET) {
		}
		else if (strcmp(at.command, "+CHLD") == 0 && at.type == AT_CMD_TYPE_TEST) {
			io_thread_write_at_response(pfds[1].fd, "+CHLD: (0,1,2,3)");
		}
		else {
			warn("Unsupported AT command: %s=%s", at.command, at.value);
			response = "ERROR";
		}

		io_thread_write_at_response(pfds[1].fd, response);
	}

fail:
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_pop(1);
	return NULL;
}

void *io_thread_sco(void *arg) {
	struct ba_transport *t = (struct ba_transport *)arg;

	/* this buffer has to be bigger than SCO MTU */
	const size_t buffer_size = 512;
	struct sbc_state *sbc = NULL;
	int16_t *buffer = malloc(buffer_size);

	pthread_cleanup_push(CANCEL_ROUTINE(free), buffer);
	pthread_cleanup_push(CANCEL_ROUTINE(free), sbc);

	if (buffer == NULL) {
		error("Couldn't create data buffers: %s", strerror(ENOMEM));
		goto fail;
	}

	struct pollfd pfds[] = {
		{ t->event_fd, POLLIN, 0 },
		{ -1, POLLIN, 0 }, //bt
		{ -1, 0, 0 }, // shm pcm mic follower by shm pcm spk
		{ -1, 0, 0 },
		{ -1, 0, 0 },
		{ -1, 0, 0 },
	};

	struct io_sync io_sync = {
		.frames = 0,
	};

	debug("Starting IO loop: %s",
			bluetooth_profile_to_string(t->profile, t->codec));
	for (;;) {

		if (t->sco.codec == TRANSPORT_SCO_CODEC_MSBC) {
			pfds[1].fd = t->bt_fd;
		} else {
			pfds[1].fd = t->sco.mic_pcm.shm != NULL ? t->bt_fd : -1;
		}

		int shm_mic_nr_pfds = libshm_nr_pollfd(t->sco.mic_pcm.shm);
		int shm_spk_nr_pfds = libshm_nr_pollfd(t->sco.spk_pcm.shm);
		libshm_populate_pollfd(t->sco.mic_pcm.shm, &pfds[2]);
		libshm_populate_pollfd(t->sco.spk_pcm.shm, &pfds[2 + shm_mic_nr_pfds]);

		if (poll(pfds, 2 + shm_mic_nr_pfds + shm_spk_nr_pfds, -1) == -1) {
			error("Transport poll error: %s", strerror(errno));
			goto fail;
		}

		if (pfds[0].revents & POLLIN) {
			/* dispatch incoming event */

			eventfd_t event;
			eventfd_read(pfds[0].fd, &event);

			/* It is required to release SCO if we are not transferring audio,
			 * because it will free Bluetooth bandwidth - microphone signal is
			 * transfered even though we are not reading from it! */
			if (t->sco.spk_pcm.shm == NULL && t->sco.mic_pcm.shm == NULL) {
				transport_release_bt_sco(t);
				io_sync.frames = 0;
			}
			else {
				debug("Trying to acquire");
				transport_acquire_bt_sco(t);
#if defined(ENABLE_MSBC)
				/* This can be called again, make sure it is "reentrant" */
				if (t->sco.codec == TRANSPORT_SCO_CODEC_MSBC) {
					sbc = iothread_initialize_msbc(sbc);
					if (!sbc)
						goto fail;
				}
#endif
			}

			io_sync.sampling = transport_get_sampling(t);
			continue;
		}

		if (io_sync.frames == 0) {
			gettimestamp(&io_sync.ts);
			io_sync.ts0 = io_sync.ts;
		}

		int poll_mic = libshm_poll(t->sco.mic_pcm.shm, &pfds[2], shm_mic_nr_pfds);
		int poll_spk = libshm_poll(t->sco.spk_pcm.shm, &pfds[2 + shm_mic_nr_pfds], shm_spk_nr_pfds);

		if (pfds[1].revents & POLLIN) { // bluetooth socket incoming

#if defined(ENABLE_MSBC)
			if (t->sco.codec == TRANSPORT_SCO_CODEC_MSBC) {
				iothread_handle_incoming_msbc(t, sbc);
			}
			else
#endif
			{
				ssize_t len;

				if ((len = read(pfds[1].fd, buffer, buffer_size)) == -1) {
					debug("SCO read error: %s", strerror(errno));
					continue;
				}

				libshm_write_all(t->sco.mic_pcm.shm, buffer, len);
			}
		}

		if (poll_spk & POLLIN) {

#if defined(ENABLE_MSBC)
			if (t->sco.codec == TRANSPORT_SCO_CODEC_MSBC) {
				iothread_handle_outgoing_msbc(t, sbc);
			}
			else
#endif
			{
				ssize_t samples = t->mtu_write / sizeof(int16_t);

				/* read data from the FIFO - this function will block */
				if ((samples = io_thread_read_pcm(&t->sco.spk_pcm, buffer, samples)) <= 0) {
					if (samples == -1)
						error("FIFO read error: %s", strerror(errno));
					continue;
				}

				write(t->bt_fd, buffer, samples * sizeof(int16_t));
			}
		}

		/* mSBC output is synchronized to input, no need for this */
		if (t->sco.codec != TRANSPORT_SCO_CODEC_MSBC) {
			/* keep data transfer at a constant bit rate */
			io_thread_time_sync(&io_sync, 48 / 2);
			t->delay = io_sync.delay;
		}

	}

fail:
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
	return NULL;
}
static gboolean
gst_fdkaacenc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
{
  GstFdkAacEnc *self = GST_FDKAACENC (enc);
  gboolean ret = FALSE;
  GstCaps *allowed_caps;
  GstCaps *src_caps;
  AACENC_ERROR err;
  gint transmux = 0, aot = AOT_AAC_LC;
  gint mpegversion = 4;
  CHANNEL_MODE channel_mode;
  AACENC_InfoStruct enc_info = { 0 };
  gint bitrate;

  if (self->enc) {
    /* drain */
    gst_fdkaacenc_handle_frame (enc, NULL);
    aacEncClose (&self->enc);
  }

  allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (self));

  GST_DEBUG_OBJECT (self, "allowed caps: %" GST_PTR_FORMAT, allowed_caps);

  if (allowed_caps && gst_caps_get_size (allowed_caps) > 0) {
    GstStructure *s = gst_caps_get_structure (allowed_caps, 0);
    const gchar *str = NULL;

    if ((str = gst_structure_get_string (s, "stream-format"))) {
      if (strcmp (str, "adts") == 0) {
        GST_DEBUG_OBJECT (self, "use ADTS format for output");
        transmux = 2;
      } else if (strcmp (str, "adif") == 0) {
        GST_DEBUG_OBJECT (self, "use ADIF format for output");
        transmux = 1;
      } else if (strcmp (str, "raw") == 0) {
        GST_DEBUG_OBJECT (self, "use RAW format for output");
        transmux = 0;
      }
    }

    gst_structure_get_int (s, "mpegversion", &mpegversion);
  }
  if (allowed_caps)
    gst_caps_unref (allowed_caps);

  err = aacEncOpen (&self->enc, 0, GST_AUDIO_INFO_CHANNELS (info));
  if (err != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to open encoder: %d\n", err);
    return FALSE;
  }

  aot = AOT_AAC_LC;

  if ((err = aacEncoder_SetParam (self->enc, AACENC_AOT, aot)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set AOT %d: %d\n", aot, err);
    return FALSE;
  }

  if ((err = aacEncoder_SetParam (self->enc, AACENC_SAMPLERATE,
              GST_AUDIO_INFO_RATE (info))) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set sample rate %d: %d\n",
        GST_AUDIO_INFO_RATE (info), err);
    return FALSE;
  }

  if (GST_AUDIO_INFO_CHANNELS (info) == 1) {
    channel_mode = MODE_1;
    self->need_reorder = FALSE;
    self->aac_positions = NULL;
  } else {
    guint64 in_channel_mask, out_channel_mask;
    gint i;

    for (i = 0; i < G_N_ELEMENTS (channel_layouts); i++) {
      if (channel_layouts[i].channels != GST_AUDIO_INFO_CHANNELS (info))
        continue;

      gst_audio_channel_positions_to_mask (&GST_AUDIO_INFO_POSITION (info, 0),
          GST_AUDIO_INFO_CHANNELS (info), FALSE, &in_channel_mask);
      gst_audio_channel_positions_to_mask (channel_layouts[i].positions,
          channel_layouts[i].channels, FALSE, &out_channel_mask);
      if (in_channel_mask == out_channel_mask) {
        channel_mode = channel_layouts[i].mode;
        self->need_reorder =
            memcmp (channel_layouts[i].positions,
            &GST_AUDIO_INFO_POSITION (info, 0),
            GST_AUDIO_INFO_CHANNELS (info) *
            sizeof (GstAudioChannelPosition)) != 0;
        self->aac_positions = channel_layouts[i].positions;
        break;
      }
    }

    if (i == G_N_ELEMENTS (channel_layouts)) {
      GST_ERROR_OBJECT (self, "Couldn't find a valid channel layout");
      return FALSE;
    }
  }

  if ((err = aacEncoder_SetParam (self->enc, AACENC_CHANNELMODE,
              channel_mode)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set channel mode %d: %d", channel_mode,
        err);
    return FALSE;
  }

  /* MPEG channel order */
  if ((err = aacEncoder_SetParam (self->enc, AACENC_CHANNELORDER,
              0)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set channel order %d: %d", channel_mode,
        err);
    return FALSE;
  }

  bitrate = self->bitrate;
  /* See
   * http://wiki.hydrogenaud.io/index.php?title=Fraunhofer_FDK_AAC#Recommended_Sampling_Rate_and_Bitrate_Combinations
   */
  if (bitrate == 0) {
    if (GST_AUDIO_INFO_CHANNELS (info) == 1) {
      if (GST_AUDIO_INFO_RATE (info) < 16000) {
        bitrate = 8000;
      } else if (GST_AUDIO_INFO_RATE (info) == 16000) {
        bitrate = 16000;
      } else if (GST_AUDIO_INFO_RATE (info) < 32000) {
        bitrate = 24000;
      } else if (GST_AUDIO_INFO_RATE (info) == 32000) {
        bitrate = 32000;
      } else if (GST_AUDIO_INFO_RATE (info) <= 44100) {
        bitrate = 56000;
      } else {
        bitrate = 160000;
      }
    } else if (GST_AUDIO_INFO_CHANNELS (info) == 2) {
      if (GST_AUDIO_INFO_RATE (info) < 16000) {
        bitrate = 16000;
      } else if (GST_AUDIO_INFO_RATE (info) == 16000) {
        bitrate = 24000;
      } else if (GST_AUDIO_INFO_RATE (info) < 22050) {
        bitrate = 32000;
      } else if (GST_AUDIO_INFO_RATE (info) < 32000) {
        bitrate = 40000;
      } else if (GST_AUDIO_INFO_RATE (info) == 32000) {
        bitrate = 96000;
      } else if (GST_AUDIO_INFO_RATE (info) <= 44100) {
        bitrate = 112000;
      } else {
        bitrate = 320000;
      }
    } else {
      /* 5, 5.1 */
      if (GST_AUDIO_INFO_RATE (info) < 32000) {
        bitrate = 160000;
      } else if (GST_AUDIO_INFO_RATE (info) <= 44100) {
        bitrate = 240000;
      } else {
        bitrate = 320000;
      }
    }
  }

  if ((err = aacEncoder_SetParam (self->enc, AACENC_TRANSMUX,
              transmux)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set transmux %d: %d", transmux, err);
    return FALSE;
  }

  if ((err = aacEncoder_SetParam (self->enc, AACENC_BITRATE,
              bitrate)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to set bitrate %d: %d", bitrate, err);
    return FALSE;
  }

  if ((err = aacEncEncode (self->enc, NULL, NULL, NULL, NULL)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to initialize encoder: %d", err);
    return FALSE;
  }

  if ((err = aacEncInfo (self->enc, &enc_info)) != AACENC_OK) {
    GST_ERROR_OBJECT (self, "Unable to get encoder info: %d", err);
    return FALSE;
  }

  gst_audio_encoder_set_frame_max (enc, 1);
  gst_audio_encoder_set_frame_samples_min (enc, enc_info.frameLength);
  gst_audio_encoder_set_frame_samples_max (enc, enc_info.frameLength);
  gst_audio_encoder_set_hard_min (enc, FALSE);
  self->outbuf_size = enc_info.maxOutBufBytes;
  self->samples_per_frame = enc_info.frameLength;

  src_caps = gst_caps_new_simple ("audio/mpeg",
      "mpegversion", G_TYPE_INT, mpegversion,
      "channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
      "framed", G_TYPE_BOOLEAN, TRUE,
      "rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);

  /* raw */
  if (transmux == 0) {
    GstBuffer *codec_data =
        gst_buffer_new_wrapped (g_memdup (enc_info.confBuf, enc_info.confSize),
        enc_info.confSize);
    gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER, codec_data,
        "stream-format", G_TYPE_STRING, "raw", NULL);
    gst_buffer_unref (codec_data);
  } else if (transmux == 1) {
    gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adif",
        NULL);
  } else if (transmux == 2) {
    gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts",
        NULL);
  } else {
    g_assert_not_reached ();
  }

  gst_codec_utils_aac_caps_set_level_and_profile (src_caps, enc_info.confBuf,
      enc_info.confSize);

  ret = gst_audio_encoder_set_output_format (enc, src_caps);
  gst_caps_unref (src_caps);

  return ret;
}
Beispiel #7
0
/*****************************************************************************
 * OpenDecoder: open the encoder.
 *****************************************************************************/
static int OpenEncoder(vlc_object_t *p_this)
{
    encoder_t *p_enc = (encoder_t *)p_this;

    config_ChainParse(p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg);

    int i_aot;
    switch (p_enc->fmt_out.i_codec) {
    case VLC_CODEC_MP4A:
        i_aot = var_InheritInteger(p_enc, ENC_CFG_PREFIX "profile");
        break;
    case VLC_FOURCC('l', 'a', 'a', 'c'):
        i_aot = PROFILE_AAC_LC;
        break;
    case VLC_FOURCC('h', 'a', 'a', 'c'):
        i_aot = PROFILE_AAC_HE;
        break;
    case VLC_FOURCC('s', 'a', 'a', 'c'):
        i_aot = PROFILE_AAC_HE_v2;
        break;
    default:
        return VLC_EGENERIC;
    }

    if (p_enc->fmt_in.audio.i_channels != 2)
        if (i_aot == PROFILE_AAC_HE_v2 || i_aot == PROFILE_AAC_ELD) {
            msg_Err(p_enc, "Selected profile %d can only be used with stereo", i_aot);
            return VLC_EGENERIC;
        }

    uint16_t channel_config;
    CHANNEL_MODE mode;
    switch (p_enc->fmt_in.audio.i_channels) {
    case 1: mode = MODE_1; channel_config = AOUT_CHAN_CENTER; break;
    case 2: mode = MODE_2; channel_config = AOUT_CHANS_STEREO; break;
    case 3: mode = MODE_1_2; channel_config = AOUT_CHANS_3_0; break;
    case 4: mode = MODE_1_2_1; channel_config = AOUT_CHANS_4_CENTER_REAR; break;
    case 5: mode = MODE_1_2_2; channel_config = AOUT_CHANS_5_0; break;
    case 6: mode = MODE_1_2_2_1; channel_config = AOUT_CHANS_5_1; break;
    case 8: mode = MODE_1_2_2_2_1; channel_config = AOUT_CHANS_7_1; break;
    default:
        msg_Err(p_enc, "we do not support > 8 input channels, this input has %i",
                        p_enc->fmt_in.audio.i_channels);
        return VLC_EGENERIC;
    }

    p_enc->fmt_in.audio.i_physical_channels = channel_config;

    msg_Info(p_enc, "Initializing AAC Encoder, %i channels", p_enc->fmt_in.audio.i_channels);

    /* Allocate the memory needed to store the encoder's structure */
    encoder_sys_t *p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t));
    if (unlikely(!p_sys))
        return VLC_ENOMEM;
    p_enc->p_sys = p_sys;
    p_enc->fmt_in.i_codec = VLC_CODEC_S16N;
    p_enc->fmt_out.i_cat = AUDIO_ES;
    p_enc->fmt_out.i_codec = VLC_CODEC_MP4A;

    p_sys->i_pts_last = 0;

    AACENC_ERROR erraac;
    erraac = aacEncOpen(&p_sys->handle, 0, p_enc->fmt_in.audio.i_channels);
    if (erraac != AACENC_OK) {
        msg_Err(p_enc, "Unable to open encoder: %s", fdkaac_error(erraac));
        free(p_sys);
        return VLC_EGENERIC;
    }

#define SET_PARAM(P, V) do { \
        AACENC_ERROR err = aacEncoder_SetParam(p_sys->handle, AACENC_ ## P, V); \
        if (err != AACENC_OK) { \
            msg_Err(p_enc, "Couldn't set " #P " to value %d: %s", V, fdkaac_error(err)); \
            goto error; \
        } \
    } while(0)

    SET_PARAM(AOT, i_aot);
    bool b_eld_sbr = var_InheritBool(p_enc, ENC_CFG_PREFIX "sbr");
    if (i_aot == PROFILE_AAC_ELD && b_eld_sbr)
        SET_PARAM(SBR_MODE, 1);
    SET_PARAM(SAMPLERATE, p_enc->fmt_out.audio.i_rate);
    SET_PARAM(CHANNELMODE, mode);
    SET_PARAM(CHANNELORDER, CH_ORDER_WG4);

    int i_vbr = var_InheritInteger(p_enc, ENC_CFG_PREFIX "vbr");
    if (i_vbr != 0) {
        if ((i_aot == PROFILE_AAC_HE || i_aot == PROFILE_AAC_HE_v2) && i_vbr > 3) {
            msg_Warn(p_enc, "Maximum VBR quality for this profile is 3, setting vbr=3");
            i_vbr = 3;
        }
        SET_PARAM(BITRATEMODE, i_vbr);
    } else {
        int i_bitrate = p_enc->fmt_out.i_bitrate;
        if (i_bitrate == 0) {
            i_bitrate = 96 * p_enc->fmt_in.audio.i_channels * p_enc->fmt_out.audio.i_rate / 44;
            if (i_aot == PROFILE_AAC_HE || i_aot == PROFILE_AAC_HE_v2 || b_eld_sbr)
                i_bitrate /= 2;
            p_enc->fmt_out.i_bitrate = i_bitrate;
            msg_Info(p_enc, "Setting optimal bitrate of %i", i_bitrate);
        }
        SET_PARAM(BITRATE, i_bitrate);
    }
    SET_PARAM(TRANSMUX, 0);
    SET_PARAM(SIGNALING_MODE, (int)var_InheritInteger(p_enc, ENC_CFG_PREFIX "signaling"));
    SET_PARAM(AFTERBURNER, !!var_InheritBool(p_enc, ENC_CFG_PREFIX "afterburner"));
#undef SET_PARAM

    erraac = aacEncEncode(p_sys->handle, NULL, NULL, NULL, NULL);
    if (erraac != AACENC_OK) {
        msg_Err(p_enc, "Unable to initialize the encoder: %s", fdkaac_error(erraac));
        goto error;
    }

    AACENC_InfoStruct info = { 0 };
    erraac = aacEncInfo(p_sys->handle, &info);
    if (erraac != AACENC_OK) {
        msg_Err(p_enc, "Unable to get the encoder info: %s", fdkaac_error(erraac));
        goto error;
    }

    /* The maximum packet size is 6144 bits aka 768 bytes per channel. */
    p_sys->i_maxoutputsize = 768*p_enc->fmt_in.audio.i_channels;
    p_enc->fmt_in.audio.i_bitspersample = 16;
    p_sys->i_frame_size = info.frameLength;
    p_sys->i_encoderdelay = info.encoderDelay;

    p_enc->fmt_out.i_extra = info.confSize;
    if (p_enc->fmt_out.i_extra) {
        p_enc->fmt_out.p_extra = malloc(p_enc->fmt_out.i_extra);
        if (p_enc->fmt_out.p_extra == NULL) {
            msg_Err(p_enc, "Unable to allocate fmt_out.p_extra");
            goto error;
        }
        memcpy(p_enc->fmt_out.p_extra, info.confBuf, p_enc->fmt_out.i_extra);
    }

    p_enc->pf_encode_audio = EncodeAudio;

#ifndef NDEBUG
    // TODO: Add more debug info to this config printout
    msg_Dbg(p_enc, "fmt_out.p_extra = %i", p_enc->fmt_out.i_extra);
#endif

    return VLC_SUCCESS;

error:
    CloseEncoder(p_this);
    return VLC_EGENERIC;
}
Beispiel #8
0
static void *libfdk_create(obs_data_t settings, obs_encoder_t encoder)
{
	bool hasFdkHandle = false;
	libfdk_encoder_t *enc = 0;
	int bitrate = (int)obs_data_get_int(settings, "bitrate") * 1000;
	int afterburner = obs_data_get_bool(settings, "afterburner") ? 1 : 0;
	audio_t audio = obs_encoder_audio(encoder);
	int mode = 0;
	AACENC_ERROR err;

	if (!bitrate) {
		blog(LOG_ERROR, "Invalid bitrate");
		return NULL;
	}

	enc = bzalloc(sizeof(libfdk_encoder_t));
	enc->encoder = encoder;

	enc->channels = (int)audio_output_get_channels(audio);
	enc->sample_rate = audio_output_get_sample_rate(audio);

	switch(enc->channels) {
	case 1:
		mode = MODE_1;
		break;
	case 2:
		mode = MODE_2;
		break;
	case 3:
		mode = MODE_1_2;
		break;
	case 4:
		mode = MODE_1_2_1;
		break;
	case 5:
		mode = MODE_1_2_2;
		break;
	case 6:
		mode = MODE_1_2_2_1;
		break;
	default:
		blog(LOG_ERROR, "Invalid channel count");
		goto fail;
	}

	CHECK_LIBFDK(aacEncOpen(&enc->fdkhandle, 0, enc->channels));
	hasFdkHandle = true;

	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AOT,
	                                 2)); // MPEG-4 AAC-LC
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_SAMPLERATE,
	                                 enc->sample_rate));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELMODE, mode));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELORDER, 1));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATEMODE, 0));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATE, bitrate));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_TRANSMUX, 0));
	CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AFTERBURNER,
	                                 afterburner));

	CHECK_LIBFDK(aacEncEncode(enc->fdkhandle, NULL, NULL, NULL, NULL));

	CHECK_LIBFDK(aacEncInfo(enc->fdkhandle, &enc->info));

	enc->frame_size_bytes = enc->info.frameLength * 2 * enc->channels;

	enc->packet_buffer_size = enc->channels * 768;
	if(enc->packet_buffer_size < 8192)
		enc->packet_buffer_size = 8192;

	enc->packet_buffer = bmalloc(enc->packet_buffer_size);

	blog(LOG_INFO, "libfdk_aac encoder created");

	blog(LOG_INFO, "libfdk_aac bitrate: %d, channels: %d",
			bitrate / 1000, enc->channels);

	return enc;

fail:

	if(hasFdkHandle)
		aacEncClose(&enc->fdkhandle);

	if(enc->packet_buffer)
		bfree(enc->packet_buffer);

	if(enc)
		bfree(enc);

	blog(LOG_WARNING, "libfdk_aac encoder creation failed");

	return 0;
}
Beispiel #9
0
int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
                const pcm_sample_description_t *format,
                AACENC_InfoStruct *info)
{
    int channel_mode;
    int aot;
    LIB_INFO lib_info;

    *encoder = 0;
    aacenc_get_lib_info(&lib_info);

    if ((channel_mode = aacenc_channel_mode(format)) == 0) {
        fprintf(stderr, "ERROR: unsupported channel layout\n");
        goto FAIL;
    }
    if (aacEncOpen(encoder, 0, 0) != AACENC_OK) {
        fprintf(stderr, "ERROR: aacEncOpen() failed\n");
        goto FAIL;
    }
    aot = (params->profile ? params->profile : AOT_AAC_LC);
    if (aacEncoder_SetParam(*encoder, AACENC_AOT, aot) != AACENC_OK) {
        fprintf(stderr, "ERROR: unsupported profile\n");
        goto FAIL;
    }
    if (params->bitrate_mode == 0)
        aacEncoder_SetParam(*encoder, AACENC_BITRATE, params->bitrate);
    else if (aacEncoder_SetParam(*encoder, AACENC_BITRATEMODE,
                                 params->bitrate_mode) != AACENC_OK) {
        fprintf(stderr, "ERROR: unsupported bitrate mode\n");
        goto FAIL;
    }
    if (aacEncoder_SetParam(*encoder, AACENC_SAMPLERATE,
                            format->sample_rate) != AACENC_OK) {
        fprintf(stderr, "ERROR: unsupported sample rate\n");
        goto FAIL;
    }
    if (aacEncoder_SetParam(*encoder, AACENC_CHANNELMODE,
                            channel_mode) != AACENC_OK) {
        fprintf(stderr, "ERROR: unsupported channel mode\n");
        goto FAIL;
    }
    aacEncoder_SetParam(*encoder, AACENC_BANDWIDTH, params->bandwidth);
    aacEncoder_SetParam(*encoder, AACENC_CHANNELORDER, 1);
    aacEncoder_SetParam(*encoder, AACENC_AFTERBURNER, !!params->afterburner);

    aacEncoder_SetParam(*encoder, AACENC_SBR_MODE, params->lowdelay_sbr);

#if AACENCODER_LIB_VL0 > 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1>=4)
    if (lib_info.version > 0x03040800)
        aacEncoder_SetParam(*encoder, AACENC_SBR_RATIO, params->sbr_ratio);
#endif

    if (aacEncoder_SetParam(*encoder, AACENC_TRANSMUX,
                            params->transport_format) != AACENC_OK) {
        fprintf(stderr, "ERROR: unsupported transport format\n");
        goto FAIL;
    }
    if (aacEncoder_SetParam(*encoder, AACENC_SIGNALING_MODE,
                            params->sbr_signaling) != AACENC_OK) {
        fprintf(stderr, "ERROR: failed to set SBR signaling mode\n");
        goto FAIL;
    }
    if (params->adts_crc_check)
        aacEncoder_SetParam(*encoder, AACENC_PROTECTION, 1);
    if (params->header_period)
        aacEncoder_SetParam(*encoder, AACENC_HEADER_PERIOD,
                            params->header_period);

    if (aacEncEncode(*encoder, 0, 0, 0, 0) != AACENC_OK) {
        fprintf(stderr, "ERROR: encoder initialization failed\n");
        goto FAIL;
    }
    if (aacEncInfo(*encoder, info) != AACENC_OK) {
        fprintf(stderr, "ERROR: cannot retrieve encoder info\n");
        goto FAIL;
    }
    return 0;
FAIL:
    if (encoder)
        aacEncClose(encoder);
    return -1;
}