210 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			210 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | #include <iostream>
 | ||
|  | #include "../music/providers/shared/pstream.h"
 | ||
|  | #include <alsa/asoundlib.h>
 | ||
|  | #include <fstream>
 | ||
|  | #include <chrono>
 | ||
|  | #include <MusicPlayer.h>
 | ||
|  | 
 | ||
|  | extern "C" { | ||
|  |     #include <libavformat/avformat.h>
 | ||
|  |     #include <libavcodec/avcodec.h>
 | ||
|  |     #include <libavutil/avutil.h>
 | ||
|  | } | ||
|  | #include <log/LogUtils.h>
 | ||
|  | #include <CXXTerminal/Terminal.h>
 | ||
|  | 
 | ||
|  | #define PCM_DEVICE "default"
 | ||
|  | using namespace std; | ||
|  | using namespace std::chrono; | ||
|  | using namespace music; | ||
|  | 
 | ||
|  | void die(const char* message) | ||
|  | { | ||
|  |     fprintf(stderr, "%s\n", message); | ||
|  |     exit(1); | ||
|  | } | ||
|  | 
 | ||
|  | int main(int, char**){ | ||
|  |     logger::config::logLevel = spdlog::level::trace; | ||
|  |     logger::config::terminalLevel = spdlog::level::trace; | ||
|  |     //terminal::install();
 | ||
|  | 
 | ||
|  |     logger::setup(); | ||
|  |     logger::updateLogLevels(); | ||
|  | 
 | ||
|  |     //youtube-dl -s --dump-json https://www.youtube.com/watch?v=1ifTLj_glhc
 | ||
|  |     //ffmpeg -hide_banner -nostats -i <url> -ac 2 -ar 48000 -f s16le -acodec pcm_s16le pipe:1
 | ||
|  |     //
 | ||
|  | 
 | ||
|  |     //printf("Length: %d\n", codec_context->frame_size / codec_context->framerate.den / codec_context->channels); //576 | 3
 | ||
|  | /*
 | ||
|  |     // To initalize libao for playback
 | ||
|  |     ao_initialize(); | ||
|  | 
 | ||
|  |     int driver = ao_default_driver_id(); | ||
|  | 
 | ||
|  |     // The format of the decoded PCM samples
 | ||
|  |     ao_sample_format sample_format; | ||
|  |     sample_format.bits = 16; | ||
|  |     sample_format.channels = 2; | ||
|  |     sample_format.rate = 44100; | ||
|  |     sample_format.byte_format = AO_FMT_NATIVE; | ||
|  |     sample_format.matrix = 0; | ||
|  | 
 | ||
|  |     ao_device* device = ao_open_live(driver, &sample_format, NULL); | ||
|  | 
 | ||
|  |     AVPacket packet; | ||
|  |     int buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; | ||
|  |     int8_t buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; | ||
|  | 
 | ||
|  |     while (1) { | ||
|  | 
 | ||
|  |         buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; | ||
|  | 
 | ||
|  |         // Read one packet into `packet`
 | ||
|  |         if (av_read_frame(container, &packet) < 0) { | ||
|  |             break;  // End of lstream. Done decoding.
 | ||
|  |         } | ||
|  | 
 | ||
|  |         // Decodes from `packet` into the buffer
 | ||
|  |         if (avcodec_decode_audio3(codec_context, (int16_t*)buffer, &buffer_size, &packet) < 1) { | ||
|  |             break;  // Error in decoding
 | ||
|  |         } | ||
|  | 
 | ||
|  |         // Send the buffer contents to the audio device
 | ||
|  |         ao_play(device, (char*)buffer, buffer_size); | ||
|  |     } | ||
|  | 
 | ||
|  |     av_close_input_file(container); | ||
|  | 
 | ||
|  |     ao_shutdown(); | ||
|  | 
 | ||
|  |     fprintf(stdout, "Done playing. Exiting..."); | ||
|  |     */ | ||
|  | 
 | ||
|  |     music::manager::loadProviders("providers/"); | ||
|  |     std::string file = "https://www.youtube.com/watch?v=GVC5adzPpiE"; //https://www.youtube.com/watch?v=eBlg2oX0Z0Q
 | ||
|  |     auto provider = music::manager::resolveProvider("YouTube", file); //test.mp3
 | ||
|  |     if(!provider) return 0; | ||
|  |     cout << "Using provider -> " << provider->providerName << endl; | ||
|  |     cout << "Using provider -> " << provider->providerDescription << endl; | ||
|  |     if(true) return 0; | ||
|  |    /*
 | ||
|  |     auto fut = provider->createPlayer(file); | ||
|  |     fut.waitAndGet(nullptr); | ||
|  |     if(fut.failed()){ | ||
|  |         log::log(log::err, "Could not create: " + fut.errorMegssage()); | ||
|  |     } else log::log(log::info, "Got!"); | ||
|  |      //VALID
 | ||
|  |     /*
 | ||
|  |     auto player = provider->createPlayer("https://r5---sn-4g5edned.googlevideo.com/videoplayback?lmt=1491636391724572&key=yt6&itag=251&keepalive=yes&signature=8220B0B2D85AFE6A44CAE901A9C5A5D9A2564DA4.59183C41417E91E04552835738ED0AD1592BD05E&source=youtube&clen=4017657&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Ckeepalive%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csource%2Cexpire&gir=yes&expire=1516917262&initcwndbps=856250&ei=rv1pWuvYBI-AV7SlqaAE&dur=234.061&mv=m&mt=1516895537&ms=au&requiressl=yes&ip=93.230.21.99&ipbits=0&mn=sn-4g5edned&mm=31&pl=26&mime=audio%2Fwebm&id=o-ABQnAlwQxtPQJTqHMc9SiTD-bGc1YR2yogmPcVUy1Xxp&ratebypass=yes").waitAndGet(nullptr); | ||
|  |     /*
 | ||
|  |     auto player = provider->createPlayer("https://r5---sn-4g5edned.googlevideo.com/videoplayback?mn=sn-4g5edned&mm=31&gir=yes&clen=4017657&requiressl=yes&mv=m&mt=1516820571&ms=au&ei=tdhoWtv0Fd5bY1wLY5qVA&lmt=1491636391724572&key=yt6&ip=80.133.238.232&expire=1516842261&dur=234.061&beids=%5B9466594%5D&id=o-AKeOawWpz0BT9Qxuqria6qw1_eTa3is7UXit4BLIC8re&initcwndbps=591250&source=youtube&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Ckeepalive%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csource%2Cexpire&ipbits=0&signature=230305B8592A57E939FDBF2D4C19C16DC2FE0D68.AC475B47E4533071F4A6EA96960384398A15D801&pl=26&itag=251&mime=audio%2Fwebm&keepalive=yes&ratebypass=yes").waitAndGet(nullptr); | ||
|  |      */ | ||
|  |     auto player = provider->createPlayer(file).waitAndGet(nullptr); | ||
|  |     if(!player){ | ||
|  |         cerr << "Could not load youtube video" << endl; | ||
|  |         return -1; | ||
|  |     } | ||
|  |     if(!player->initialize()){ | ||
|  |         log::log(log::err, "Could not inizalisze ffmpeg player -> " + player->error()); | ||
|  |         return 1; | ||
|  |     } | ||
|  |     player->registerEventHandler("main", [player](music::MusicEvent event){ //FIXME weak ptr
 | ||
|  |         log::log(log::info, "Got event " + to_string(event)); | ||
|  |         if(event == music::EVENT_ERROR) { | ||
|  |             log::log(log::err, "Recived error: " + player->error()); | ||
|  |             player->clearError(); | ||
|  |         } | ||
|  |     }); | ||
|  |     player->play(); | ||
|  |     player->forward(chrono::minutes(0)); | ||
|  |     cout << "Song length " << duration_cast<seconds>(player->length()).count() << " seconds" << endl; | ||
|  | 
 | ||
|  | 
 | ||
|  |     unsigned int pcm, tmp, dir; | ||
|  |     snd_pcm_t *pcm_handle; | ||
|  |     snd_pcm_hw_params_t *params; | ||
|  |     snd_pcm_uframes_t frames; | ||
|  |     int loops; | ||
|  | 
 | ||
|  |     int channels = 2; | ||
|  |     int rate = 48000; | ||
|  |     int seconds = duration_cast<std::chrono::seconds>(player->length()).count() + 1; | ||
|  |     seconds = 10000; | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) | ||
|  |         printf("ERROR: Can't open \"%s\" PCM device. %s\n", | ||
|  |                PCM_DEVICE, snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     snd_pcm_hw_params_alloca(¶ms); | ||
|  | 
 | ||
|  |     snd_pcm_hw_params_any(pcm_handle, params); | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params, | ||
|  |                                            SND_PCM_ACCESS_RW_INTERLEAVED) < 0) | ||
|  |         printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params, | ||
|  |                                            SND_PCM_FORMAT_S16_LE) < 0) | ||
|  |         printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0) | ||
|  |         printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) | ||
|  |         printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0) | ||
|  |         printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); | ||
|  | 
 | ||
