./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, ¤t_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, ¤t_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, ¶m) != 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;
}
最新发布