ShuaiShao93 / Audio-Capture-Transmission-Player

A remote Audio Capture-Transmission-Play program including Server, Client, and Transmission
Apache License 2.0
5 stars 1 forks source link

Usage about the project #1

Closed ghost closed 6 years ago

ghost commented 6 years ago

Hi,

How is the usage about this project? I built all the subprojects, but I don't know how to hook the audio of process.

ShuaiShao93 commented 6 years ago

Sorry there is an instruction in Chinese, I'll update with an English one.

  1. Locate Line 21 in InjectDLL/InjectDLL.cpp, change the if-sentence with the process names you want to inject. You can see currently it's working on "QQmusic.exe" and "splayer.exe".

  2. Locate Line 19 in TestLibPlayer/TestLibPlayer.h, change SERVER_ADD to the actual address of server. If you want to test locally, just leave it be.

  3. Build every subprojects except 'InjectDLL'.

  4. Locate Line 25 in InjectDLL/InjectDLL.cpp, change the path to AudioHook2.dll file, which you built in project 'AudioHook'.

  5. Build 'InjectDLL'.

  6. On server, run the processes that you want to capture audio.

  7. On server, run InjectDll.exe in 'InjectDLL' to inject the dll into the processes and start capturing audio.

  8. On server, run AudioSender.exe in 'TestCaptureAudio' to read audio from buffer and mix.

  9. On client, run AudioReceier.exe in 'TestLibPlayer' to play audio.

ghost commented 6 years ago

First of all it a great project. Really thanks by detailed reply =) I did that. Let me share with you some issues after share my results:

I - In '\TestCaptureAudio' the .exe is named TestCaptureAudio.exe instead of AudioSender.exe II - In '\TestLibPlayer' the .exe is named TestLibPlayer.exe instead of AudioReceiver.exe.

So, I tried to capture the chrome.exe audio by the first, but the browser is multiprocess and while I was playing an audio with some opened tabs it opened more than 12 chrome.exe processes. But ok. chrome

1- I built InjectDLL using Detours Version 3.0 Build_343 and I ran it. The Detours's includes and libs I got it was using set_PROCESSOR=x86. All your subprojects was compiled to x86 Release. Remembering that my system is x64 and the chrome installed is x64 too: injectdll

2 - I ran TestCaptureAudio.exe: testcaptureaudio

3 - And I ran TesLibPlayer.exe, but I could not hear any song to be played. testlibplayer

What's your thoughts about it? Maybe this issues is caused by multiprocessing and/or by the x86 builds trying to hook a x64 process.

ShuaiShao93 commented 6 years ago

According to the output, the hook should have succeeded and the audio could be read from the buffer. But I wonder why TestLibPlayer.exe exits at once without any output. If the init_socket failed, then some errors should be printed. Otherwise, there should be an infinite loop. Could you maybe look into the TestLibPlayer code and debug?

ghost commented 6 years ago

Hi, sorry by later. I was really busy these weeks.

So debugging I found out that numGet =recv ( ) Line 56 is not going to loop. It looks like is stuck on there. The only case that happen is when I close the TestCaptureAudio.exe process, but numGet receive -1 and obviously it doesn't enter on while loop:

numget1

numget2

ShuaiShao93 commented 6 years ago

This is really weird, because the connection seems be established successfully, but the data sending went wrong. Could you uncomment the log on server here, make sure the server has been running when you run client, and see if the server has some logs about sending data? _20171112150538

ghost commented 6 years ago

I uncommented the log and I found out that iResult sends = 113 only in the first loop iteration and in the other iteration iResult is 0:

send

Any suggestion?

ShuaiShao93 commented 6 years ago

Seems that the first round of data is here outside the loop, for feeding the decoder initialization. image Could you here at line 31 print the numGet and see if it matches the size sent by server?

And at line 57 print numGet as well.

Then run the program and see what happens.

ghost commented 6 years ago

In the first round in the server, it sends iResult= 113:

numget_server

In first round, outside of loop, the client receives numGet = 113

numget_client

In the second round, the server sends iResult = 0

numget_server2