|  |     printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle)); | ||
|  |     printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle))); | ||
|  | 
 | ||
|  |     snd_pcm_hw_params_get_channels(params, &tmp); | ||
|  |     printf("channels: %i ", tmp); | ||
|  | 
 | ||
|  |     if (tmp == 1) | ||
|  |         printf("(mono)\n"); | ||
|  |     else if (tmp == 2) | ||
|  |         printf("(stereo)\n"); | ||
|  | 
 | ||
|  |     snd_pcm_hw_params_get_rate(params, &tmp, 0); | ||
|  |     printf("rate: %d bps\n", tmp); | ||
|  | 
 | ||
|  |     printf("seconds: %d\n", seconds); | ||
|  | 
 | ||
|  |     snd_pcm_hw_params_get_period_size(params, &frames, 0); | ||
|  |     cout << "perd size: " << frames << endl; | ||
|  |     snd_pcm_hw_params_get_period_time(params, &tmp, NULL); | ||
|  |     player->preferredSampleCount(frames); | ||
|  | 
 | ||
|  |     auto last = system_clock::now(); | ||
|  |     for (loops = seconds * 1000000 / tmp; loops > 0; loops--) { | ||
|  |         //cout << " dur: " << duration_cast<microseconds>(system_clock::now() - last).count() << endl;
 | ||
|  | 
 | ||
|  |         auto next = player->popNextSegment(); | ||
|  |         if(!next) { | ||
|  |             log::log(log::info, "END!"); | ||
|  |             continue; | ||
|  |         } | ||
|  |         retry: | ||
|  |         if (pcm = snd_pcm_writei(pcm_handle, next->segments, next->segmentLength) == -EPIPE) { | ||
|  |             printf("XRUN.\n"); | ||
|  |             snd_pcm_prepare(pcm_handle); | ||
|  |             goto retry; | ||
|  |         } else if (pcm < 0) { | ||
|  |             printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); | ||
|  |         } | ||
|  |         //if((system_clock::now() - last) > ::seconds(1)) {
 | ||
|  |             log::log(log::debug, "Time: " + to_string(duration_cast<milliseconds>(system_clock::now() - last).count()) + " | " + to_string(duration_cast<milliseconds>(player->currentIndex()).count())); | ||
|  |             last = system_clock::now(); | ||
|  |         //}
 | ||
|  |         //TODO!
 | ||
|  |     } | ||
|  | 
 | ||
|  |     snd_pcm_drain(pcm_handle); | ||
|  |     snd_pcm_close(pcm_handle); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } |