管理音频缓冲|线程切换Sleep

本文介绍了一种音频缓冲管理方法,通过设立三个缓冲区并利用生产者和消费者模型来确保音频数据的有序处理。此外,还介绍了如何通过线程间的Sleep机制实现线程的合理调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、管理音频缓冲

1.建立三个缓冲区

2.两个线程:一个线程向缓冲区PUSH数据,另一个线程从缓冲区读数据

3.通过block_status变量来保证缓冲队列读写互斥

block_status;/*0--avail,1--pcm ready,2--playing*/

4.生产者和消费者模型:生产者每次生产的数目不能超过缓冲区的数量,消费者每次消费的数目不能超过缓冲区的数量。

if(g_wave_out.in>=MAX_AUDIO_BLOCK)
            g_wave_out.in =0;

if(out>=MAX_AUDIO_BLOCK)
           out=0;

5.为了防止一开始时消费线程速度快于生产线程,先有生产线程将缓冲队列填满后,消费线程才从队列中读数据。

二、线程切换Sleep

生产线程和消费线程都有while循环,通过在while循环里面进行sleep,使两个线程能交替运行。(线程通过休眠来转让CPU的占有权)。

sleep的时间就是生产者(消费者)“生产”(“消费”)一次所用的时间。例如,生产线程是一个解码线程,解码一帧数据所花费的时间是20ms,那么就可以在生产线程sleep20ms.


三、音频数据的有序性

通过变量in和变量out控制写入和读出的有序性。