And in the second round, the client keep waiting for the client :(

numget_client2

ShuaiShao93 commented 6 years ago

I'm so sorry that I have no idea why this happens... This is a very old program that was run on Windows XP. The only thing I think you might try is to install some software specifically for playing music or video instead of Chrome. The chrome seems more complicated with more than one process. A simpler media player might work.

ghost commented 6 years ago

No problem. My real intention is integrate the hook process to my project to use only hook/inject and server projects. The process that I'm hooking is Windows Media Player. The hook/inject works very well, but the server-client process doesn't.

In the server, I tried to write on disk the encoded sound, so: int main() { FILE * outfile = fopen("output.wav", "wb"); const int BUFSIZE = 512; short int buff16[BUFSIZE]; ...

if(bytesEncode > 0){ fwrite(buff16, 1, bytesEncode, outfile); }

.... I could write the bytes encoded on disk, but unfortunately I couldn't play the file.

Do you have any ideas to do that?

ShuaiShao93 commented 6 years ago

I did the same thing for testing at that time.

The reason why it can't be played is because you'll need a file header to let player know some information about the whole audio file. I don't remember the details of the header. But I believe you could easily find it online and add it by some tool or manually.

ghost commented 6 years ago

I tried to compile all the subproject to x64 build with Detours x64 together. So, one question: libfaac libraries are x86 only?

ghost commented 6 years ago

Hi,

I coded a file header and I successfully wrote a .aac on disk. I tried out a lot to success make a right file header. I got rid of send_offset on TestCaptureAudio project doing this:

if((bytesEncode = faacEncEncode(hEncoder, (int32_t *)encoder_buffer, samplesRead, buffer, maxBytesOutput)) < 0)

Whenever the send_offset variable is used the .aac file goes wrong.

So, unfortunately I can't listen nothing to .aac file. Do you have any suggest about that? My idea is: analyse the .aac file to find out any frequency to apply some filters.

ShuaiShao93 commented 6 years ago

I believe the send_offset is necessary, because the encoder can only encode 8192 Bytes every time, so if in one loop we have more than 8192B audio, we'll need to encode them in more than one round.

Did you try saving the original audio into WAV file? I think you should try WAV at first to exclude the issues caused by encoder, though WAV has different file header...

ghost commented 6 years ago

Injecting Windows Media Player playing back Robbie Williams - Angels (One Love Manchester).mp3 I tried saving the original audio into WAV file. I wrote the following header:

struct wavfile_header {
    char    riff_tag[4];
    int riff_length;
    char    wave_tag[4];
    char    fmt_tag[4];
    int fmt_length;
    short   audio_format;
    short   num_channels;
    int sample_rate;
    int byte_rate;
    short   block_align;
    short   bits_per_sample;
    char    data_tag[4];
    int data_length;
};

and I assigned some values:

FILE * out = fopen("out.wav","wb");
    struct wavfile_header header;

    int samples_per_second = 48000;
    int bits_per_sample = 16;

    strncpy(header.riff_tag, "RIFF", 4);
    strncpy(header.wave_tag, "WAVE", 4);
    strncpy(header.fmt_tag, "fmt ", 4);
    strncpy(header.data_tag, "data", 4);

    header.riff_length = 0;
    header.fmt_length = 16;
    header.audio_format = 1;
    header.num_channels = 1;
    header.sample_rate = samples_per_second;
    header.byte_rate = samples_per_second*(bits_per_sample / 8);
    header.block_align = bits_per_sample / 8;
    header.bits_per_sample = bits_per_sample;
    header.data_length = 0;

    fwrite(&header, sizeof(header), 1, out);

    fflush(out);

as the result:

file_header

But, I couldn't really find out the right buffer variable to write. I tried writing the following: fwrite(read_buffer, sizeof(BYTE), 1, out); and fwrite(get_buffer, sizeof(BYTE), 1, out);

So, while debugging a little bit more, I realized that the get_buffer and read_buffer come empty:

get_buffer

read_buffer

They still empty for a long time of loop. Is it normal? Any tips?

ShuaiShao93 commented 6 years ago

I think you could replace this whole loop image

with

do { numGet = getAudio(get_buffer); fwrite(get_buffer, sizeoof(BYTE), numGet, out); } while(numGet > 0);

ghost commented 6 years ago

That worked. But, it only write 76kb due to in the AudioHook solution there is: #define MAXLENGTH 76800 As it is the maximum buffer length of the process audio, so and about an audio file with a bigger size? I tried use others players and the same issue occur.

ShuaiShao93 commented 6 years ago

Oh sorry, I think you should add Sleep(80); in the loop, to make sure we could fetch reasonable amount of audio. Otherwise we may get 0 bytes of audio and the loop terminates. do { numGet = getAudio(get_buffer); fwrite(get_buffer, sizeoof(BYTE), numGet, out); Sleep(80); } while(numGet > 0);

ghost commented 6 years ago

I added the Sleep (80) function and I waited up by several minutes ( even over after the player finish playing back the audio) and nothing.

So, I realized the problem is not here, but in getAudio() on AudioHook2 project.

Do you have an .exe compiled/built working of this project which could you share with me?

ShuaiShao93 commented 6 years ago

I tried to build the project, but some library file failed to be compiled on my Visual Studio 2017. Seems that I have to build it on VS 2013. Maybe I could try to update with the new version of libraries if you still cannot make it.

ghost commented 6 years ago

In AudioHook project, I added a Post-Build Event to link the library DLL dynamically which export the dlls to inside of TestCaptureAudio/Release after the build. Everything was ok, but unfortunately, it didn't work. I mean, all the dlls is put inside that, but the old bug stand:

(InjectDLL[ok] -> TestCaptureAudio[ok 1º loop, after get 0] -> TestLibPlayer[mute]).

Let me know if you got successful using VS 2013.

ShuaiShao93 commented 6 years ago

I don't think DLL is used by TestCaptureAudio, it's only used by InjectDLL. What TestCaptureAudio needs is .lib file, which is also generated by AudioHook. You can put dll wherever you want, but lib must be in the dependency path of TestCaptureAudio.

ghost commented 6 years ago

Thanks. It finally worked.

Update: If you want to close the issue. It's ok.