[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