[Libav-user] Loopback audio encode and transmission on RTP

Netcoder1989 sachinrajput1989 at outlook.com
Thu Nov 28 05:43:43 CET 2013


Hello all I'm here to discuss a part of my project due to which I'm searching
and trying all the things but no success.
I'm capturing the loopback audio of my system and I want to transmit it on
UDP-RTP after encoding in (mp3/aac) using ffmpeg.
here is the snippets of my code.
HRESULT LoopbackCapture(
    IMMDevice *pMMDevice,
    bool bInt16,
    HANDLE hStartedEvent,
    HANDLE hStopEvent,
    CPrefs* prefs,
    PUINT32 pnFrames
) {
    HRESULT hr;

    // activate an IAudioClient
    IAudioClient *pAudioClient;
    hr = pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        printf("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
        return hr;
    }
    
    // get the default device periodicity
    REFERENCE_TIME hnsDefaultDevicePeriod;
    hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
    if (FAILED(hr)) {
        printf("IAudioClient::GetDevicePeriod failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }

    // get the default device format
    WAVEFORMATEX *pwfx;
    hr = pAudioClient->GetMixFormat(&pwfx);
    if (FAILED(hr)) {
        printf("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
        return hr;
    }

	int write;
	
	av_register_all();
	avformat_network_init();
	AVCodec *codec;
AVCodecContext *c= NULL;
AVFrame *frame;
AVPacket pkt;
int i, j, k, ret, got_output;
int buffer_size;

uint16_t *samples;
float t, tincr;
//printf("Encode audio file %s\n", filename);
/* find the MP2 encoder */
codec = avcodec_find_encoder(AV_CODEC_ID_MP3);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* put sample parameters */
c->bit_rate = 128000;
/* check that the encoder supports s16 pcm input */
c->sample_fmt = AV_SAMPLE_FMT_S16P;
c->time_base.num = 1;
c->time_base.den = select_sample_rate(codec);
if (!check_sample_fmt(codec, c->sample_fmt)) {
fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(c->sample_fmt));
exit(1);
}
/* select other audio parameters supported by the encoder */
c->sample_rate = select_sample_rate(codec);
c->channel_layout = select_channel_layout(codec);
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
c->codec_type = AVMEDIA_TYPE_AUDIO;


/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}

frame = avcodec_alloc_frame();
if (!frame) {
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
frame->nb_samples = c->frame_size;
frame->format = c->sample_fmt;
frame->channel_layout = c->channel_layout;
/* the codec gives us the frame size, in samples,
* we calculate the size of the samples buffer in bytes */
buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size,
c->sample_fmt, 0);
samples =(uint16_t*) av_malloc(buffer_size);
if (!samples) {
fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
buffer_size);
exit(1);
}


/* setup the data pointers in the AVFrame */


    if (bInt16) {
        // coerce int-16 wave format
        // can do this in-place since we're not changing the size of the
format
        // also, the engine will auto-convert from float to int for us
        switch (pwfx->wFormatTag) {
            case WAVE_FORMAT_IEEE_FLOAT:
                pwfx->wFormatTag = WAVE_FORMAT_PCM;
                pwfx->wBitsPerSample = 16;
                pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample /
8;
                pwfx->nAvgBytesPerSec = pwfx->nBlockAlign *
pwfx->nSamplesPerSec;
                break;

            case WAVE_FORMAT_EXTENSIBLE:
                {
                    // naked scope for case-local variable
                    PWAVEFORMATEXTENSIBLE pEx =
reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
                    if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
pEx->SubFormat)) {
                        pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
                        pEx->Samples.wValidBitsPerSample = 16;
                        pwfx->wBitsPerSample = 16;
                        pwfx->nBlockAlign = pwfx->nChannels *
pwfx->wBitsPerSample / 8;
                        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign *
pwfx->nSamplesPerSec;
						
                    } else {
                        printf("Don't know how to coerce mix format to
int-16\n");
                        CoTaskMemFree(pwfx);
                        pAudioClient->Release();
                        return E_UNEXPECTED;
                    }
                }
                break;

            default:
                printf("Don't know how to coerce WAVEFORMATEX with
wFormatTag = 0x%08x to int-16\n", pwfx->wFormatTag);
                CoTaskMemFree(pwfx);
                pAudioClient->Release();
                return E_UNEXPECTED;
        }
    }


    // create a periodic waitable timer
    HANDLE hWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
    if (NULL == hWakeUp) {
        DWORD dwErr = GetLastError();
        printf("CreateWaitableTimer failed: last error = %u\n", dwErr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
        return HRESULT_FROM_WIN32(dwErr);
    }

    UINT32 nBlockAlign = pwfx->nBlockAlign;
    *pnFrames = 0;
    
    // call IAudioClient::Initialize
    // note that AUDCLNT_STREAMFLAGS_LOOPBACK and
AUDCLNT_STREAMFLAGS_EVENTCALLBACK
    // do not work together...
    // the "data ready" event never gets set
    // so we're going to do a timer-driven loop
    hr = pAudioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_STREAMFLAGS_LOOPBACK,
        0, 0, pwfx, 0
    );
    if (FAILED(hr)) {
        printf("IAudioClient::Initialize failed: hr = 0x%08x\n", hr);
        CloseHandle(hWakeUp);
        pAudioClient->Release();
        return hr;
    }
    CoTaskMemFree(pwfx);

    // activate an IAudioCaptureClient
    IAudioCaptureClient *pAudioCaptureClient;
    hr = pAudioClient->GetService(
        __uuidof(IAudioCaptureClient),
        (void**)&pAudioCaptureClient
    );
    if (FAILED(hr)) {
        printf("IAudioClient::GetService(IAudioCaptureClient) failed: hr
0x%08x\n", hr);
        CloseHandle(hWakeUp);
        pAudioClient->Release();
        return hr;
    }
    
    // register with MMCSS
    DWORD nTaskIndex = 0;
    HANDLE hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);
    if (NULL == hTask) {
        DWORD dwErr = GetLastError();
        printf("AvSetMmThreadCharacteristics failed: last error = %u\n",
dwErr);
        pAudioCaptureClient->Release();
        CloseHandle(hWakeUp);
        pAudioClient->Release();
        return HRESULT_FROM_WIN32(dwErr);
    }    



    // set the waitable timer
    LARGE_INTEGER liFirstFire;
    liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means
relative time
    LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000);