./audio_stream 禁用重采样 使用URL: https://ting8.yymp3.com/new27/liyugang6/6.mp3 正在下载音频文件... 等待音频数据... 等待缓冲: 2.0秒 (当前: 0.0秒) 缓冲中: 0.0秒/2.0秒 (0.0%) 文件大小: 3.05 MB 缓冲中: 1.1秒/2.0秒 (52.8%) 缓冲完成: 2.3秒/2.0秒 检测到新音频格式: 44100 Hz, 2 声道 播放格式: 44100 Hz, 2 声道 (原始: 44100 Hz) [重采样禁用] 缓冲: 186.6s | 速度: 1.020 | 队列: 2915.2kb 下载完成, 总大小: 3.05 MB 缓冲: 0.7s | 速度: 1.015 | 队列: 10.8kbbbbb 缓冲不足 (0.7秒 < 1.0秒), 重新缓冲... 等待缓冲: 2.0秒 (当前: 0.7秒) 下载完成,剩余数据: 0.7秒 缓冲恢复,继续播放 缓冲不足 (0.7秒 < 1.0秒), 重新缓冲... 等待缓冲: 2.0秒 (当前: 0.7秒) 下载完成,剩余数据: 0.7秒 缓冲恢复,继续播放 缓冲: 0.0s | 速度: 1.008 | 队列: 0.0kb 缓冲不足 (0.0秒 < 1.0秒), 重新缓冲... 等待缓冲: 2.0秒 (当前: 0.0秒) 下载完成,剩余数据: 0.0秒 缓冲恢复,继续播放 播放线程退出 播放结束 MP3文件而不是流媒体,已经播放完毕就不需要再去缓冲了,直接停止播放就行了,只有播放持续不断的流媒体才会尝试去缓冲,再优化一下 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <curl/curl.h> #include <mpg123.h> #include <pulse/simple.h> #include <pulse/error.h> #include <unistd.h> #include <samplerate.h> #include <time.h> #include <math.h> #include <malloc.h> #include <errno.h> #define BUFFER_SIZE 8192 #define USE_RESAMPLING 0 #define INITIAL_BUFFER_SECONDS 2.0 #define MIN_BUFFER_SECONDS 1.0 #define TARGET_BUFFER_SECONDS 2.0 #define BYTES_PER_SECOND (128 * 1000 / 8) // 共享数据结构 typedef struct { mpg123_handle *mh; pa_simple *pa_stream; pthread_mutex_t mutex; int stop; int format_initialized; int channels; long rate; int buffering; size_t buffer_bytes; double buffer_level; double playback_speed; #if USE_RESAMPLING SRC_STATE *resampler; float *resample_in_buf; float *resample_out_buf; size_t resample_in_size; size_t resample_out_size; long target_rate; #endif } PlayerState; // 自定义结构体用于存储音频数据块 struct data_chunk { unsigned char *data; size_t size; struct data_chunk *next; }; // 线程安全队列 struct data_queue { struct data_chunk *head; struct data_chunk *tail; pthread_mutex_t mutex; pthread_cond_t cond; pthread_cond_t buffer_cond; size_t total_size; size_t target_size; int finished; }; // 下载状态结构 struct DownloadStatus { size_t total_size; // 文件总大小 size_t downloaded_size; // 已下载大小 double last_update; // 最后更新时间 int display_active; // 是否显示进度 }; // 初始化队列 void queue_init(struct data_queue *q) { q->head = q->tail = NULL; pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cond, NULL); pthread_cond_init(&q->buffer_cond, NULL); q->total_size = 0; q->target_size = 0; q->finished = 0; } // 添加数据到队列 void queue_push(struct data_queue *q, unsigned char *data, size_t size) { struct data_chunk *chunk = malloc(sizeof(struct data_chunk)); if (!chunk) return; chunk->data = malloc(size); if (!chunk->data) { free(chunk); return; } memcpy(chunk->data, data, size); chunk->size = size; chunk->next = NULL; pthread_mutex_lock(&q->mutex); if (q->tail) { q->tail->next = chunk; } else { q->head = chunk; } q->tail = chunk; q->total_size += size; if (q->target_size > 0 && q->total_size >= q->target_size) { pthread_cond_signal(&q->buffer_cond); } pthread_cond_signal(&q->cond); pthread_mutex_unlock(&q->mutex); } // 标记下载完成 void queue_finish(struct data_queue *q) { pthread_mutex_lock(&q->mutex); q->finished = 1; pthread_cond_signal(&q->cond); pthread_cond_signal(&q->buffer_cond); pthread_mutex_unlock(&q->mutex); } // 从队列获取数据 struct data_chunk *queue_pop(struct data_queue *q) { pthread_mutex_lock(&q->mutex); // 等待直到有数据或下载完成 while (!q->head && !q->finished) { pthread_cond_wait(&q->cond, &q->mutex); } // 如果队列为空且下载完成,返回NULL if (!q->head) { pthread_mutex_unlock(&q->mutex); return NULL; } struct data_chunk *chunk = q->head; q->head = chunk->next; if (!q->head) q->tail = NULL; q->total_size -= chunk->size; pthread_mutex_unlock(&q->mutex); return chunk; } // 清理队列 void queue_cleanup(struct data_queue *q) { pthread_mutex_lock(&q->mutex); struct data_chunk *chunk = q->head; while (chunk) { struct data_chunk *next = chunk->next; free(chunk->data); free(chunk); chunk = next; } q->head = q->tail = NULL; q->total_size = 0; pthread_mutex_unlock(&q->mutex); } // 设置缓冲目标并等待 void set_buffer_target(struct data_queue *q, struct DownloadStatus *status, size_t target_size) { pthread_mutex_lock(&q->mutex); q->target_size = target_size; // 暂停下载进度显示 if (status) status->display_active = 0; if (q->total_size >= target_size) { pthread_mutex_unlock(&q->mutex); if (status) status->display_active = 1; return; } printf("\n等待缓冲: %.1f秒 (当前: %.1f秒)\n", (double)target_size / BYTES_PER_SECOND, (double)q->total_size / BYTES_PER_SECOND); while (q->total_size < target_size && !q->finished) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 1; printf("缓冲中: %.1f秒/%.1f秒 (%.1f%%)\r", (double)q->total_size / BYTES_PER_SECOND, (double)target_size / BYTES_PER_SECOND, (double)q->total_size / target_size * 100); fflush(stdout); pthread_cond_timedwait(&q->buffer_cond, &q->mutex, &ts); } if (q->finished) { printf("\n下载完成,剩余数据: %.1f秒\n", (double)q->total_size / BYTES_PER_SECOND); } else { printf("\n缓冲完成: %.1f秒/%.1f秒\n", (double)q->total_size / BYTES_PER_SECOND, (double)target_size / BYTES_PER_SECOND); } // 恢复下载进度显示 if (status) status->display_active = 1; pthread_mutex_unlock(&q->mutex); } // libcurl回调函数 static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct data_queue *q = (struct data_queue *)userp; queue_push(q, (unsigned char *)contents, realsize); return realsize; } // 添加抖动处理函数 void apply_dither(short *output, float *input, size_t samples) { const float scale = 32767.0f; for (size_t i = 0; i < samples; i++) { float sample = input[i]; // 简单的抖动处理 float dither_val = (rand() / (float)RAND_MAX) * 0.0001f; sample += dither_val; // 软裁剪 if (sample > 1.0f) sample = 1.0f; if (sample < -1.0f) sample = -1.0f; output[i] = (short)(sample * scale); } } // 简单的低通滤波器 void apply_lowpass(float *buffer, size_t samples, int channels) { static float prev[8] = {0}; const float alpha = 0.15f; for (size_t i = 0; i < samples; i++) { int ch = i % channels; float current = buffer[i]; buffer[i] = alpha * current + (1 - alpha) * prev[ch]; prev[ch] = buffer[i]; } } // 初始化PulseAudio设备 int init_pulse_audio(PlayerState *state, long rate, int channels) { if (state->format_initialized && state->pa_stream) { if (state->rate == rate && state->channels == channels) { return 1; } pa_simple_free(state->pa_stream); state->pa_stream = NULL; } pa_sample_spec ss; #if USE_RESAMPLING ss.rate = state->target_rate; #else ss.rate = rate; #endif ss.format = PA_SAMPLE_S16LE; ss.channels = channels; pa_buffer_attr buffer_attr = { .maxlength = (uint32_t)-1, .tlength = (uint32_t)-1, .prebuf = (uint32_t)-1, .minreq = (uint32_t)4096, .fragsize = (uint32_t)1024 }; int error; state->pa_stream = pa_simple_new( NULL, "AudioStream", PA_STREAM_PLAYBACK, NULL, "Music", &ss, NULL, &buffer_attr, &error); if (!state->pa_stream) { fprintf(stderr, "无法创建PulseAudio连接: %s\n", pa_strerror(error)); return 0; } state->rate = rate; state->channels = channels; state->format_initialized = 1; state->playback_speed = 1.0; printf("播放格式: %d Hz, %d 声道 (原始: %ld Hz) %s\n", ss.rate, channels, rate, #if USE_RESAMPLING "[重采样启用]" #else "[重采样禁用]" #endif ); #if USE_RESAMPLING if (state->resampler) { src_delete(state->resampler); state->resampler = NULL; } int src_error; state->resampler = src_new(SRC_SINC_FASTEST, channels, &src_error); if (!state->resampler) { fprintf(stderr, "无法创建重采样器: %s\n", src_strerror(src_error)); return 0; } double src_ratio = (double)state->target_rate / rate; src_set_ratio(state->resampler, src_ratio); size_t needed_in_size = BUFFER_SIZE * sizeof(float) * channels; if (needed_in_size > state->resample_in_size) { free(state->resample_in_buf); state->resample_in_buf = malloc(needed_in_size); if (!state->resample_in_buf) { fprintf(stderr, "无法分配重采样输入缓冲区\n"); return 0; } state->resample_in_size = needed_in_size; } size_t needed_out_size = needed_in_size * 2; if (needed_out_size > state->resample_out_size) { free(state->resample_out_buf); state->resample_out_buf = malloc(needed_out_size); if (!state->resample_out_buf) { fprintf(stderr, "无法分配重采样输出缓冲区\n"); return 0; } state->resample_out_size = needed_out_size; } #endif return 1; } // 调整播放速度 void adjust_playback_speed(PlayerState *state, double buffer_level) { // 动态调整播放速度 double target_speed = 1.0; if (buffer_level < MIN_BUFFER_SECONDS) { target_speed = 0.98; } else if (buffer_level > TARGET_BUFFER_SECONDS * 1.5) { target_speed = 1.02; } else { target_speed = 1.0; } // 平滑过渡 state->playback_speed = 0.9 * state->playback_speed + 0.1 * target_speed; if (state->playback_speed < 0.9) state->playback_speed = 0.9; if (state->playback_speed > 1.1) state->playback_speed = 1.1; } // 播放线程函数 void *play_thread(void *arg) { PlayerState *state = (PlayerState *)arg; struct data_queue *q = (struct data_queue *)((char *)arg + sizeof(PlayerState)); float *buffer; size_t buffer_size = BUFFER_SIZE * sizeof(float); size_t done; int status; int error; if (posix_memalign((void**)&buffer, 16, buffer_size)) { fprintf(stderr, "内存对齐分配失败\n"); return NULL; } printf("等待音频数据...\n"); state->buffering = 1; state->buffer_level = 0.0; state->playback_speed = 1.0; size_t initial_buffer_target = BYTES_PER_SECOND * INITIAL_BUFFER_SECONDS; set_buffer_target(q, NULL, initial_buffer_target); state->buffering = 0; struct timespec last_frame, current_frame; clock_gettime(CLOCK_MONOTONIC, &last_frame); srand(time(NULL)); int download_completed = 0; // 跟踪下载状态 while (1) { pthread_mutex_lock(&state->mutex); if (state->stop) { pthread_mutex_unlock(&state->mutex); break; } pthread_mutex_unlock(&state->mutex); state->buffer_level = (double)q->total_size / BYTES_PER_SECOND; adjust_playback_speed(state, state->buffer_level); // 只有在下载未完成时才检查缓冲不足 if (!download_completed && state->buffer_level < MIN_BUFFER_SECONDS && !state->buffering) { state->buffering = 1; printf("\n缓冲不足 (%.1f秒 < %.1f秒), 重新缓冲...\n", state->buffer_level, MIN_BUFFER_SECONDS); size_t buffer_target = BYTES_PER_SECOND * TARGET_BUFFER_SECONDS; set_buffer_target(q, NULL, buffer_target); state->buffering = 0; printf("缓冲恢复,继续播放\n"); } struct data_chunk *chunk = queue_pop(q); // 检测下载完成 if (chunk == NULL) { download_completed = 1; // 标记下载已完成 // 播放解码器中剩余的数据 int more_data = 1; while (more_data) { status = mpg123_read(state->mh, (unsigned char*)buffer, buffer_size, &done); if (status == MPG123_NEED_MORE) { // 没有更多数据了 more_data = 0; } else if (status == MPG123_DONE) { printf("播放完成\n"); more_data = 0; } else if (status != MPG123_OK) { if (status != MPG123_NEW_FORMAT) { fprintf(stderr, "解码错误: %s\n", mpg123_strerror(state->mh)); more_data = 0; } } if (done > 0) { size_t frames = done / (sizeof(float) * state->channels); if (state->format_initialized) { apply_lowpass(buffer, frames * state->channels, state->channels); size_t pcm_size = frames * sizeof(short) * state->channels; short *pcm_buffer = malloc(pcm_size); apply_dither(pcm_buffer, buffer, frames * state->channels); if (pa_simple_write(state->pa_stream, pcm_buffer, pcm_size, &error) < 0) { fprintf(stderr, "PulseAudio播放失败: %s\n", pa_strerror(error)); } free(pcm_buffer); // 高精度播放控制 clock_gettime(CLOCK_MONOTONIC, &current_frame); double elapsed = (current_frame.tv_sec - last_frame.tv_sec) + (current_frame.tv_nsec - last_frame.tv_nsec) / 1e9; double expected_time = (double)frames / state->rate / state->playback_speed; if (elapsed < expected_time) { double sleep_seconds = expected_time - elapsed; usleep((useconds_t)(sleep_seconds * 1000000)); } clock_gettime(CLOCK_MONOTONIC, &last_frame); } } } // 确保所有音频数据都已播放 if (state->format_initialized && state->pa_stream) { if (pa_simple_drain(state->pa_stream, &error) < 0) { fprintf(stderr, "PulseAudio drain失败: %s\n", pa_strerror(error)); } } break; } if (mpg123_feed(state->mh, chunk->data, chunk->size) != MPG123_OK) { fprintf(stderr, "喂入数据失败: %s\n", mpg123_strerror(state->mh)); free(chunk->data); free(chunk); mpg123_close(state->mh); if (mpg123_open_feed(state->mh) != MPG123_OK) { fprintf(stderr, "无法重置解码器\n"); break; } continue; } free(chunk->data); free(chunk); while (1) { status = mpg123_read(state->mh, (unsigned char*)buffer, buffer_size, &done); if (status == MPG123_NEW_FORMAT) { long rate; int channels, encoding; if (mpg123_getformat(state->mh, &rate, &channels, &encoding) == MPG123_OK) { printf("检测到新音频格式: %ld Hz, %d 声道\n", rate, channels); if (!init_pulse_audio(state, rate, channels)) { fprintf(stderr, "无法初始化音频设备\n"); break; } } continue; } if (status == MPG123_NEED_MORE) { break; } if (status != MPG123_OK) { if (status != MPG123_DONE) { fprintf(stderr, "解码错误: %s\n", mpg123_strerror(state->mh)); mpg123_close(state->mh); if (mpg123_open_feed(state->mh) != MPG123_OK) { fprintf(stderr, "无法重置解码器\n"); break; } } break; } size_t frames = done / (sizeof(float) * state->channels); if (state->format_initialized && done > 0) { apply_lowpass(buffer, frames * state->channels, state->channels); size_t pcm_size = frames * sizeof(short) * state->channels; short *pcm_buffer = malloc(pcm_size); apply_dither(pcm_buffer, buffer, frames * state->channels); if (pa_simple_write(state->pa_stream, pcm_buffer, pcm_size, &error) < 0) { fprintf(stderr, "PulseAudio播放失败: %s\n", pa_strerror(error)); } free(pcm_buffer); clock_gettime(CLOCK_MONOTONIC, &current_frame); double elapsed = (current_frame.tv_sec - last_frame.tv_sec) + (current_frame.tv_nsec - last_frame.tv_nsec) / 1e9; double expected_time = (double)frames / state->rate / state->playback_speed; if (elapsed < expected_time) { double sleep_seconds = expected_time - elapsed; usleep((useconds_t)(sleep_seconds * 1000000)); } clock_gettime(CLOCK_MONOTONIC, &last_frame); } state->buffer_level = (double)q->total_size / BYTES_PER_SECOND; printf("缓冲: %.1fs | 速度: %.3f | 队列: %.1fkb\r", state->buffer_level, state->playback_speed, (double)q->total_size / 1024); fflush(stdout); } } free(buffer); printf("\n播放线程退出\n"); return NULL; } // 下载参数结构 struct DownloadParam { CURL *curl; struct data_queue *queue; struct DownloadStatus *status; // 下载状态 }; // 下载进度显示函数 void display_progress(struct DownloadStatus *status, size_t dlnow) { if (!status->display_active) return; double current_time = (double)clock() / CLOCKS_PER_SEC; // 限制更新频率,每秒最多更新10次 if (current_time - status->last_update < 0.1) { return; } status->last_update = current_time; if (status->total_size > 0) { double progress = (double)dlnow / status->total_size * 100.0; printf("下载进度: %.2f%% (%.2f MB/%.2f MB)\r", progress, (double)dlnow / (1024 * 1024), (double)status->total_size / (1024 * 1024)); } else { printf("已下载: %.2f MB\r", (double)dlnow / (1024 * 1024)); } fflush(stdout); } // 下载进度回调函数 static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { struct DownloadStatus *status = (struct DownloadStatus *)clientp; // 如果这是第一次获取文件大小 if (dltotal > 0 && status->total_size == 0) { status->total_size = dltotal; printf("\n文件大小: %.2f MB\n", (double)dltotal / (1024 * 1024)); } // 更新已下载大小 status->downloaded_size = dlnow; // 显示进度 display_progress(status, dlnow); return 0; } // 下载线程函数 void *download_thread_wrapper(void *arg) { struct DownloadParam *param = (struct DownloadParam *)arg; CURL *curl = param->curl; struct data_queue *q = param->queue; struct DownloadStatus *status = param->status; // 设置进度回调 curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, status); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); // 初始化下载状态 status->total_size = 0; status->downloaded_size = 0; status->last_update = 0; status->display_active = 1; CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { fprintf(stderr, "\n下载失败: %s\n", curl_easy_strerror(res)); } else { // 确保显示最终进度 status->display_active = 1; display_progress(status, status->downloaded_size); printf("\n下载完成, 总大小: %.2f MB\n", (double)status->downloaded_size / (1024 * 1024)); } // 标记下载完成 queue_finish(q); return NULL; } int main() { CURL *curl; struct { PlayerState state; struct data_queue queue; } shared_data = {0}; pthread_t play_tid, download_tid; queue_init(&shared_data.queue); if (mpg123_init() != MPG123_OK) { fprintf(stderr, "无法初始化mpg123\n"); return 1; } shared_data.state.mh = mpg123_new(NULL, NULL); if (!shared_data.state.mh) { fprintf(stderr, "创建mpg123句柄失败: %s\n", mpg123_plain_strerror(mpg123_errcode(NULL))); mpg123_exit(); return 1; } if (mpg123_format_none(shared_data.state.mh) != MPG123_OK || mpg123_format(shared_data.state.mh, 44100, MPG123_STEREO, MPG123_ENC_FLOAT_32) != MPG123_OK) { fprintf(stderr, "无法设置输出格式\n"); mpg123_delete(shared_data.state.mh); mpg123_exit(); return 1; } #if USE_RESAMPLING printf("启用高质量重采样 (48kHz)\n"); shared_data.state.target_rate = 48000; #else printf("禁用重采样\n"); #endif #ifdef MPG123_QUIET mpg123_param(shared_data.state.mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0); #else mpg123_param(shared_data.state.mh, MPG123_VERBOSE, 0, 0.0); #endif mpg123_param(shared_data.state.mh, MPG123_ADD_FLAGS, MPG123_SKIP_ID3V2, 0); mpg123_param(shared_data.state.mh, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0); mpg123_param(shared_data.state.mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0); if (mpg123_open_feed(shared_data.state.mh) != MPG123_OK) { fprintf(stderr, "无法打开feed模式: %s\n", mpg123_strerror(shared_data.state.mh)); mpg123_delete(shared_data.state.mh); mpg123_exit(); return 1; } shared_data.state.format_initialized = 0; shared_data.state.stop = 0; shared_data.state.buffering = 1; shared_data.state.buffer_bytes = 0; shared_data.state.buffer_level = 0.0; shared_data.state.playback_speed = 1.0; #if USE_RESAMPLING shared_data.state.resampler = NULL; shared_data.state.resample_in_buf = NULL; shared_data.state.resample_out_buf = NULL; shared_data.state.resample_in_size = 0; shared_data.state.resample_out_size = 0; #endif if (pthread_mutex_init(&shared_data.state.mutex, NULL)) { fprintf(stderr, "无法初始化互斥锁\n"); mpg123_delete(shared_data.state.mh); mpg123_exit(); return 1; } curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (!curl) { fprintf(stderr, "初始化libcurl失败\n"); return 1; } // 使用普通MP3文件URL const char *url = "https://ting8.yymp3.com/new27/liyugang6/6.mp3"; printf("使用URL: %s\n", url); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &shared_data.queue); curl_easy_setopt(curl, CURLOPT_USERAGENT, "Lavf/60.3.100"); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Accept: */*"); headers = curl_slist_append(headers, "Range: bytes=0-"); headers = curl_slist_append(headers, "Connection: keep-alive"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0L); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 65536L); curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // 创建下载状态结构 struct DownloadStatus download_status = {0}; printf("正在下载音频文件...\n"); // 创建下载线程参数 struct DownloadParam param = { .curl = curl, .queue = &shared_data.queue, .status = &download_status }; // 创建下载线程 if (pthread_create(&download_tid, NULL, download_thread_wrapper, &param) != 0) { fprintf(stderr, "无法创建下载线程\n"); curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // 创建播放线程 if (pthread_create(&play_tid, NULL, play_thread, &shared_data) != 0) { fprintf(stderr, "无法创建播放线程\n"); mpg123_delete(shared_data.state.mh); mpg123_exit(); return 1; } // 等待下载线程完成 pthread_join(download_tid, NULL); // 等待播放线程结束 pthread_join(play_tid, NULL); // 清理资源 curl_slist_free_all(headers); curl_easy_cleanup(curl); curl_global_cleanup(); queue_cleanup(&shared_data.queue); if (shared_data.state.format_initialized && shared_data.state.pa_stream) { pa_simple_free(shared_data.state.pa_stream); } #if USE_RESAMPLING if (shared_data.state.resampler) { src_delete(shared_data.state.resampler); } free(shared_data.state.resample_in_buf); free(shared_data.state.resample_out_buf); #endif if (shared_data.state.mh) { mpg123_close(shared_data.state.mh); mpg123_delete(shared_data.state.mh); } mpg123_exit(); printf("播放结束\n"); return 0; }
最新发布
07-04
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值