// convert to milliseconds
    BOOL bOK = SetWaitableTimer(
        hWakeUp,
        &liFirstFire,
        lTimeBetweenFires,
        NULL, NULL, FALSE
    );
    if (!bOK) {
        DWORD dwErr = GetLastError();
        printf("SetWaitableTimer failed: last error = %u\n", dwErr);
        AvRevertMmThreadCharacteristics(hTask);
        pAudioCaptureClient->Release();
        CloseHandle(hWakeUp);
        pAudioClient->Release();
        return HRESULT_FROM_WIN32(dwErr);
    }
    
    // call IAudioClient::Start
    hr = pAudioClient->Start();
    if (FAILED(hr)) {
        printf("IAudioClient::Start failed: hr = 0x%08x\n", hr);
        AvRevertMmThreadCharacteristics(hTask);
        pAudioCaptureClient->Release();
        CloseHandle(hWakeUp);
        pAudioClient->Release();
        return hr;
    }
    SetEvent(hStartedEvent);
   // audio_encode_example();
	
    // loopback capture loop
    HANDLE waitArray[2] = { hStopEvent, hWakeUp };
    DWORD dwWaitResult;

    bool bDone = false;
    bool bFirstPacket = true;
	//filename = fopen("abcde.mp3", "wb+");
    for (UINT32 nPasses = 0; !bDone; nPasses++) {
        dwWaitResult = WaitForMultipleObjects(
            ARRAYSIZE(waitArray), waitArray,
            FALSE, INFINITE
        );

        if (WAIT_OBJECT_0 == dwWaitResult) {
            printf("Received stop event after %u passes and %u frames\n",
nPasses, *pnFrames);
            bDone = true;
            continue; // exits loop
        }

        if (WAIT_OBJECT_0 + 1 != dwWaitResult) {
            printf("Unexpected WaitForMultipleObjects return value %u on
pass %u after %u frames\n", dwWaitResult, nPasses, *pnFrames);
            pAudioClient->Stop();
            CancelWaitableTimer(hWakeUp);
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            CloseHandle(hWakeUp);
            pAudioClient->Release();
            return E_UNEXPECTED;
        }

        // got a "wake up" event - see if there's data
        UINT32 nNextPacketSize;
        hr = pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize);
        if (FAILED(hr)) {
            printf("IAudioCaptureClient::GetNextPacketSize failed on pass %u
after %u frames: hr = 0x%08x\n", nPasses, *pnFrames, hr);
            pAudioClient->Stop();
            CancelWaitableTimer(hWakeUp);
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            CloseHandle(hWakeUp);
            pAudioClient->Release();            
            return hr;
        }

        if (0 == nNextPacketSize) {
            // no data yet
            continue;
        }

        // get the captured data
       
        UINT32 nNumFramesToRead;
        DWORD dwFlags;

        hr = pAudioCaptureClient->GetBuffer(
            &pData,
            &nNumFramesToRead,
            &dwFlags,
            NULL,
            NULL
        );
        if (FAILED(hr)) {
            printf("IAudioCaptureClient::GetBuffer failed on pass %u after
%u frames: hr = 0x%08x\n", nPasses, *pnFrames, hr);
            pAudioClient->Stop();
            CancelWaitableTimer(hWakeUp);
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            CloseHandle(hWakeUp);
            pAudioClient->Release();            
            return hr;            
        }

       /* if ((AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY & dwFlags) != 0) {
            printf("Audio capture glitch\n");
        }*/

        if (0 == nNumFramesToRead) {
            printf("IAudioCaptureClient::GetBuffer said to read 0 frames on
pass %u after %u frames\n", nPasses, *pnFrames);
            pAudioClient->Stop();
            CancelWaitableTimer(hWakeUp);
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            CloseHandle(hWakeUp);
            pAudioClient->Release();            
            return E_UNEXPECTED;            
        }

        if ((AUDCLNT_BUFFERFLAGS_SILENT & dwFlags) == 0) {
            // ignore if buffer is supposed to be silence.
			
            LONG lBytesToWrite = nNumFramesToRead * nBlockAlign;

            DWORD dwWaitResult =
WaitForSingleObject(prefs->m_AudioBufferMutex, INFINITE);

            switch (dwWaitResult)
            {
            case WAIT_OBJECT_0:
                while (lBytesToWrite > 0) {
                    int copy_len = 0;
                    size_t space_left = prefs->m_AudioBufferSize -
prefs->m_AudioBufferLastWrite;
                    copy_len = lBytesToWrite > space_left ? space_left :
lBytesToWrite;
                   
memcpy(prefs->m_AudioBuffer+prefs->m_AudioBufferLastWrite, pData, copy_len);
                    prefs->m_AudioBufferLastWrite += copy_len;


                    if (prefs->m_AudioBufferLastWrite >=
prefs->m_AudioBufferSize) 
					{
                        prefs->m_AudioBufferLastWrite = 0;
                    }

                    prefs->m_AudioBufferLength += copy_len;


                    if (prefs->m_AudioBufferLength >
prefs->m_AudioBufferSize) {
                        // overrun
                        printf("audio buffer overrun\n");
                        prefs->m_AudioBufferLength = copy_len;
                        prefs->m_AudioBufferLastRead =
prefs->m_AudioBufferLastWrite;
                    } 
				
					else {
                        printf("buffer length: %d\n",
prefs->m_AudioBufferLength);
						
                    }
                    lBytesToWrite -= copy_len;
					
				
                }
                if (! ReleaseMutex(prefs->m_AudioBufferMutex))
                {
                    // TODO: Handle error.
                }
                break;

            case WAIT_ABANDONED:
               return FALSE;
            }

        } 
		
		else
		{
            printf("SILENCE\n");
        }

        *pnFrames += nNumFramesToRead;
       
		samples =(uint16_t*) prefs->m_AudioBuffer;



		ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
(const uint8_t*)samples, buffer_size, 0);
if (ret < 0) {
fprintf(stderr, "Could not setup audio frame\n");
exit(1);
}

		av_init_packet(&pkt);
		pkt.data = NULL; // packet data will be allocated by the encoder
		pkt.size = 0;

		//* encode the samples */
		avcodec_encode_audio2(c, &pkt, frame, &got_output);

		
		//fwrite(pkt.data, 1, pkt.size, f);
		//streaming part of the data pkt
		
		avctx = avformat_alloc_context();

		struct AVOutputFormat* fmt = av_guess_format("rtp", NULL, NULL);
		avctx->oformat = fmt;


	AVStream*fakeaudio= 0;
	fakeaudio = av_new_stream(avctx, 0);
	avcodec_get_context_defaults3(fakeaudio->codec, NULL);
	fakeaudio->codec->codec_id = AV_CODEC_ID_MP3;
	avctx->audio_codec_id = AV_CODEC_ID_MP3;

	//fakeVideo->codec->codec_id = AV_CODEC_ID_MPEG2TS;
	//	rtpCtx->audio_codec_id = AV_CODEC_ID_NONE;

	sprintf(avctx->filename,  "rtp://%s:%d", RTP_ADDRESS, RTP_PORT);
	if (avio_open(&avctx->pb, "rtp://192.168.100.48:5798",  AVIO_FLAG_WRITE) <
0)    //"rtp://192.168.100.48:5467"
    {
        perror("url_fopen failed");
        return 1;
    }
    struct AVStream* stream = av_new_stream(avctx, 1);

	AVCodecContext* c1 = stream->codec;
    c1->codec_id = AV_CODEC_ID_MP3;
    c1->codec_type = AVMEDIA_TYPE_AUDIO;
    c1->flags = CODEC_FLAG_GLOBAL_HEADER;
	c1->sample_rate = 44100;

    //c->time_base.num = 1;
   // c->gop_size = 10;
    c1->bit_rate = BITRATE;
 avformat_write_header(avctx, NULL);
 AVPacket pkt1;

 av_init_packet(&pkt1);
 pkt1.data = pkt.data;
 pkt1.size = pkt.size;
 pkt1.stream_index = fakeaudio->index;
 pkt1.flags = AV_PKT_FLAG_KEY;
 pkt1.pts = AV_NOPTS_VALUE;
 pkt1.dts  = AV_NOPTS_VALUE;


 //fwrite(pkt1.data, 1, pkt1.size, file);
 if(pkt1.data >0)
 {
 printf("data ok \n");
 
 }


//av_interleaved_write_frame(avctx, &pkt1);
 if(av_interleaved_write_frame(avctx, &pkt1) == 0)
 {
 printf("Sending continous data \n");
 }


		// Begin by setting up our usage environment:
   // only to prevent compiler warning

		hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);

		

        if (FAILED(hr)) {
            printf("IAudioCaptureClient::ReleaseBuffer failed on pass %u
after %u frames: hr = 0x%08x\n", nPasses, *pnFrames, hr);
            pAudioClient->Stop();
            CancelWaitableTimer(hWakeUp);
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            CloseHandle(hWakeUp);
            pAudioClient->Release();            
            return hr;            
        }
        
        bFirstPacket = false;
		
    } // capture loop


When I'm trying to write the .pcm file from the buffer I'm getting a file
that I can play in audacity. After encoding if I'm trying to write the
encoded data in a file then there is data in the file but creepy sound.
and for the RTP part there is nothing I'm receiving on the VLC.

pkt1.data is not empty but av_interleaved_write_frame is writing nothing.
This is my humble request to please have a look on the code and tell me
where I'm wrong.





--
View this message in context: http://libav-users.943685.n4.nabble.com/Loopback-audio-encode-and-transmission-on-RTP-tp4658912.html
Sent from the libav-users mailing list archive at Nabble.com.


More information about the Libav-user mailing list